8188144: regression in method reference type-checking

Method reference checking prefers unbound lookup when both searches produce same results

Reviewed-by: vromero
This commit is contained in:
Maurizio Cimadamore 2017-10-02 12:29:44 +01:00
parent 6ab21308de
commit 870b0834fe
2 changed files with 78 additions and 27 deletions

View File

@ -117,7 +117,7 @@ public class Resolve {
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 @@ public class Resolve {
//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 @@ public class Resolve {
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 @@ public class Resolve {
return false;
}
}
static ReferenceLookupResult error(Symbol sym) {
return new ReferenceLookupResult(sym, StaticKind.UNDEFINED);
}
}
/**
@ -3092,7 +3100,7 @@ public class Resolve {
* 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 @@ public class Resolve {
/**
* 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 @@ public class Resolve {
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 @@ public class Resolve {
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;
}
}
};

View File

@ -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!");
}
}
}