new inference: nothing should be cached during overload resolution (IDEA-136759)
authorAnna Kozlova <anna.kozlova@jetbrains.com>
Tue, 24 Feb 2015 18:00:41 +0000 (19:00 +0100)
committerAnna Kozlova <anna.kozlova@jetbrains.com>
Tue, 24 Feb 2015 18:18:57 +0000 (19:18 +0100)
java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java
java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java
java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java
java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA136759.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/CachedSubstitutionDuringOverloadResolution.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java
java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/TypeInference18Test.java

index 276fd77f0e3f9d8b62015a41e167a32ee0f4b7f5..8a63eabe16e2780bcbdb3cb8a4b69e5b4d7e3a57 100644 (file)
@@ -116,48 +116,36 @@ public class MethodCandidateInfo extends CandidateInfo{
       return getApplicabilityLevel();
     }
     @ApplicabilityLevelConstant int level;
-    Integer boxedLevel = ourOverloadGuard.doPreventingRecursion(myArgumentList, false, new Computable<Integer>() {
-      @Override
-      public Integer compute() {
-        if (PsiUtil.isLanguageLevel8OrHigher(myArgumentList)) {
-          PsiSubstitutor substitutor = getSubstitutor(false);
-          Map<PsiElement, CurrentCandidateProperties> map = CURRENT_CANDIDATE.get();
-          if (map == null) {
-            map = ContainerUtil.createConcurrentWeakMap();
-            CURRENT_CANDIDATE.set(map);
-          }
-          final PsiMethod method = getElement();
-          final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true);
-          final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties);
-          try {
-            PsiType[] argumentTypes = getArgumentTypes();
-            if (argumentTypes == null) {
-              return ApplicabilityLevel.NOT_APPLICABLE;
-            }
-
-            final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
-            if (!isVarargs() && applicabilityLevel < ApplicabilityLevel.FIXED_ARITY) {
-              return ApplicabilityLevel.NOT_APPLICABLE;
-            }
-            return applicabilityLevel;
-          }
-          finally {
-            if (alreadyThere == null) {
-              map.remove(getMarkerList());
-            } else {
-              map.put(getMarkerList(), alreadyThere);
-            }
-          }
-        }
-        return getApplicabilityLevelInner();
+    PsiSubstitutor substitutor = getSubstitutor(false);
+    Map<PsiElement, CurrentCandidateProperties> map = CURRENT_CANDIDATE.get();
+    if (map == null) {
+      map = ContainerUtil.createConcurrentWeakMap();
+      CURRENT_CANDIDATE.set(map);
+    }
+    final PsiMethod method = getElement();
+    final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true);
+    final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties);
+    try {
+      PsiType[] argumentTypes = getArgumentTypes();
+      if (argumentTypes == null) {
+        return ApplicabilityLevel.NOT_APPLICABLE;
       }
 
-    });
-    if (boxedLevel == null) {
-      return getApplicabilityLevel();
+      level = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
+      if (!isVarargs() && level < ApplicabilityLevel.FIXED_ARITY) {
+        return ApplicabilityLevel.NOT_APPLICABLE;
+      }
+    }
+    finally {
+      if (alreadyThere == null) {
+        map.remove(getMarkerList());
+      } else {
+        map.put(getMarkerList(), alreadyThere);
+      }
+    }
+    if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable(false)) {
+      level = ApplicabilityLevel.NOT_APPLICABLE;
     }
-    level = boxedLevel;
-    if (level > ApplicabilityLevel.NOT_APPLICABLE && !isTypeArgumentsApplicable(false)) level = ApplicabilityLevel.NOT_APPLICABLE;
     return level;
   }
 
index 8ed59d42b629f1e0137a1df979c4cce1c3939fec..389c9d3c23ee773c30eb6843ba63b12b09e0b677 100644 (file)
@@ -396,8 +396,17 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
             return parent instanceof PsiNewExpression ? ((PsiNewExpression)parent).getArgumentList() : super.getMarkerList();
           }
         };
-      if (!varargs && staticFactoryMethod.isVarArgs() && staticFactoryCandidateInfo.getPertinentApplicabilityLevel() < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
-        return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true);
+      if (!varargs && staticFactoryMethod.isVarArgs()) {
+        final Computable<Integer> computable = new Computable<Integer>() {
+          @Override
+          public Integer compute() {
+            return staticFactoryCandidateInfo.getPertinentApplicabilityLevel();
+          }
+        };
+        final Integer applicability = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(expression, true, computable);
+        if ((applicability != null ? applicability : staticFactoryCandidateInfo.getApplicabilityLevel()) < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
+          return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true);
+        }
       }
       return staticFactoryCandidateInfo.getSubstitutor();
     }
index 380f86ed9f2ec7d79e352023ff0547eba4c57f87..8acbda0128946568c5ea9fb70416a2b8d1e964ba 100644 (file)
@@ -16,6 +16,7 @@
 package com.intellij.psi.impl.source.tree.java;
 
 import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Computable;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
 import com.intellij.psi.impl.source.resolve.ResolveCache;
@@ -212,7 +213,7 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
 
     @Nullable
     @Override
