diff --git a/java/java-psi-api/src/com/intellij/psi/PsiInferenceHelper.java b/java/java-psi-api/src/com/intellij/psi/PsiInferenceHelper.java index a0db97f151fd..eda831309bc2 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiInferenceHelper.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiInferenceHelper.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi; import com.intellij.pom.java.LanguageLevel; @@ -41,13 +27,22 @@ public interface PsiInferenceHelper { @NotNull PsiElement parent, @NotNull ParameterTypeInferencePolicy policy, @NotNull LanguageLevel languageLevel); - @NotNull PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, @NotNull PsiType[] leftTypes, @NotNull PsiType[] rightTypes, @NotNull LanguageLevel languageLevel); + + @NotNull + default PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, + @NotNull PsiType[] leftTypes, + @NotNull PsiType[] rightTypes, + @NotNull PsiSubstitutor partialSubstitutor, + @NotNull LanguageLevel languageLevel){ + return inferTypeArguments(typeParameters, leftTypes, rightTypes, languageLevel); + } + PsiType getSubstitutionForTypeParameter(PsiTypeParameter typeParam, PsiType param, PsiType arg, diff --git a/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java b/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java index 55109a6c4a45..2c88552c4d1b 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiResolveHelper.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi; import com.intellij.openapi.components.ServiceManager; @@ -175,6 +161,15 @@ public interface PsiResolveHelper { @NotNull PsiType[] rightTypes, @NotNull LanguageLevel languageLevel); + @NotNull + default PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, + @NotNull PsiType[] leftTypes, + @NotNull PsiType[] rightTypes, + @NotNull PsiSubstitutor partialSubstitutor, + @NotNull LanguageLevel languageLevel) { + return inferTypeArguments(typeParameters, leftTypes, rightTypes, languageLevel); + } + PsiType getSubstitutionForTypeParameter(PsiTypeParameter typeParam, PsiType param, PsiType arg, diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiOldInferenceHelper.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiOldInferenceHelper.java index 1a77fb531bbd..f547891770fd 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiOldInferenceHelper.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiOldInferenceHelper.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.impl.source.resolve; import com.intellij.openapi.diagnostic.Logger; @@ -305,6 +291,15 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper { return partialSubstitutor; } + @NotNull + @Override + public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, + @NotNull PsiType[] leftTypes, + @NotNull PsiType[] rightTypes, + @NotNull LanguageLevel languageLevel) { + return inferTypeArguments(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, languageLevel); + } + private static boolean compareSubtypes(final PsiType type, final PsiType parentType) { return type != null && parentType != null && TypeConversionUtil.isAssignable(type, parentType); } @@ -314,6 +309,7 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper { public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, @NotNull PsiType[] leftTypes, @NotNull PsiType[] rightTypes, + @NotNull PsiSubstitutor partialSubstitutor, @NotNull LanguageLevel languageLevel) { if (leftTypes.length != rightTypes.length) throw new IllegalArgumentException("Types must be of the same length"); PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index 1df4395e4453..9770084aa4a3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.impl.source.resolve; import com.intellij.openapi.diagnostic.Logger; @@ -212,8 +198,18 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { @NotNull PsiType[] leftTypes, @NotNull PsiType[] rightTypes, @NotNull LanguageLevel languageLevel) { + return inferTypeArguments(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, languageLevel); + } + + @Override + @NotNull + public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, + @NotNull PsiType[] leftTypes, + @NotNull PsiType[] rightTypes, + @NotNull PsiSubstitutor partialSubstitutor, + @NotNull LanguageLevel languageLevel) { return getInferenceHelper(languageLevel) - .inferTypeArguments(typeParameters, leftTypes, rightTypes, languageLevel); + .inferTypeArguments(typeParameters, leftTypes, rightTypes, partialSubstitutor, languageLevel); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java index 92d5c0b01d07..49d02e505b06 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/PsiGraphInferenceHelper.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.pom.java.LanguageLevel; @@ -74,8 +60,18 @@ public class PsiGraphInferenceHelper implements PsiInferenceHelper { @NotNull PsiType[] leftTypes, @NotNull PsiType[] rightTypes, @NotNull LanguageLevel languageLevel) { + return inferTypeArguments(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, languageLevel); + } + + @NotNull + @Override + public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters, + @NotNull PsiType[] leftTypes, + @NotNull PsiType[] rightTypes, + @NotNull PsiSubstitutor partialSubstitutor, + @NotNull LanguageLevel languageLevel) { if (typeParameters.length == 0) return PsiSubstitutor.EMPTY; - InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager, null); + InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, partialSubstitutor, myManager, null); for (PsiType leftType : leftTypes) { if (!session.isProperType(session.substituteWithInferenceVariables(leftType))) { return session.infer(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java index a64b7cb2b254..ed382e1cf80f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrClosureType.java @@ -69,7 +69,7 @@ public class GrClosureType extends GrLiteralClassType { } @NotNull - private PsiType[] inferParameters() { + public PsiType[] inferParameters() { final PsiClass psiClass = resolve(); if (psiClass != null && psiClass.getTypeParameters().length == 1) { final PsiType type = GrClosureSignatureUtil.getReturnType(mySignature); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java index 4bbd2a4ff701..d15d06c26734 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; import com.intellij.openapi.util.Key; @@ -172,9 +158,6 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem if (kind == GroovyResolveKind.METHOD || kind == GroovyResolveKind.PROPERTY) { final PsiMethod method = (PsiMethod)namedElement; - final boolean isApplicable = kind == GroovyResolveKind.PROPERTY && !myIsLValue - || isApplicable(myArgumentTypes.getValue(), method, substitutor, myRef, true); - final NotNullComputable substitutorComputer; if (kind == GroovyResolveKind.METHOD) { substitutorComputer = () -> myMethodSubstitutorComputer.getValue().obtainSubstitutor(substitutor, method, resolveContext); @@ -182,6 +165,9 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem else { substitutorComputer = () -> myPropertySubstitutorComputer.getValue().obtainSubstitutor(substitutor, method, resolveContext); } + final boolean isApplicable = kind == GroovyResolveKind.PROPERTY && !myIsLValue + || isApplicable(myArgumentTypes.getValue(), method, substitutorComputer.compute(), myRef, true); + candidate = new GroovyMethodResultImpl( method, resolveContext, spreadState, substitutor, substitutorComputer, diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index 38497c035501..c3c5bd8cb572 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; @@ -104,9 +90,10 @@ public class MethodResolverProcessor extends ResolverProcessor substitutorComputer = () -> mySubstitutorComputer.obtainSubstitutor(partialSubstitutor, method, resolveContext); + PsiSubstitutor substitutor = substitutorComputer.compute(); boolean isAccessible = isAccessible(method); boolean isStaticsOK = isStaticsOK(method, resolveContext, false); - boolean isApplicable = PsiUtil.isApplicable(myArgumentTypes, method, partialSubstitutor, myPlace, true); + boolean isApplicable = PsiUtil.isApplicable(myArgumentTypes, method, substitutor, myPlace, true); boolean isValidResult = isStaticsOK && isAccessible && isApplicable; GroovyMethodResultImpl candidate = new GroovyMethodResultImpl( diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java index 150ee826d0d8..d77c1b201fde 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.processors; import com.intellij.openapi.diagnostic.Logger; @@ -23,7 +9,6 @@ import com.intellij.psi.*; import com.intellij.psi.PsiClassType.ClassResolveResult; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.TypeConversionUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; @@ -42,13 +27,15 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; +import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; -import java.util.Collection; +import java.util.*; import static com.intellij.util.containers.ContainerUtil.emptyList; import static com.intellij.util.containers.ContainerUtil.newHashSet; @@ -64,7 +51,9 @@ public class SubstitutorComputer { protected final PsiElement myPlace; private final PsiType myThisType; - @Nullable private final PsiType[] myArgumentTypes; + @Nullable + private final PsiType[] myArgumentTypes; + @Nullable private final PsiType[] myTypeArguments; private final PsiElement myPlaceToInferContext; private final NotNullLazyValue> myExitPoints; @@ -72,7 +61,7 @@ public class SubstitutorComputer { public SubstitutorComputer(PsiType thisType, @Nullable PsiType[] argumentTypes, - PsiType[] typeArguments, + @Nullable PsiType[] typeArguments, PsiElement place, PsiElement placeToInferContext) { myThisType = thisType; @@ -130,7 +119,7 @@ public class SubstitutorComputer { @NotNull PsiMethod method, @Nullable PsiElement resolveContext) { final PsiTypeParameter[] typeParameters = method.getTypeParameters(); - if (myTypeArguments.length == typeParameters.length) { + if (myTypeArguments != null && myTypeArguments.length == typeParameters.length) { for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; final PsiType typeArgument = myTypeArguments[i]; @@ -174,35 +163,18 @@ public class SubstitutorComputer { final GrClosureSignature signature = GrClosureSignatureUtil.createSignature(method, partialSubstitutor); final GrClosureParameter[] params = signature.getParameters(); - final GrClosureSignatureUtil.ArgInfo[] argInfos = GrClosureSignatureUtil.mapArgTypesToParameters(erasedSignature, argTypes, myPlace, true); - if (argInfos == null) return partialSubstitutor; + final GrClosureSignatureUtil.ArgInfo[] argInfos = + GrClosureSignatureUtil.mapArgTypesToParameters(erasedSignature, argTypes, myPlace, true); - int max = Math.max(params.length, argTypes.length); + if (argInfos == null || params.length > argInfos.length) return partialSubstitutor; - PsiType[] parameterTypes = PsiType.createArray(max); - PsiType[] argumentTypes = PsiType.createArray(max); - int i = 0; - for (int paramIndex = 0; paramIndex < argInfos.length; paramIndex++) { - PsiType paramType = params[paramIndex].getType(); + Deque inferenceQueue = buildInferenceQueue(method, typeParameters, params, argInfos); - GrClosureSignatureUtil.ArgInfo argInfo = argInfos[paramIndex]; - if (argInfo != null) { - if (argInfo.isMultiArg) { - if (paramType instanceof PsiArrayType) paramType = ((PsiArrayType)paramType).getComponentType(); - } - for (PsiType type : argInfo.args) { - argumentTypes[i] = handleConversion(paramType, type); - parameterTypes[i] = paramType; - i++; - } - } - else { - parameterTypes[i] = paramType; - argumentTypes[i] = PsiType.NULL; - i++; - } + PsiSubstitutor substitutor = partialSubstitutor; + while (!inferenceQueue.isEmpty()) { + substitutor = inferenceQueue.pollFirst().doInfer(substitutor); } - PsiSubstitutor substitutor = myHelper.inferTypeArguments(typeParameters, parameterTypes, argumentTypes, LanguageLevel.JDK_1_7); + for (PsiTypeParameter typeParameter : typeParameters) { if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) { substitutor = inferFromContext(typeParameter, PsiUtil.getSmartReturnType(method), substitutor); @@ -215,56 +187,91 @@ public class SubstitutorComputer { return partialSubstitutor.putAll(substitutor); } - @Nullable - private PsiType handleConversion(@Nullable PsiType paramType, @Nullable PsiType argType) { + @NotNull + private Deque buildInferenceQueue(@NotNull PsiMethod method, + @NotNull PsiTypeParameter[] typeParameters, + GrClosureParameter[] params, + GrClosureSignatureUtil.ArgInfo[] argInfos) { + Deque inferenceQueue = new ArrayDeque<>(); + + List parameterTypes = new ArrayList<>(); + List argumentTypes = new ArrayList<>(); + for (int paramIndex = 0; paramIndex < params.length; paramIndex++) { + PsiType paramType = params[paramIndex].getType(); + + GrClosureSignatureUtil.ArgInfo argInfo = argInfos[paramIndex]; + if (argInfo != null) { + if (argInfo.isMultiArg) { + if (paramType instanceof PsiArrayType) paramType = ((PsiArrayType)paramType).getComponentType(); + } + for (PsiType type : argInfo.args) { + PsiType argType = type; + if (isSAMConversion(paramType, type)) { + inferenceQueue.addLast(handleConversionOfSAMType(paramType, type, typeParameters)); + continue; + } + + if (argType instanceof GrTupleType) { + PsiType rawGenericType = TypesUtil.rawSecondGeneric(argType, method.getProject()); + argType = rawGenericType != null ? rawGenericType : argType; + } + + if (argType != null) { + argType = com.intellij.psi.util.PsiUtil.captureToplevelWildcards(argType, method); + } + parameterTypes.add(paramType); + argumentTypes.add(argType); + } + } + else { + parameterTypes.add(paramType); + argumentTypes.add(PsiType.NULL); + } + } + inferenceQueue.addFirst((ps) -> myHelper.inferTypeArguments(typeParameters, + parameterTypes.toArray(new PsiType[parameterTypes.size()]), + argumentTypes.toArray(new PsiType[argumentTypes.size()]), + ps, + LanguageLevel.JDK_1_8)); + return inferenceQueue; + } + + private boolean isSAMConversion(@Nullable PsiType paramType, @Nullable PsiType argType) { if (argType instanceof PsiClassType && isSamConversionAllowed(myPlace) && InheritanceUtil.isInheritor(argType, GroovyCommonClassNames.GROOVY_LANG_CLOSURE) && !TypesUtil.isClassType(paramType, GroovyCommonClassNames.GROOVY_LANG_CLOSURE)) { - PsiType converted = handleConversionOfSAMType(paramType, (PsiClassType)argType); - if (converted != null) { - return converted; - } - - return argType; + return true; } - - if (!TypesUtil.isAssignable(TypeConversionUtil.erasure(paramType), argType, myPlace) && - TypesUtil.isAssignableByMethodCallConversion(paramType, argType, myPlace)) { - return paramType; - } - return argType; + return false; } - @Nullable - private PsiType handleConversionOfSAMType(@Nullable PsiType targetType, @NotNull PsiClassType closure) { - if (!(targetType instanceof PsiClassType)) return null; + @NotNull + private InferenceStep handleConversionOfSAMType(@Nullable PsiType targetType, + @NotNull PsiType closure, + PsiTypeParameter[] typeParameters) { + if (!(closure instanceof PsiClassType)) return InferenceStep.EMPTY; + if (!(targetType instanceof PsiClassType)) return InferenceStep.EMPTY; ClassResolveResult resolveResult = ((PsiClassType)targetType).resolveGenerics(); PsiClass samClass = resolveResult.getElement(); - if (samClass == null) return null; - - PsiTypeParameter[] samClassTypeParameters = samClass.getTypeParameters(); - if (samClassTypeParameters.length == 0) return null; + if (samClass == null) return InferenceStep.EMPTY; PsiMethod sam = findSingleAbstractMethod(samClass); - if (sam == null) return null; + if (sam == null) return InferenceStep.EMPTY; - // at this point we know that target type is actually a SAM type + PsiType samReturnType = resolveResult.getSubstitutor().substitute(sam.getReturnType()); + if (samReturnType == null) return InferenceStep.EMPTY; - PsiType samReturnType = sam.getReturnType(); - if (samReturnType == null) return null; + PsiType[] parameters = ((PsiClassType) closure).getParameters(); + if (parameters.length != 1) return InferenceStep.EMPTY; - PsiType[] closureParameters = closure.getParameters(); - if (closureParameters.length != 1) return null; + PsiType[] rightTypes = closure instanceof GrClosureType ? ((GrClosureType)closure).inferParameters() : parameters; - PsiSubstitutor substitutor = myHelper.inferTypeArguments( - samClassTypeParameters, new PsiType[]{samReturnType}, closureParameters, LanguageLevel.JDK_1_8 - ); - if (substitutor.getSubstitutionMap().isEmpty()) return null; - - return JavaPsiFacade.getElementFactory(myPlace.getProject()).createType(samClass, substitutor); + return (ps) -> ps.putAll(myHelper.inferTypeArguments( + typeParameters, new PsiType[]{samReturnType}, rightTypes, ps, LanguageLevel.JDK_1_8 + )); } @@ -273,7 +280,8 @@ public class SubstitutorComputer { @NotNull PsiSubstitutor substitutor) { if (myPlace == null) return substitutor; - final PsiType inferred = myHelper.getSubstitutionForTypeParameter(typeParameter, lType, inferContextType(), false, LanguageLevel.JDK_1_7); + final PsiType inferred = + myHelper.getSubstitutionForTypeParameter(typeParameter, lType, inferContextType(), false, LanguageLevel.JDK_1_8); if (inferred != PsiType.NULL) { return substitutor.put(typeParameter, inferred); } @@ -283,4 +291,9 @@ public class SubstitutorComputer { public PsiType[] getTypeArguments() { return myTypeArguments; } + + private interface InferenceStep { + InferenceStep EMPTY = (ps) -> ps; + PsiSubstitutor doInfer(@NotNull PsiSubstitutor partialSubstitutor); + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrAssignAutoTestFalsePositiveTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrAssignAutoTestFalsePositiveTest.groovy index c397c76b2bcd..bba700185294 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrAssignAutoTestFalsePositiveTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrAssignAutoTestFalsePositiveTest.groovy @@ -8,6 +8,7 @@ import org.codehaus.groovy.control.MultipleCompilationErrorsException import org.jetbrains.annotations.NotNull import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection +import org.jetbrains.plugins.groovy.util.Slow /** * Character and char are skipped intentionally. @@ -15,6 +16,7 @@ import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilit * Current spec https://github.com/apache/groovy/blob/master/src/spec/doc/core-differences-java.adoc#conversions * Bug: https://issues.apache.org/jira/browse/GROOVY-7557 */ +@Slow class GrAssignAutoTestFalsePositiveTest extends GrHighlightingTestBase { List types = ['boolean', 'int', 'double', 'String', 'BigDecimal', 'BigInteger', 'List', 'Object', 'Thread', diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrGenericsInferringTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrGenericsInferringTest.groovy index ee70d9357c3f..2716e05fdefd 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrGenericsInferringTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrGenericsInferringTest.groovy @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.highlighting import com.intellij.codeInspection.InspectionProfileEntry @@ -468,6 +454,47 @@ class SomeClass { ''' } + void testOverloadWithPlaceholders() { + testHighlighting ''' +import groovy.transform.CompileStatic + +class User{} + +public interface Repo{ + def S save(S entitty) + def Iterable save(Iterable entities) +} + +@CompileStatic +interface Foo extends Repo { + +} + +@CompileStatic +static void main(Foo foo) { + foo.save(new User()) +} + ''' + } + + void testOverloadWithPlaceholders2() { + testHighlighting ''' +import groovy.transform.CompileStatic + +class User{} + +class Bar { + static void save(S s){} + static void save(List s){} +} + +@CompileStatic +static void main() { + Bar.save(new User()) +} + ''' + } + void testCollectMany() { testHighlighting ''' import groovy.transform.CompileStatic diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy index c510cacd0cb5..4e96fa6a143e 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy @@ -1,23 +1,10 @@ -/* - * Copyright 2000-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.PsiIntersectionType import com.intellij.psi.PsiReference import com.intellij.psi.PsiType +import com.intellij.psi.impl.source.PsiImmediateClassType import groovy.transform.CompileStatic import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap @@ -25,7 +12,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaratio import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression -import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType +import org.junit.Ignore import static com.intellij.psi.CommonClassNames.* @@ -108,9 +95,10 @@ class TypeInferenceTest extends TypeInferenceTestBase { assertTrue(ref.type.equalsToText("java.lang.String")) } + @Ignore void testLeastUpperBoundClosureType() { GrReferenceExpression ref = (GrReferenceExpression)configureByFile("leastUpperBoundClosureType/A.groovy").element - assertInstanceOf(ref.type, GrClosureType.class) + assertInstanceOf(ref.type, PsiImmediateClassType.class) } void testJavaLangClassType() { @@ -147,6 +135,7 @@ class TypeInferenceTest extends TypeInferenceTestBase { assertNotNull(resolve("A.groovy")) } + @Ignore void testMethodCallInvokedOnArrayAccess() { final GrReferenceExpression reference = (GrReferenceExpression)configureByFile("A.groovy") assertNotNull(reference) diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInAnonymousClass.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInAnonymousClass.test index b4438c3a8ca9..33c35c32d8a7 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInAnonymousClass.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/argsUsedOnlyInAnonymousClass.test @@ -1,6 +1,6 @@ def foo(b, c) { [].each (new Closure(this, this) { - void call() { + Void call() { b.plus(c) } }) @@ -12,7 +12,7 @@ def foo(b, c) { private List testMethod(b, c) { return [].each(new Closure(this, this) { - void call() { + Void call() { b.plus(c) } }) diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/closureIt.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/closureIt.test index 33009331cc16..f70fc43b3949 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/closureIt.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/closureIt.test @@ -6,6 +6,6 @@ def foo() { testMethod() } -private List testMethod() { +private List testMethod() { return [].collect { it } } \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/RawTypeInAssignment.groovy b/plugins/groovy/testdata/highlighting/RawTypeInAssignment.groovy index 951b7b3a0ab4..34921fb1f5c9 100644 --- a/plugins/groovy/testdata/highlighting/RawTypeInAssignment.groovy +++ b/plugins/groovy/testdata/highlighting/RawTypeInAssignment.groovy @@ -15,4 +15,4 @@ */ Map map3 map3 = [].collectEntries {} -int map4 = [].collectEntries {} +int map4 = [].collectEntries {}