diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index c916cf2a1aec..2338a925e25d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -74,7 +74,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiClass applicableMemberContainingClass = applicableMember.getContainingClass(); final PsiClass containingClass = qualifierResolveResult.getContainingClass(); - PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, applicableMember, applicableMemberContainingClass); + PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, applicableMember, applicableMemberContainingClass, myExpression); int idx = 0; for (PsiTypeParameter param : ((PsiTypeParameterListOwner)applicableMember).getTypeParameters()) { @@ -167,7 +167,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiType referencedMethodReturnType; final PsiClass containingClass = method.getContainingClass(); LOG.assertTrue(containingClass != null, method); - PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, method, containingClass); + PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, method, containingClass, myExpression); if (method.isConstructor()) { referencedMethodReturnType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass, PsiSubstitutor.EMPTY); @@ -218,19 +218,22 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm return true; } - private PsiSubstitutor getSubstitutor(MethodSignature signature, - PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult, - PsiMember member, - @Nullable PsiClass containingClass) { + public static PsiSubstitutor getSubstitutor(MethodSignature signature, + PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult, + PsiMember member, + @Nullable PsiClass containingClass, + final PsiMethodReferenceExpression methodReferenceExpression) { final PsiClass qContainingClass = qualifierResolveResult.getContainingClass(); PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor(); if (qContainingClass != null && containingClass != null) { // 15.13.1 If the ReferenceType is a raw type, and there exists a parameterization of this type, T, that is a supertype of P1, // the type to search is the result of capture conversion (5.1.10) applied to T; // otherwise, the type to search is the same as the type of the first search. Again, the type arguments, if any, are given by the method reference. - if ( PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) { - if (member instanceof PsiMethod && PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, myExpression)) { - final PsiType pType = PsiUtil.captureToplevelWildcards(signature.getParameterTypes()[0], myExpression); + if (PsiUtil.isRawSubstitutor(qContainingClass, psiSubstitutor)) { + if (member instanceof PsiMethod && + PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, + methodReferenceExpression)) { + final PsiType pType = PsiUtil.captureToplevelWildcards(signature.getParameterTypes()[0], methodReferenceExpression); psiSubstitutor = getParameterizedTypeSubstitutor(qContainingClass, pType); } else if (member instanceof PsiMethod && ((PsiMethod)member).isConstructor() || member instanceof PsiClass) { @@ -238,16 +241,16 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm //If ClassType is a raw type, but is not a non-static member type of a raw type, //the candidate notional member methods are those specified in ยง15.9.3 for a class instance creation expression that uses <> //to elide the type arguments to a class. - final PsiResolveHelper helper = JavaPsiFacade.getInstance(myExpression.getProject()).getResolveHelper(); + final PsiResolveHelper helper = JavaPsiFacade.getInstance(methodReferenceExpression.getProject()).getResolveHelper(); final PsiType[] paramTypes = member instanceof PsiMethod ? ((PsiMethod)member).getSignature(PsiSubstitutor.EMPTY).getParameterTypes() : PsiType.EMPTY_ARRAY; - LOG.assertTrue(paramTypes.length == signature.getParameterTypes().length, "expr: " + myExpression + "; " + + LOG.assertTrue(paramTypes.length == signature.getParameterTypes().length, "expr: " + methodReferenceExpression + "; " + paramTypes.length + "; " + Arrays.toString(signature.getParameterTypes())); psiSubstitutor = helper.inferTypeArguments(qContainingClass.getTypeParameters(), paramTypes, signature.getParameterTypes(), - PsiUtil.getLanguageLevel(myExpression)); + PsiUtil.getLanguageLevel(methodReferenceExpression)); } else { psiSubstitutor = PsiSubstitutor.EMPTY; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java index b993727a30ed..3d3a759ca71f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java @@ -21,6 +21,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy; import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.impl.source.resolve.graphInference.constraints.PsiMethodReferenceCompatibilityConstraint; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.infos.ClassCandidateInfo; import com.intellij.psi.infos.MethodCandidateInfo; @@ -127,7 +128,8 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR } if (includeReturnConstraint && !PsiType.VOID.equals(interfaceMethodReturnType) && interfaceMethodReturnType != null) { - final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, substitutor) : substitutor.substitute(method.getReturnType()); + PsiSubstitutor subst = PsiMethodReferenceCompatibilityConstraint.getSubstitutor(signature, qualifierResolveResult, method, containingClass, reference); + final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, subst) : subst.substitute(method.getReturnType()); if (returnType != null) { session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/ReturnTypeCompatibilityConstraintForSecondSearchCase.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/ReturnTypeCompatibilityConstraintForSecondSearchCase.java new file mode 100644 index 000000000000..85f183ff4b68 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/ReturnTypeCompatibilityConstraintForSecondSearchCase.java @@ -0,0 +1,19 @@ + +class Test { + public interface Copier { + TypeT m(TypeT value); + } + + public static class A { + public > OtherT copy() { + return null; + } + } + + static void foo(TypeT value, Copier copier) {} + + public static void foo() { + A val = new A<>(); + foo(val, A::copy); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index 0c1dbb90c60c..4acf09e0f382 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -529,6 +529,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testReturnTypeCompatibilityConstraintForSecondSearchCase() throws Exception { + doTest(); + } + private void doTest() { doTest(false); }