From a684c033a1f6ed8430320cb445fcb64cf36a69bc Mon Sep 17 00:00:00 2001 From: anna Date: Mon, 25 Feb 2013 13:40:41 +0100 Subject: [PATCH] lambda: replace raw inference from lambda with Object when it doesn't matter (IDEA-101788) --- .../source/resolve/PsiResolveHelperImpl.java | 49 +++++++++++++++++-- .../highlighting/AcceptRawSubstForLambda.java | 30 ++++++++++++ .../daemon/lambda/LambdaHighlightingTest.java | 4 ++ 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AcceptRawSubstForLambda.java 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 5af0d2dae5b3..5c5aa513970b 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 @@ -205,6 +205,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { sortLambdaExpressionsLast(paramTypes, argTypes); boolean rawType = false; boolean nullPassed = false; + boolean lambdaRaw = false; for (int j = 0; j < argTypes.length; j++) { PsiType argumentType = argTypes[j]; if (argumentType == null) continue; @@ -228,6 +229,12 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { if (currentSubstitution == FAILED_INFERENCE || (currentSubstitution == null && lowerBound == PsiType.NULL)) return RAW_INFERENCE; } if (nullPassed && currentSubstitution == null) return RAW_INFERENCE; + if (currentSubstitution != null && currentSubstitution.first == null) { + lambdaRaw = true; + } + if (currentSubstitution == null && lambdaRaw) { + return new Pair(PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope()), ConstraintType.EQUALS); + } } else if (argumentType instanceof PsiMethodReferenceType) { final PsiMethodReferenceExpression referenceExpression = ((PsiMethodReferenceType)argumentType).getExpression(); currentSubstitution = inferConstraintFromFunctionalInterfaceMethod(typeParameter, referenceExpression, partialSubstitutor.substitute(parameterType), partialSubstitutor, policy); @@ -998,7 +1005,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return null; } - private static Pair inferMethodTypeParameterFromParent(PsiElement parent, + private static Pair inferMethodTypeParameterFromParent(final PsiElement parent, PsiExpression methodCall, final PsiTypeParameter typeParameter, PsiSubstitutor substitutor, @@ -1065,16 +1072,24 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { } } } else if (parent instanceof PsiLambdaExpression) { - expectedType = LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType()); + expectedType = ourGraphGuard.doPreventingRecursion(methodCall, true, new Computable() { + @Override + public PsiType compute() { + return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType()); + } + }); if (expectedType == null) { - return getFailedInferenceConstraint(typeParameter); + return null; } } else if (parent instanceof PsiTypeCastExpression) { expectedType = ((PsiTypeCastExpression)parent).getType(); } else if (parent instanceof PsiConditionalExpression) { if (PsiUtil.isLanguageLevel8OrHigher(parent)) { try { - return inferMethodTypeParameterFromParent(PsiUtil.skipParenthesizedExprUp(parent.getParent()), (PsiExpression)parent, typeParameter, substitutor, policy); + final Pair pair = inferFromConditionalExpression(parent, methodCall, typeParameter, substitutor, policy); + if (pair != null) { + return pair; + } } finally { GraphInferencePolicy.forget(parent); @@ -1175,6 +1190,32 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { return result; } + private static Pair inferFromConditionalExpression(PsiElement parent, + PsiExpression methodCall, + PsiTypeParameter typeParameter, + PsiSubstitutor substitutor, + ParameterTypeInferencePolicy policy) { + Pair pair = + inferMethodTypeParameterFromParent(PsiUtil.skipParenthesizedExprUp(parent.getParent()), (PsiExpression)parent, typeParameter, substitutor, policy); + if (pair == null) { + final PsiExpression thenExpression = ((PsiConditionalExpression)parent).getThenExpression(); + final PsiExpression elseExpression = ((PsiConditionalExpression)parent).getElseExpression(); + final PsiType[] paramTypes = {((PsiMethod)typeParameter.getOwner()).getReturnType()}; + if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(elseExpression)) && thenExpression != null) { + final PsiType thenType = thenExpression.getType(); + if (thenType != null) { + pair = inferTypeForMethodTypeParameterInner(typeParameter, paramTypes, new PsiType[] {thenType}, substitutor, null, policy); + } + } else if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(thenExpression)) && elseExpression != null) { + final PsiType elseType = elseExpression.getType(); + if (elseType != null) { + pair = inferTypeForMethodTypeParameterInner(typeParameter, paramTypes, new PsiType[] {elseType}, substitutor, null, policy); + } + } + } + return pair; + } + private static final ProcessCandidateParameterTypeInferencePolicy GRAPH_INFERENCE_POLICY = new GraphInferencePolicy(); private static Pair graphInferenceFromCallContext(@NotNull final PsiExpression methodCall, diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AcceptRawSubstForLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AcceptRawSubstForLambda.java new file mode 100644 index 000000000000..9f7573f82c4a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AcceptRawSubstForLambda.java @@ -0,0 +1,30 @@ +public class CyclicReferenceTest { + void test(Match match) { + Match matcher = match.or(s -> Optional.empty(), i -> 2); + Match matcher1 = match.or(s -> s.startsWith("_") ? Optional.of(1) : Optional.empty(), i -> 2); + } +} + +class Match { + public Match or(Extractor e, Function c) { + return this; + } +} + +interface Extractor { + Optional unapply(T t); +} + +interface Function { + public V apply(W t); +} + +class Optional { + public static Optional empty() { + return null; + } + + public static Optional of(T value) { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java index fb83818521de..53fa466743e8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java @@ -216,6 +216,10 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testAcceptRawSubstForLambda() throws Exception { + doTest(); + } + public void testCheckFunctionalInterfaceAccess() throws Exception { doTest(); }