diff options
Diffstat (limited to 'java/java-psi-impl/src/com/intellij/psi/impl/source')
9 files changed, 244 insertions, 122 deletions
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java index 78c5c2d8fdc8..fd38e3ddaf56 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java @@ -399,9 +399,14 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps @Override public PsiElement getOriginalElement() { - PsiClass originalClass = (PsiClass)getContainingClass().getOriginalElement(); - PsiField originalField = originalClass.findFieldByName(getName(), false); - return originalField != null ? originalField : this; + PsiClass containingClass = getContainingClass(); + if (containingClass != null) { + PsiField originalField = ((PsiClass)containingClass.getOriginalElement()).findFieldByName(getName(), false); + if (originalField != null) { + return originalField; + } + } + return this; } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java index e77e7ad01f5e..799f9b459e69 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java @@ -324,4 +324,24 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple final PsiElement declarationScope = getDeclarationScope(); return new LocalSearchScope(declarationScope); } + + @Override + public PsiElement getOriginalElement() { + PsiElement parent = getParent(); + if (parent instanceof PsiParameterList) { + PsiElement gParent = parent.getParent(); + if (gParent instanceof PsiMethod) { + PsiElement originalMethod = gParent.getOriginalElement(); + if (originalMethod instanceof PsiMethod) { + int index = ((PsiParameterList)parent).getParameterIndex(this); + PsiParameter[] originalParameters = ((PsiMethod)originalMethod).getParameterList().getParameters(); + if (index < originalParameters.length) { + return originalParameters[index]; + } + } + } + } + return this; + } + } 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 556bf7152b68..a27dfe5adb83 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 @@ -15,7 +15,6 @@ */ package com.intellij.psi.impl.source.resolve; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -211,16 +210,8 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { .getSubstitutionForTypeParameter(typeParam, param, arg, isContraVariantPosition, languageLevel); } - private PsiInferenceHelper myTestHelper; - - public void setTestHelper(PsiInferenceHelper testHelper) { - myTestHelper = testHelper; - } - - public PsiInferenceHelper getInferenceHelper(LanguageLevel languageLevel) { - if (ApplicationManager.getApplication().isUnitTestMode() && myTestHelper != null) { - return myTestHelper; - } + @NotNull + public PsiInferenceHelper getInferenceHelper(@NotNull LanguageLevel languageLevel) { if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { return new PsiGraphInferenceHelper(myManager); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index 35db6c29bc0c..a1b4570e5361 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -174,7 +174,6 @@ public class InferenceSession { } } } - return true; } if (expr instanceof PsiLambdaExpression) { if (!((PsiLambdaExpression)expr).hasFormalParameterTypes()) { @@ -234,7 +233,7 @@ public class InferenceSession { !MethodCandidateInfo.ourOverloadGuard.currentStack().contains(PsiUtil.skipParenthesizedExprUp(parent.getParent()))) { final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>(); if (parameters.length > 0) { - collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs(), true); + collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs()); } if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) { @@ -264,67 +263,113 @@ public class InferenceSession { PsiMethod parentMethod, PsiSubstitutor siteSubstitutor, Set<ConstraintFormula> additionalConstraints, - boolean varargs, boolean toplevel) { + boolean varargs) { for (int i = 0; i < args.length; i++) { - if (args[i] != null) { - InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(args[i], PsiCallExpression.class)); - if (session == null) { - session = this; - } - PsiType parameterType = session.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs)); - if (!isPertinentToApplicability(args[i], parentMethod)) { - additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType)); + final PsiExpression arg = PsiUtil.skipParenthesizedExprDown(args[i]); + if (arg != null) { + final InferenceSession nestedCallSession = findNestedCallSession(arg); + final PsiType parameterType = + nestedCallSession.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs)); + if (!isPertinentToApplicability(arg, parentMethod)) { + additionalConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType)); } - additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType)); - if (args[i] instanceof PsiCallExpression && PsiPolyExpressionUtil.isPolyExpression(args[i])) { + additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(arg, parameterType)); + if (arg instanceof PsiCallExpression) { //If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12), //the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type. - final PsiCallExpression callExpression = (PsiCallExpression)args[i]; - collectAdditionalConstraints(additionalConstraints, callExpression); - } else if (args[i] instanceof PsiLambdaExpression && toplevel) { - final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType); - if (interfaceReturnType != null) { - final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)args[i]); - for (PsiExpression returnExpression : returnExpressions) { - if (returnExpression instanceof PsiCallExpression) { - final PsiCallExpression callExpression = (PsiCallExpression)returnExpression; - collectAdditionalConstraints(additionalConstraints, callExpression); - } - } + final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)arg); + if (PsiPolyExpressionUtil.isMethodCallPolyExpression(arg, calledMethod)) { + collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)arg); } + } else if (arg instanceof PsiLambdaExpression) { + collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType); } } } } + private static PsiMethod getCalledMethod(PsiCallExpression arg) { + final PsiExpressionList argumentList = arg.getArgumentList(); + if (argumentList == null || argumentList.getExpressions().length == 0) { + return null; + } + + MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList); + if (properties != null) { + return properties.getMethod(); + } + final JavaResolveResult resolveResult = getMethodResult(arg); + return resolveResult instanceof MethodCandidateInfo ? (PsiMethod)resolveResult.getElement() : null; + } + + private void collectLambdaReturnExpression(Set<ConstraintFormula> additionalConstraints, + PsiLambdaExpression lambdaExpression, + PsiType parameterType) { + final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType); + if (interfaceReturnType != null) { + final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression); + for (PsiExpression returnExpression : returnExpressions) { + processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType); + } + } + } + + private void processReturnExpression(Set<ConstraintFormula> additionalConstraints, + PsiExpression returnExpression, + PsiType functionalType) { + if (returnExpression instanceof PsiCallExpression) { + final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression); + if (PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) { + collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression); + } + } + else if (returnExpression instanceof PsiParenthesizedExpression) { + processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType); + } + else if (returnExpression instanceof PsiConditionalExpression) { + processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType); + processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType); + } + else if (returnExpression instanceof PsiLambdaExpression) { + collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType); + } + } + private void collectAdditionalConstraints(final Set<ConstraintFormula> additionalConstraints, final PsiCallExpression callExpression) { PsiExpressionList argumentList = callExpression.getArgumentList(); if (argumentList != null) { - final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class); - final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() { - @Override - public JavaResolveResult compute() { - return callExpression.resolveMethodGenerics(); - } - }; + final JavaResolveResult result = getMethodResult(callExpression); MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList); - final JavaResolveResult result = properties != null ? null : - expression == null - ? computableResolve.compute() - : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve); final PsiMethod method = result instanceof MethodCandidateInfo ? ((MethodCandidateInfo)result).getElement() : properties != null ? properties.getMethod() : null; if (method != null) { final PsiExpression[] newArgs = argumentList.getExpressions(); final PsiParameter[] newParams = method.getParameterList().getParameters(); if (newParams.length > 0) { collectAdditionalConstraints(newParams, newArgs, method, result != null ? ((MethodCandidateInfo)result).getSiteSubstitutor() : properties.getSubstitutor(), - additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs(), false); + additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs()); } } } } + private static JavaResolveResult getMethodResult(final PsiCallExpression callExpression) { + final PsiExpressionList argumentList = callExpression.getArgumentList(); + + final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class); + final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() { + @Override + public JavaResolveResult compute() { + return callExpression.resolveMethodGenerics(); + } + }; + MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList); + return properties != null ? null : + expression == null + ? computableResolve.compute() + : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve); + } + public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) { PsiSubstitutor substitutor = mySiteSubstitutor; for (InferenceVariable variable : variables) { @@ -702,7 +747,7 @@ public class InferenceSession { } final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); - final PsiTypeParameter[] freshParameters = createFreshVariables(vars); + final PsiTypeParameter[] freshParameters = createFreshVariables(vars, substitutor); for (int i = 0; i < freshParameters.length; i++) { PsiTypeParameter parameter = freshParameters[i]; final InferenceVariable var = vars.get(i); @@ -725,7 +770,7 @@ public class InferenceSession { return substitutor; } - private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars) { + private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars, final PsiSubstitutor siteSubstitutor) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; @@ -742,7 +787,7 @@ public class InferenceSession { final String classText = "class I<" + StringUtil.join(vars, new Function<InferenceVariable, String>() { @Override public String fun(InferenceVariable variable) { - final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor, true); + final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor.putAll(siteSubstitutor), true); return getFreshVariableName(variable) + " extends " + glb.getInternalCanonicalText(); } }, ", ") + ">{}"; @@ -860,46 +905,67 @@ public class InferenceSession { //extract subset of constraints final Set<ConstraintFormula> subset = buildSubset(additionalConstraints); - //collect all input variables of selection + //collect all input variables of selection final Set<InferenceVariable> varsToResolve = new LinkedHashSet<InferenceVariable>(); for (ConstraintFormula formula : subset) { if (formula instanceof InputOutputConstraintFormula) { - final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)formula).getInputVariables(this); - if (inputVariables != null) { - for (InferenceVariable inputVariable : inputVariables) { - varsToResolve.addAll(inputVariable.getDependencies(this)); - } - varsToResolve.addAll(inputVariables); - } + collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula); } } - //resolve input variables - PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor); - if (substitutor == null) { - return false; + for (ConstraintFormula formula : subset) { + if (!processOneConstraint(formula, siteSubstitutor, varsToResolve)) return false; } + } + return true; + } - if (myContext instanceof PsiCallExpression) { - PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList(); - LOG.assertTrue(argumentList != null); - MethodCandidateInfo.updateSubstitutor(argumentList, substitutor); + private void collectVarsToResolve(Set<InferenceVariable> varsToResolve, InputOutputConstraintFormula formula) { + final Set<InferenceVariable> inputVariables = formula.getInputVariables(this); + if (inputVariables != null) { + for (InferenceVariable inputVariable : inputVariables) { + varsToResolve.addAll(inputVariable.getDependencies(this)); } + varsToResolve.addAll(inputVariables); + } + } - try { - for (ConstraintFormula additionalConstraint : subset) { - additionalConstraint.apply(substitutor, true); - } - - myConstraints.addAll(subset); - if (!repeatInferencePhases(true)) { - return false; + private boolean processOneConstraint(ConstraintFormula formula, PsiSubstitutor siteSubstitutor, Set<InferenceVariable> varsToResolve) { + if (formula instanceof ExpressionCompatibilityConstraint) { + final PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression(); + final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(expression, PsiCallExpression.class, false); + if (callExpression != null) { + final InferenceSession session = myNestedSessions.get(callExpression); + if (session != null) { + formula.apply(session.myInferenceSubstitution, true); + collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula); } } - finally { - LambdaUtil.ourFunctionTypes.set(null); + } + + //resolve input variables + PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor); + if (substitutor == null) { + return false; + } + + if (myContext instanceof PsiCallExpression) { + PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList(); + LOG.assertTrue(argumentList != null); + MethodCandidateInfo.updateSubstitutor(argumentList, substitutor); + } + + try { + formula.apply(substitutor, true); + + myConstraints.add(formula); + if (!repeatInferencePhases(true)) { + return false; } } + finally { + LambdaUtil.ourFunctionTypes.set(null); + } return true; } @@ -1139,9 +1205,6 @@ public class InferenceSession { } final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)arg); - if (sReturnType == PsiType.VOID) { - return returnExpressions.isEmpty() && session == null; - } if (LambdaUtil.isFunctionalType(sReturnType) && LambdaUtil.isFunctionalType(tReturnType) && !TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(sReturnType), TypeConversionUtil.erasure(tReturnType)) && @@ -1197,10 +1260,6 @@ public class InferenceSession { return true; } - if (sReturnType == PsiType.VOID && session != null) { - return false; - } - final boolean sPrimitive = sReturnType instanceof PsiPrimitiveType && sReturnType != PsiType.VOID; final boolean tPrimitive = tReturnType instanceof PsiPrimitiveType && tReturnType != PsiType.VOID; @@ -1295,6 +1354,14 @@ public class InferenceSession { return myInferenceSubstitution.substitute(type); } + public InferenceSession findNestedCallSession(PsiExpression arg) { + InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(arg, PsiCallExpression.class)); + if (session == null) { + session = this; + } + return session; + } + public PsiType startWithFreshVars(PsiType type) { PsiSubstitutor s = PsiSubstitutor.EMPTY; for (InferenceVariable variable : myInferenceVariables) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java index 8d91b620f798..da7b4b78930a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightTypeParameter; +import com.intellij.psi.util.PsiUtil; import java.util.*; @@ -49,6 +50,10 @@ public class InferenceVariable extends LightTypeParameter { } public boolean addBound(PsiType classType, InferenceBound inferenceBound) { + if (inferenceBound == InferenceBound.EQ && + PsiUtil.resolveClassInClassTypeOnly(classType) == this) { + return false; + } List<PsiType> list = myBounds.get(inferenceBound); if (list == null) { list = new ArrayList<PsiType>(); @@ -77,20 +82,18 @@ public class InferenceVariable extends LightTypeParameter { } } + if (!session.hasCapture(this) && dependencies.isEmpty()) { + return dependencies; + } + next: for (InferenceVariable variable : session.getInferenceVariables()) { if (!dependencies.contains(variable) && variable != this) { - nextBound: - for (List<PsiType> bounds : myBounds.values()) { //todo + for (List<PsiType> bounds : variable.myBounds.values()) { //todo if (bounds != null) { for (PsiType bound : bounds) { - final Set<InferenceVariable> deps = new HashSet<InferenceVariable>(); - session.collectDependencies(bound, deps); - if (deps.isEmpty()) { - continue nextBound; - } - - if (deps.contains(this)) { + final InferenceVariable inferenceVariable = session.getInferenceVariable(bound); + if (inferenceVariable == this) { dependencies.add(variable); continue next; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java index c282481e79c0..f7e9badfa33c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java @@ -3,6 +3,7 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import java.util.List; @@ -62,8 +63,9 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul if (returnExpressions.isEmpty() && !myExpression.isValueCompatible()) { //not value-compatible return false; } - returnType = session.substituteWithInferenceVariables(substitutor.substitute(returnType)); - if (!session.isProperType(returnType)) { + InferenceSession callsession = session.findNestedCallSession(myExpression); + returnType = callsession.substituteWithInferenceVariables(substitutor.substitute(returnType)); + if (!callsession.isProperType(returnType)) { for (PsiExpression returnExpression : returnExpressions) { constraints.add(new ExpressionCompatibilityConstraint(returnExpression, returnType)); } 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 fbfd8195fc11..b5e4188e1644 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 @@ -169,11 +169,11 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm } LOG.assertTrue(referencedMethodReturnType != null, method); - session.initBounds(method.getTypeParameters()); + session.initBounds(myExpression, method.getTypeParameters()); if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || PsiUtil.getEnclosingStaticElement(myExpression, containingClass) != null) { - session.initBounds(containingClass.getTypeParameters()); + session.initBounds(myExpression, containingClass.getTypeParameters()); } //if i) the method reference elides NonWildTypeArguments, @@ -243,7 +243,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType); if (qualifierClass != null) { - session.initBounds(qualifierClass.getTypeParameters()); + session.initBounds(myExpression, qualifierClass.getTypeParameters()); constraints.add(new StrictSubtypingConstraint(session.substituteWithInferenceVariables(qualifierType), session.substituteWithInferenceVariables(substitutor.substitute(targetParameters[0].getType())))); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java index 412b09eadec3..6b3c104aab35 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java @@ -92,8 +92,22 @@ public class StrictSubtypingConstraint implements ConstraintFormula { return false; } - if (!(myS instanceof PsiClassType)) return false; - PsiClassType.ClassResolveResult SResult = ((PsiClassType)myS).resolveGenerics(); + PsiClassType.ClassResolveResult SResult = null; + if (myS instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType)myS).getConjuncts()) { + if (conjunct instanceof PsiClassType) { + final PsiClassType.ClassResolveResult conjunctResult = ((PsiClassType)conjunct).resolveGenerics(); + if (InheritanceUtil.isInheritorOrSelf(conjunctResult.getElement(), CClass, true)) { + SResult = conjunctResult; + break; + } + } + } + } else if (myS instanceof PsiClassType) { + SResult = ((PsiClassType)myS).resolveGenerics(); + } + + if (SResult == null) return false; PsiClass SClass = SResult.getElement(); if (((PsiClassType)myT).isRaw()) { return SClass != null && InheritanceUtil.isInheritorOrSelf(SClass, CClass, true); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java index 069f667d92cf..9d35ace98cf4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java @@ -30,7 +30,6 @@ import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.containers.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -78,16 +77,11 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi @Override public boolean isVoidCompatible() { final PsiElement body = getBody(); - if (body != null) { - try { - ControlFlow controlFlow = ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy - .getInstance()); - int startOffset = controlFlow.getStartOffset(body); - int endOffset = controlFlow.getEndOffset(body); - return startOffset != -1 && endOffset != -1 && !ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset); - } - catch (AnalysisCanceledException e) { - return true; + if (body instanceof PsiCodeBlock) { + for (PsiReturnStatement statement : PsiUtil.findReturnStatements((PsiCodeBlock)body)) { + if (statement.getReturnValue() != null) { + return false; + } } } return true; @@ -96,18 +90,25 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi @Override public boolean isValueCompatible() { final PsiElement body = getBody(); - if (body != null) { + if (body instanceof PsiCodeBlock) { try { - final ControlFlow controlFlow = - ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); - if (ControlFlowUtil.findExitPointsAndStatements(controlFlow, 0, controlFlow.getSize(), new IntArrayList(), - PsiReturnStatement.class, - PsiThrowStatement.class).isEmpty()) { + ControlFlow controlFlow = + ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy + .getInstance()); + int startOffset = controlFlow.getStartOffset(body); + int endOffset = controlFlow.getEndOffset(body); + if (startOffset != -1 && endOffset != -1 && ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset)) { return false; } } catch (AnalysisCanceledException e) { - return true; + return false; + } + + for (PsiReturnStatement statement : PsiUtil.findReturnStatements((PsiCodeBlock)body)) { + if (statement.getReturnValue() == null) { + return false; + } } } return true; @@ -200,17 +201,36 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi } } + + //A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true: + // The arity of the target type's function type is the same as the arity of the lambda expression. + // If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2). + // If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2). + PsiType methodReturnType = interfaceMethod.getReturnType(); if (checkReturnType) { final String uniqueVarName = JavaCodeStyleManager.getInstance(getProject()).suggestUniqueVariableName("l", this, true); final String canonicalText = toArray(leftType).getCanonicalText(); final PsiStatement assignmentFromText = JavaPsiFacade.getElementFactory(getProject()) .createStatementFromText(canonicalText + " " + uniqueVarName + " = " + getText(), this); final PsiLocalVariable localVariable = (PsiLocalVariable)((PsiDeclarationStatement)assignmentFromText).getDeclaredElements()[0]; - PsiType methodReturnType = interfaceMethod.getReturnType(); if (methodReturnType != null) { return LambdaHighlightingUtil.checkReturnTypeCompatible((PsiLambdaExpression)localVariable.getInitializer(), substitutor.substitute(methodReturnType)) == null; } + } else { + final PsiElement body = getBody(); + if (methodReturnType == PsiType.VOID) { + if (body instanceof PsiCodeBlock) { + return isVoidCompatible(); + } else { + return LambdaUtil.isExpressionStatementExpression(body); + } + } else { + if (body instanceof PsiCodeBlock) { + return isValueCompatible(); + } + return body instanceof PsiExpression; + } } return true; } |