8188144: regression in method reference type-checking
Summary: method reference checking prefers unbound lookup when both searches produce same results
Reviewed-by: vromero
--- 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!");
+ }
+ }
+}