PsiType (PsiType psiClassType, PsiLambdaExpression expr, boolean performFinalCheck) { final PsiParameter[] lambdaParams = expr.getParameterList().getParameters(); LOG.assertTrue(psiClassType instanceof PsiClassType, "Unexpected type: " + psiClassType); final PsiType[] parameters = ((PsiClassType)psiClassType).getParameters(); final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)psiClassType).resolveGenerics(); PsiClass psiClass = resolveResult.getElement(); if (psiClass != null) { final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); if (interfaceMethod == null) return null; final PsiClass samClass = interfaceMethod.getContainingClass(); if (samClass == null) return null; PsiTypeParameter[] typeParameters = psiClass.getTypeParameters(); if (typeParameters.length != parameters.length) { return null; } final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiClass.getProject()); final PsiParameter[] targetMethodParams = interfaceMethod.getParameterList().getParameters(); if (targetMethodParams.length != lambdaParams.length) { return null; } final PsiSubstitutor lambdaSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(samClass, psiClass, PsiSubstitutor.EMPTY); final InferenceSession session = new InferenceSession(typeParameters, PsiSubstitutor.EMPTY, expr.getManager(), expr); for (int i = 0; i < targetMethodParams.length; i++) { final PsiType qType = lambdaSubstitutor.substitute(targetMethodParams[i].getType()); session.addConstraint(new TypeEqualityConstraint(lambdaParams[i].getType(), session.substituteWithInferenceVariables(qType))); } if (!session.repeatInferencePhases()) { return null; } final PsiSubstitutor substitutor = session.getInstantiations(session.getInferenceVariables()); final PsiType[] newTypeParameters = new PsiType[parameters.length]; for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; if (substitutor.getSubstitutionMap().containsKey(typeParameter)) { newTypeParameters[i] = substitutor.substitute(typeParameter); } else { newTypeParameters[i] = parameters[i]; } } final PsiClassType parameterization = elementFactory.createType(psiClass, newTypeParameters); //If F<A'1, ..., A'm> is not a well-formed type (that is, the type arguments are not within their bounds), // or if F<A'1, ..., A'm> is not a subtype of F<A1, ..., Am>, no valid parameterization exists. if (!isWellFormed(psiClass, typeParameters, newTypeParameters) || performFinalCheck && !psiClassType.isAssignableFrom(parameterization)) { return null; } //Otherwise, the inferred parameterization is either F<A'1, ..., A'm>, if all the type arguments are types, if (!isWildcardParameterized(parameterization)) { return parameterization; } //or the non-wildcard parameterization (p9.8) of F<A'1, ..., A'm>, if one or more type arguments are still wildcards. return getNonWildcardParameterization(parameterization); } return null; }