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 b7dc1e65ec6a..ac12a59c5336 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 @@ -27,6 +27,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.constraints.*; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.scope.MethodProcessorSetupFailedException; import com.intellij.psi.scope.processor.MethodCandidatesProcessor; +import com.intellij.psi.scope.processor.MethodResolverProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; @@ -304,25 +305,16 @@ public class InferenceSession { returnType = PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context); PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context); if (targetType == null) { + final PsiType finalReturnType = returnType; targetType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(context, true, new Computable() { @Override public PsiType compute() { - return getTargetType(context); + return getTargetType(context, finalReturnType); } }); } if (targetType != null) { - final InferenceVariable inferenceVariable = shouldResolveAndInstantiate(returnType, targetType); - if (inferenceVariable != null) { - resolveBounds(Collections.singletonList(inferenceVariable), mySiteSubstitutor, true); - myConstraints.add(new TypeCompatibilityConstraint(inferenceVariable.getInstantiation(), returnType)); - } - else { - if (targetType instanceof PsiClassType && ((PsiClassType)targetType).isRaw()) { - setErased(); - } - myConstraints.add(new TypeCompatibilityConstraint(myErased ? TypeConversionUtil.erasure(targetType) : GenericsUtil.eliminateWildcards(targetType, false), returnType)); - } + registerConstraints(returnType, targetType); } } } @@ -330,11 +322,26 @@ public class InferenceSession { for (PsiClassType thrownType : method.getThrowsList().getReferencedTypes()) { final InferenceVariable variable = getInferenceVariable(thrownType); if (variable != null) { - variable.setThrows(); + variable.setThrownBound(); } } } + private void registerConstraints(PsiType returnType, PsiType targetType) { + final InferenceVariable inferenceVariable = shouldResolveAndInstantiate(returnType, targetType); + if (inferenceVariable != null) { + resolveBounds(Collections.singletonList(inferenceVariable), mySiteSubstitutor, true); + myConstraints.add(new TypeCompatibilityConstraint(inferenceVariable.getInstantiation(), returnType)); + } + else { + if (targetType instanceof PsiClassType && ((PsiClassType)targetType).isRaw()) { + setErased(); + } + myConstraints.add(new TypeCompatibilityConstraint(myErased ? TypeConversionUtil.erasure(targetType) : GenericsUtil.eliminateWildcards( + targetType, false), returnType)); + } + } + private InferenceVariable shouldResolveAndInstantiate(PsiType returnType, PsiType targetType) { final InferenceVariable inferenceVariable = getInferenceVariable(returnType); if (inferenceVariable != null) { @@ -374,7 +381,7 @@ public class InferenceSession { return false; } - private PsiType getTargetType(final PsiExpression context) { + private PsiType getTargetType(final PsiExpression context, PsiType returnType) { final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent()); if (parent instanceof PsiExpressionList) { final PsiElement gParent = parent.getParent(); @@ -384,7 +391,7 @@ public class InferenceSession { final Pair pair = MethodCandidateInfo.getCurrentMethod(argumentList); final JavaResolveResult resolveResult; if (pair == null) { - final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(gParent, context.getContainingFile()) { + final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, argumentList, context.getContainingFile()) { @Override protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) { if (argumentList != null) { @@ -416,7 +423,13 @@ public class InferenceSession { for (JavaResolveResult result : results) { final PsiType type = getTypeByMethod(context, argumentList, null, result, result.getElement()); if (type != null) { - return type; + final Set parameters = myInferenceVariables.keySet(); + final InferenceSession session = new InferenceSession(parameters.toArray(new PsiTypeParameter[parameters.size()]), mySiteSubstitutor, myManager, myContext); + session.copy(this); + session.registerConstraints(returnType, type); + if (session.repeatInferencePhases(true)) { + return type; + } } } return null; @@ -427,7 +440,7 @@ public class InferenceSession { } else if (parent instanceof PsiConditionalExpression) { PsiType targetType = PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent); if (targetType == null) { - targetType = getTargetType((PsiExpression)parent); + targetType = getTargetType((PsiExpression)parent, returnType); } return targetType; } @@ -437,6 +450,12 @@ public class InferenceSession { return null; } + private void copy(InferenceSession session) { + for (PsiTypeParameter parameter : session.myInferenceVariables.keySet()) { + myInferenceVariables.put(parameter, session.myInferenceVariables.get(parameter).copy()); + } + } + private PsiType getTypeByMethod(PsiExpression context, PsiExpressionList argumentList, Pair pair, 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 e0e0486afd08..c3ef4b60794b 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 @@ -83,7 +83,20 @@ public class InferenceVariable { return myThrownBound; } - public void setThrows() { + public void setThrownBound() { myThrownBound = true; } + + public InferenceVariable copy() { + final InferenceVariable variable = new InferenceVariable(myParameter); + for (InferenceBound bound : InferenceBound.values()) { + for (PsiType type : getBounds(bound)) { + variable.addBound(type, bound); + } + } + if (myThrownBound) { + variable.setThrownBound(); + } + return variable; + } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java index 4a75428861e0..c3b5b0b3e959 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java @@ -146,7 +146,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai for (PsiType expectedNonProperThrownType : expectedNonProperThrownTypes) { final InferenceVariable variable = session.getInferenceVariable(expectedNonProperThrownType); LOG.assertTrue(variable != null); - variable.setThrows(); + variable.setThrownBound(); } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java index 736433a089c4..396d9b3b60d0 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java @@ -27,10 +27,15 @@ import org.jetbrains.annotations.NotNull; public class MethodResolverProcessor extends MethodCandidatesProcessor { private boolean myStopAcceptingCandidates = false; - public MethodResolverProcessor(@NotNull PsiMethodCallExpression place, @NotNull PsiFile placeFile){ - this(place, placeFile, new PsiConflictResolver[]{new JavaMethodsConflictResolver(place.getArgumentList(), - PsiUtil.getLanguageLevel(placeFile))}); - setArgumentList(place.getArgumentList()); + public MethodResolverProcessor(@NotNull PsiMethodCallExpression place, @NotNull PsiFile placeFile) { + this(place, place.getArgumentList(), placeFile); + } + + public MethodResolverProcessor(@NotNull PsiCallExpression place, + @NotNull PsiExpressionList argumentList, + @NotNull PsiFile placeFile){ + this(place, placeFile, new PsiConflictResolver[]{new JavaMethodsConflictResolver(argumentList, PsiUtil.getLanguageLevel(placeFile))}); + setArgumentList(argumentList); obtainTypeArguments(place); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/InferenceFromNotEqualTypeParamsBounds.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/InferenceFromNotEqualTypeParamsBounds.java index 764acd23750a..a5ad9f0f5a1e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/InferenceFromNotEqualTypeParamsBounds.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/InferenceFromNotEqualTypeParamsBounds.java @@ -29,7 +29,7 @@ public class ConcurrentCollectors { static > C groupingBy(F f, C c, BiConsumer consumer) { - return new CImpl<>(f, consumer, arg(c.getOp())); + return new CImpl<>(f, consumer, arg(c.getOp())); } static > BiOp arg(BiOp op) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/TargetTypeByOverloadedMethod2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/TargetTypeByOverloadedMethod2.java new file mode 100644 index 000000000000..139fcb4f5c22 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/TargetTypeByOverloadedMethod2.java @@ -0,0 +1,72 @@ +import java.util.Arrays; + +import static java.lang.System.out; + +public final class LambdaMain { + public static void main(final String... args) { + for (final A a : Arrays.>asList(new A() { + @Override + public String foo(final String ignored) + throws X { + throw new X(); + } + }, ignored -> { throw new X(); })) + try { + test(a, "Bob"); + } catch (final X x) { + x.printStackTrace(); + } + + try { + out.println(test(new A() { + @Override + public String foo(final String ignored) + throws X { + throw new X(); + } + }, "Bob")); + } catch (final Exception e) { + e.printStackTrace(); + } + + try { + out.println(test(ignored -> { throw new X(); }, "Bob")); + } catch (final Exception e) { + e.printStackTrace(); + } + } + + static class X + extends Exception {} + + interface A { + T foo(T ignored) + throws E; + } + + static T test(final A a, final T ignored) + throws E { + return a.foo(ignored); + } +} + +final class LambdaMainTest { + public void main(A a) { + println(test(a)); + } + + + public void println(boolean x) {} + + public void println(String x) {} + + + + interface A { + T foo(T ignored) ; + } + + static T test (final A a) { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index f28448631e88..edae6cf1ee93 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -120,6 +120,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testTargetTypeByOverloadedMethod2() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); }