boolean (InferenceSession session, List<? super ConstraintFormula> constraints) { if (!LambdaUtil.isFunctionalType(myT)) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.not.a.functional.interface", session.getPresentableText(myT))); return false; } final PsiType groundTargetType = myExpression.getGroundTargetType(myT); final PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(groundTargetType); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(classResolveResult); if (interfaceMethod == null) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.no.valid.function.type.found", session.getPresentableText(myT))); return false; } final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, classResolveResult); final MethodSignature signature = interfaceMethod.getSignature(substitutor); final PsiParameter[] targetParameters = interfaceMethod.getParameterList().getParameters(); final PsiType interfaceMethodReturnType = interfaceMethod.getReturnType(); final PsiType returnType = substitutor.substitute(interfaceMethodReturnType); final PsiType[] typeParameters = myExpression.getTypeParameters(); final PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult = PsiMethodReferenceUtil.getQualifierResolveResult(myExpression); if (myExpression.isExact()) { final PsiMember applicableMember = myExpression.getPotentiallyApplicableMember(); LOG.assertTrue(applicableMember != null); final PsiClass applicableMemberContainingClass = applicableMember.getContainingClass(); final PsiClass containingClass = qualifierResolveResult.getContainingClass(); PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, applicableMember, applicableMemberContainingClass, myExpression); int idx = 0; for (PsiTypeParameter param : ((PsiTypeParameterListOwner)applicableMember).getTypeParameters()) { if (idx < typeParameters.length) { psiSubstitutor = psiSubstitutor.put(param, typeParameters[idx++]); } } final PsiParameter[] parameters = applicableMember instanceof PsiMethod ? ((PsiMethod)applicableMember).getParameterList().getParameters() : PsiParameter.EMPTY_ARRAY; if (targetParameters.length == parameters.length + 1) { final PsiType qualifierType = PsiMethodReferenceUtil.getQualifierType(myExpression); final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType); if (qualifierClass != null) { final PsiType pType = signature.getParameterTypes()[0]; constraints.add(new StrictSubtypingConstraint(session.substituteWithInferenceVariables(qualifierType), pType)); } for (int i = 1; i < targetParameters.length; i++) { constraints.add(new TypeCompatibilityConstraint(session.substituteWithInferenceVariables(psiSubstitutor.substitute(parameters[i - 1].getType())), PsiUtil.captureToplevelWildcards(signature.getParameterTypes()[i], myExpression))); } } else if (targetParameters.length == parameters.length) { for (int i = 0; i < targetParameters.length; i++) { constraints.add(new TypeCompatibilityConstraint(session.substituteWithInferenceVariables(psiSubstitutor.substitute(parameters[i].getType())), PsiUtil.captureToplevelWildcards(signature.getParameterTypes()[i], myExpression))); } } else { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.incompatible.parameter.types.in.method.reference")); return false; } if (!PsiTypes.voidType().equals(returnType) && returnType != null) { PsiType applicableMethodReturnType = null; if (applicableMember instanceof PsiMethod) { final PsiType getClassReturnType = PsiTypesUtil.patchMethodGetClassReturnType(myExpression, (PsiMethod)applicableMember); applicableMethodReturnType = getClassReturnType != null ? getClassReturnType : ((PsiMethod)applicableMember).getReturnType(); } if (PsiTypes.voidType().equals(applicableMethodReturnType)) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.incompatible.types.expected.not.void.got.void.method.reference")); return false; } if (applicableMethodReturnType == null && (applicableMember instanceof PsiClass || applicableMember instanceof PsiMethod && ((PsiMethod)applicableMember).isConstructor())) { if (containingClass != null) { applicableMethodReturnType = JavaPsiFacade.getElementFactory(applicableMember.getProject()).createType(containingClass, PsiSubstitutor.EMPTY); } } if (applicableMethodReturnType != null) { applicableMethodReturnType = psiSubstitutor.substitute(applicableMethodReturnType); applicableMethodReturnType = Registry.is("unsound.capture.conversion.java.spec.change") ? applicableMethodReturnType : PsiUtil.captureToplevelWildcards(applicableMethodReturnType, myExpression); constraints.add(new TypeCompatibilityConstraint(returnType, session.substituteWithInferenceVariables(applicableMethodReturnType))); } } return true; } //------ non exact method references -------------------- for (PsiType paramType : signature.getParameterTypes()) { if (!session.isProperType(paramType)) { //session.registerIncompatibleErrorMessage("Parameter type in not yet inferred: " + session.getPresentableText(paramType)); return false; } } JavaResolveResult resolve = myExpression.advancedResolve(false); final PsiElement element = resolve.getElement(); if (element == null || resolve instanceof MethodCandidateInfo && !((MethodCandidateInfo)resolve).isApplicable()) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.declaration.for.the.method.reference.not.found")); return false; } if (PsiTypes.voidType().equals(returnType) || returnType == null) { return true; } if (element instanceof PsiMethod) { final PsiMethod method = (PsiMethod)element; PsiType referencedMethodReturnType; final PsiClass containingClass = method.getContainingClass(); LOG.assertTrue(containingClass != null, method); PsiSubstitutor psiSubstitutor = getSubstitutor(signature, qualifierResolveResult, method, containingClass, myExpression); if (method.isConstructor()) { referencedMethodReturnType = JavaPsiFacade.getElementFactory(method.getProject()).createType(containingClass, PsiSubstitutor.EMPTY); } else { final PsiType getClassReturnType = PsiTypesUtil.patchMethodGetClassReturnType(myExpression, method); referencedMethodReturnType = getClassReturnType != null ? getClassReturnType : method.getReturnType(); } LOG.assertTrue(referencedMethodReturnType != null, method); //if i) the method reference elides NonWildTypeArguments, // ii) the compile-time declaration is a generic method, and // iii) the return type of the compile-time declaration mentions at least one of the method's type parameters; if (typeParameters.length == 0) { PsiTypeParameter[] methodTypeParameters = method.isConstructor() ? containingClass.getTypeParameters() : method.getTypeParameters(); if (methodTypeParameters.length > 0) { final PsiClass interfaceClass = classResolveResult.getElement(); LOG.assertTrue(interfaceClass != null); if (PsiTypesUtil.mentionsTypeParameters(referencedMethodReturnType, ContainerUtil.newHashSet(methodTypeParameters))) { session.initBounds(myExpression, psiSubstitutor, methodTypeParameters); //the constraint reduces to the bound set B3 which would be used to determine the method reference's invocation type //when targeting the return type of the function type, as defined in 18.5.2. session.collectApplicabilityConstraints(myExpression, ((MethodCandidateInfo)resolve), groundTargetType); session.registerReturnTypeConstraints(psiSubstitutor.substitute(referencedMethodReturnType), returnType, myExpression); return true; } } } if (PsiTypes.voidType().equals(referencedMethodReturnType)) { session.registerIncompatibleErrorMessage( JavaPsiBundle.message("error.incompatible.type.expected.non.void.got.void.method.reference")); return false; } int idx = 0; for (PsiTypeParameter param : method.getTypeParameters()) { if (idx < typeParameters.length) { psiSubstitutor = psiSubstitutor.put(param, typeParameters[idx++]); } } PsiClass qContainingClass = qualifierResolveResult.getContainingClass(); if (qContainingClass != null && PsiUtil.isRawSubstitutor(qContainingClass, qualifierResolveResult.getSubstitutor())) { //15.13.1 If there exist a parameterization, then it would be used to search, the *raw type* would be used otherwise if (getParameterization(signature, qualifierResolveResult, method, myExpression, qContainingClass) == null) { if (!PsiMethodReferenceUtil.isSecondSearchPossible(signature.getParameterTypes(), qualifierResolveResult, myExpression)) { session.initBounds(myExpression, qContainingClass.getTypeParameters()); } else { referencedMethodReturnType = TypeConversionUtil.erasure(referencedMethodReturnType); } } } referencedMethodReturnType = psiSubstitutor.substitute(referencedMethodReturnType); referencedMethodReturnType = Registry.is("unsound.capture.conversion.java.spec.change") ? referencedMethodReturnType : PsiUtil.captureToplevelWildcards(referencedMethodReturnType, myExpression); constraints.add(new TypeCompatibilityConstraint(returnType, session.substituteWithInferenceVariables(referencedMethodReturnType))); } return true; }