# HG changeset patch # User mcimadamore # Date 1506943784 -3600 # Node ID a0116bcc65b70dcb5824bebc28034cb2cfe607de # Parent f83c45751d581860169fd6d8283d0d90bc1583d3 8188144: regression in method reference type-checking Summary: method reference checking prefers unbound lookup when both searches produce same results Reviewed-by: vromero diff -r f83c45751d58 -r a0116bcc65b7 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.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 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; } } }; diff -r f83c45751d58 -r a0116bcc65b7 test/langtools/tools/javac/lambda/8188144/T8188144.java --- /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 format = String::format; + if (!format.apply("foo %s", "bar").endsWith("foo bar")) { + throw new AssertionError("Unexpected output!"); + } + } +}