8188144: regression in method reference type-checking
authormcimadamore
Mon, 02 Oct 2017 12:29:44 +0100
changeset 47297 a0116bcc65b7
parent 47296 f83c45751d58
child 47298 2e947e1bd907
8188144: regression in method reference type-checking Summary: method reference checking prefers unbound lookup when both searches produce same results Reviewed-by: vromero
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java
test/langtools/tools/javac/lambda/8188144/T8188144.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Sep 27 21:48:21 2017 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Oct 02 12:29:44 2017 +0100
@@ -117,7 +117,7 @@
         varNotFound = new SymbolNotFoundError(ABSENT_VAR);
         methodNotFound = new SymbolNotFoundError(ABSENT_MTH);
         typeNotFound = new SymbolNotFoundError(ABSENT_TYP);
-        referenceNotFound = new ReferenceLookupResult(methodNotFound, null);
+        referenceNotFound = ReferenceLookupResult.error(methodNotFound);
 
         names = Names.instance(context);
         log = Log.instance(context);
@@ -2968,10 +2968,10 @@
 
         //merge results
         Pair<Symbol, ReferenceLookupHelper> res;
-        Symbol bestSym = referenceChooser.result(boundRes, unboundRes);
-        res = new Pair<>(bestSym,
-                bestSym == unboundSym ? unboundLookupHelper : boundLookupHelper);
-        env.info.pendingResolutionPhase = bestSym == unboundSym ?
+        ReferenceLookupResult bestRes = referenceChooser.result(boundRes, unboundRes);
+        res = new Pair<>(bestRes.sym,
+                bestRes == unboundRes ? unboundLookupHelper : boundLookupHelper);
+        env.info.pendingResolutionPhase = bestRes == unboundRes ?
                 unboundEnv.info.pendingResolutionPhase :
                 boundEnv.info.pendingResolutionPhase;
 
@@ -3027,11 +3027,15 @@
         Symbol sym;
 
         ReferenceLookupResult(Symbol sym, MethodResolutionContext resolutionContext) {
-            this.staticKind = staticKind(sym, resolutionContext);
+            this(sym, staticKind(sym, resolutionContext));
+        }
+
+        private ReferenceLookupResult(Symbol sym, StaticKind staticKind) {
+            this.staticKind = staticKind;
             this.sym = sym;
         }
 
-        private StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
+        private static StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
             switch (sym.kind) {
                 case MTH:
                 case AMBIGUOUS:
@@ -3080,6 +3084,10 @@
                     return false;
             }
         }
+
+        static ReferenceLookupResult error(Symbol sym) {
+            return new ReferenceLookupResult(sym, StaticKind.UNDEFINED);
+        }
     }
 
     /**
@@ -3092,7 +3100,7 @@
          * Generate a result from a pair of lookup result objects. This method delegates to the
          * appropriate result generation routine.
          */
-        Symbol result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+        ReferenceLookupResult result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
             return unboundRes != referenceNotFound ?
                     unboundResult(boundRes, unboundRes) :
                     boundResult(boundRes);
@@ -3101,12 +3109,12 @@
         /**
          * Generate a symbol from a given bound lookup result.
          */
-        abstract Symbol boundResult(ReferenceLookupResult boundRes);
+        abstract ReferenceLookupResult boundResult(ReferenceLookupResult boundRes);
 
         /**
          * Generate a symbol from a pair of bound/unbound lookup results.
          */
-        abstract Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
+        abstract ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
     }
 
     /**
@@ -3116,37 +3124,38 @@
     ReferenceChooser basicReferenceChooser = new ReferenceChooser() {
 
         @Override
-        Symbol boundResult(ReferenceLookupResult boundRes) {
+        ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
             return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ?
-                    boundRes.sym : //the search produces a non-static method
-                    new BadMethodReferenceError(boundRes.sym, false);
+                    boundRes : //the search produces a non-static method
+                    ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
         }
 
         @Override
-        Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+        ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
             if (boundRes.hasKind(StaticKind.STATIC) &&
                     (!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
                 //the first search produces a static method and no non-static method is applicable
                 //during the second search
-                return boundRes.sym;
+                return boundRes;
             } else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
                     (!boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC))) {
                 //the second search produces a non-static method and no static method is applicable
                 //during the first search
-                return unboundRes.sym;
+                return unboundRes;
             } else if (boundRes.isSuccess() && unboundRes.isSuccess()) {
                 //both searches produce some result; ambiguity (error recovery)
-                return ambiguityError(boundRes.sym, unboundRes.sym);
+                return ReferenceLookupResult.error(ambiguityError(boundRes.sym, unboundRes.sym));
             } else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
                 //Both searches failed to produce a result with correct staticness (i.e. first search
                 //produces an non-static method). Alternatively, a given search produced a result
                 //with the right staticness, but the other search has applicable methods with wrong
                 //staticness (error recovery)
-                return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
+                return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
+                        boundRes.sym : unboundRes.sym, true));
             } else {
                 //both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
                 return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
-                        unboundRes.sym : boundRes.sym;
+                        unboundRes : boundRes;
             }
         }
     };
@@ -3158,28 +3167,29 @@
     ReferenceChooser structuralReferenceChooser = new ReferenceChooser() {
 
         @Override
-        Symbol boundResult(ReferenceLookupResult boundRes) {
+        ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
             return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ?
-                    boundRes.sym : //the search has at least one applicable non-static method
-                    new BadMethodReferenceError(boundRes.sym, false);
+                    boundRes : //the search has at least one applicable non-static method
+                    ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
         }
 
         @Override
-        Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+        ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
             if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) {
                 //the first serach has at least one applicable static method
-                return boundRes.sym;
+                return boundRes;
             } else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) {
                 //the second search has at least one applicable non-static method
-                return unboundRes.sym;
+                return unboundRes;
             } else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
                 //either the first search produces a non-static method, or second search produces
                 //a non-static method (error recovery)
-                return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
+                return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
+                        boundRes.sym : unboundRes.sym, true));
             } else {
                 //both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
                 return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
-                        unboundRes.sym : boundRes.sym;
+                        unboundRes : boundRes;
             }
         }
     };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lambda/8188144/T8188144.java	Mon Oct 02 12:29:44 2017 +0100
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8188144
+ * @summary regression in method reference type-checking
+ */
+
+import java.util.function.BiFunction;
+
+public class T8188144 {
+    public static void main(String[] args) {
+        BiFunction<String, String, String> format = String::format;
+        if (!format.apply("foo %s", "bar").endsWith("foo bar")) {
+            throw new AssertionError("Unexpected output!");
+        }
+    }
+}