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:
parent
6ab21308de
commit
870b0834fe
@ -117,7 +117,7 @@ public class Resolve {
|
|||||||
varNotFound = new SymbolNotFoundError(ABSENT_VAR);
|
varNotFound = new SymbolNotFoundError(ABSENT_VAR);
|
||||||
methodNotFound = new SymbolNotFoundError(ABSENT_MTH);
|
methodNotFound = new SymbolNotFoundError(ABSENT_MTH);
|
||||||
typeNotFound = new SymbolNotFoundError(ABSENT_TYP);
|
typeNotFound = new SymbolNotFoundError(ABSENT_TYP);
|
||||||
referenceNotFound = new ReferenceLookupResult(methodNotFound, null);
|
referenceNotFound = ReferenceLookupResult.error(methodNotFound);
|
||||||
|
|
||||||
names = Names.instance(context);
|
names = Names.instance(context);
|
||||||
log = Log.instance(context);
|
log = Log.instance(context);
|
||||||
@ -2968,10 +2968,10 @@ public class Resolve {
|
|||||||
|
|
||||||
//merge results
|
//merge results
|
||||||
Pair<Symbol, ReferenceLookupHelper> res;
|
Pair<Symbol, ReferenceLookupHelper> res;
|
||||||
Symbol bestSym = referenceChooser.result(boundRes, unboundRes);
|
ReferenceLookupResult bestRes = referenceChooser.result(boundRes, unboundRes);
|
||||||
res = new Pair<>(bestSym,
|
res = new Pair<>(bestRes.sym,
|
||||||
bestSym == unboundSym ? unboundLookupHelper : boundLookupHelper);
|
bestRes == unboundRes ? unboundLookupHelper : boundLookupHelper);
|
||||||
env.info.pendingResolutionPhase = bestSym == unboundSym ?
|
env.info.pendingResolutionPhase = bestRes == unboundRes ?
|
||||||
unboundEnv.info.pendingResolutionPhase :
|
unboundEnv.info.pendingResolutionPhase :
|
||||||
boundEnv.info.pendingResolutionPhase;
|
boundEnv.info.pendingResolutionPhase;
|
||||||
|
|
||||||
@ -3027,11 +3027,15 @@ public class Resolve {
|
|||||||
Symbol sym;
|
Symbol sym;
|
||||||
|
|
||||||
ReferenceLookupResult(Symbol sym, MethodResolutionContext resolutionContext) {
|
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;
|
this.sym = sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
private StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
|
private static StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case MTH:
|
case MTH:
|
||||||
case AMBIGUOUS:
|
case AMBIGUOUS:
|
||||||
@ -3080,6 +3084,10 @@ public class Resolve {
|
|||||||
return false;
|
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
|
* Generate a result from a pair of lookup result objects. This method delegates to the
|
||||||
* appropriate result generation routine.
|
* appropriate result generation routine.
|
||||||
*/
|
*/
|
||||||
Symbol result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
ReferenceLookupResult result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||||
return unboundRes != referenceNotFound ?
|
return unboundRes != referenceNotFound ?
|
||||||
unboundResult(boundRes, unboundRes) :
|
unboundResult(boundRes, unboundRes) :
|
||||||
boundResult(boundRes);
|
boundResult(boundRes);
|
||||||
@ -3101,12 +3109,12 @@ public class Resolve {
|
|||||||
/**
|
/**
|
||||||
* Generate a symbol from a given bound lookup result.
|
* 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.
|
* 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() {
|
ReferenceChooser basicReferenceChooser = new ReferenceChooser() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Symbol boundResult(ReferenceLookupResult boundRes) {
|
ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
|
||||||
return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ?
|
return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ?
|
||||||
boundRes.sym : //the search produces a non-static method
|
boundRes : //the search produces a non-static method
|
||||||
new BadMethodReferenceError(boundRes.sym, false);
|
ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||||
if (boundRes.hasKind(StaticKind.STATIC) &&
|
if (boundRes.hasKind(StaticKind.STATIC) &&
|
||||||
(!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
|
(!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
|
||||||
//the first search produces a static method and no non-static method is applicable
|
//the first search produces a static method and no non-static method is applicable
|
||||||
//during the second search
|
//during the second search
|
||||||
return boundRes.sym;
|
return boundRes;
|
||||||
} else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
|
} else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
|
||||||
(!boundRes.isSuccess() || boundRes.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
|
//the second search produces a non-static method and no static method is applicable
|
||||||
//during the first search
|
//during the first search
|
||||||
return unboundRes.sym;
|
return unboundRes;
|
||||||
} else if (boundRes.isSuccess() && unboundRes.isSuccess()) {
|
} else if (boundRes.isSuccess() && unboundRes.isSuccess()) {
|
||||||
//both searches produce some result; ambiguity (error recovery)
|
//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()) {
|
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
|
||||||
//Both searches failed to produce a result with correct staticness (i.e. first search
|
//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
|
//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
|
//with the right staticness, but the other search has applicable methods with wrong
|
||||||
//staticness (error recovery)
|
//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 {
|
} else {
|
||||||
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
|
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
|
||||||
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
|
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
|
||||||
unboundRes.sym : boundRes.sym;
|
unboundRes : boundRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3158,28 +3167,29 @@ public class Resolve {
|
|||||||
ReferenceChooser structuralReferenceChooser = new ReferenceChooser() {
|
ReferenceChooser structuralReferenceChooser = new ReferenceChooser() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Symbol boundResult(ReferenceLookupResult boundRes) {
|
ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
|
||||||
return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ?
|
return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ?
|
||||||
boundRes.sym : //the search has at least one applicable non-static method
|
boundRes : //the search has at least one applicable non-static method
|
||||||
new BadMethodReferenceError(boundRes.sym, false);
|
ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
|
||||||
if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) {
|
if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) {
|
||||||
//the first serach has at least one applicable static method
|
//the first serach has at least one applicable static method
|
||||||
return boundRes.sym;
|
return boundRes;
|
||||||
} else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) {
|
} else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) {
|
||||||
//the second search has at least one applicable non-static method
|
//the second search has at least one applicable non-static method
|
||||||
return unboundRes.sym;
|
return unboundRes;
|
||||||
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
|
} else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
|
||||||
//either the first search produces a non-static method, or second search produces
|
//either the first search produces a non-static method, or second search produces
|
||||||
//a non-static method (error recovery)
|
//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 {
|
} else {
|
||||||
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
|
//both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
|
||||||
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
|
return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
|
||||||
unboundRes.sym : boundRes.sym;
|
unboundRes : boundRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
41
test/langtools/tools/javac/lambda/8188144/T8188144.java
Normal file
41
test/langtools/tools/javac/lambda/8188144/T8188144.java
Normal 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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user