-    public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts) {
+    protected CandidateInfo guardedOverloadResolution(@NotNull List<CandidateInfo> conflicts) {
       if (mySignature == null) return null;
 
       if (conflicts.size() > 1) checkSameSignatures(conflicts);
index 678011e4048d964d8110c3241df1a87ff5133652..ce4e29a6781e82a6b5195c9b38f217f1ff80f06b 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.progress.ProgressManager;
 import com.intellij.openapi.projectRoots.JavaSdkVersion;
 import com.intellij.openapi.projectRoots.JavaVersionService;
 import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Computable;
 import com.intellij.pom.java.LanguageLevel;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.PsiSuperMethodImplUtil;
@@ -68,7 +69,17 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
   }
 
   @Override
-  public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts){
+  public final CandidateInfo resolveConflict(@NotNull final List<CandidateInfo> conflicts){
+    return MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(myArgumentsList, true, new Computable<CandidateInfo>() {
+      @Override
+      public CandidateInfo compute() {
+        return guardedOverloadResolution(conflicts);
+      }
+    });
+  }
+
+  @Nullable
+  protected CandidateInfo guardedOverloadResolution(@NotNull List<CandidateInfo> conflicts) {
     if (conflicts.isEmpty()) return null;
     if (conflicts.size() == 1) return conflicts.get(0);
 
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA136759.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA136759.java
new file mode 100644 (file)
index 0000000..50348e4
--- /dev/null
@@ -0,0 +1,19 @@
+
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+class Test {
+
+  public Long getKey() {
+    return 0L;
+  }
+
+  public static void main(Stream<Test> stream) {
+    stream.map(s -> Inner.of(Test::getKey, s));
+  }
+
+  public static final class Inner<K> {
+    public static <T> Inner<T> of(final Object key, final Test   value) {return null;}
+    public static <T> Inner<T> of(final Function< T, Long> keyMapper, final Test value) {return null;}
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/CachedSubstitutionDuringOverloadResolution.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/resolve/CachedSubstitutionDuringOverloadResolution.java
new file mode 100644 (file)
index 0000000..8c020ce
--- /dev/null
@@ -0,0 +1,19 @@
+
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+class Test {
+
+  public Long getKey() {
+    return 0L;
+  }
+
+  public static void main(Stream<Test> stream) {
+    stream.map(s -> Inner.of(Test::get<ref>Key, s));
+  }
+
+  public static final class Inner<K> {
+    public static <T> Inner<T> of(final Object key, final Test   value) {return null;}
+    public static <T> Inner<T> of(final Function< T, Long> keyMapper, final Test value) {return null;}
+  }
+}
\ No newline at end of file
index f0636eb92e5708d31b6ea76d205e9a610e08f8fa..b43b210229468039d77c9db9cffbb3924e02b96f 100644 (file)
@@ -17,14 +17,13 @@ package com.intellij.codeInsight.daemon.lambda;
 
 import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
 import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
-import com.intellij.idea.Bombed;
 import com.intellij.openapi.projectRoots.JavaSdkVersion;
 import com.intellij.openapi.projectRoots.Sdk;
 import com.intellij.testFramework.IdeaTestUtil;
+import junit.framework.Test;
+import junit.framework.TestSuite;
 import org.jetbrains.annotations.NonNls;
 
-import java.util.Calendar;
-
 public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
   @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/newLambda";
 
@@ -178,6 +177,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
     doTest();
   }
 
+  public void testIDEA136759() throws Exception {
+    doTest();
+  }
+
   private void doTest() {
     doTest(false);
   }
@@ -194,7 +197,7 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
 /*
   public static Test suite() {
     final TestSuite suite = new TestSuite();
-    for (int i = 0; i < 100; i++) {
+    for (int i = 0; i < 1000; i++) {
       suite.addTestSuite(NewLambdaHighlightingTest.class);
     }
     return suite;
index 5d8cd07c3270a70f1c9a9de8bea3ca1d587e4175..04b261cedec8bfd030596783f4fc39225697b76a 100644 (file)
@@ -32,11 +32,15 @@ public class TypeInference18Test extends ResolveTestCase {
   }
 
   public void testSecondConflictResolution() throws Exception {
+    doTestMethodCall();
+  }
+
+  public void testCachedSubstitutionDuringOverloadResolution() throws Exception {
     PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java");
     assertNotNull(ref);
-    PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodCallExpression.class);
+    PsiMethodReferenceExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodReferenceExpression.class, false);
     assertNotNull(methodCallExpression);
-    assertNotNull(methodCallExpression.resolveMethod());
+    assertNotNull(methodCallExpression.resolve());
   }
 
   private LanguageLevel myOldLanguageLevel;
@@ -55,6 +59,14 @@ public class TypeInference18Test extends ResolveTestCase {
     super.tearDown();
   }
 
+  private void doTestMethodCall() throws Exception {
+    PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java");
+    assertNotNull(ref);
+    PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethodCallExpression.class);
+    assertNotNull(methodCallExpression);
+    assertNotNull(methodCallExpression.resolveMethod());
+  }
+
   private void doTest() throws Exception {
     PsiReference ref = configureByFile("/codeInsight/daemonCodeAnalyzer/lambda/resolve/" + getTestName(false) + ".java");
     assertNotNull(ref);