mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
8005179: Cleanup Resolve.AmbiguityError
Linearize nested ambiguity errors Reviewed-by: jjg
This commit is contained in:
parent
159b251085
commit
c932023b04
3 changed files with 93 additions and 65 deletions
|
@ -1122,52 +1122,20 @@ public class Resolve {
|
||||||
if (m1Abstract && !m2Abstract) return m2;
|
if (m1Abstract && !m2Abstract) return m2;
|
||||||
if (m2Abstract && !m1Abstract) return m1;
|
if (m2Abstract && !m1Abstract) return m1;
|
||||||
// both abstract or both concrete
|
// both abstract or both concrete
|
||||||
if (!m1Abstract && !m2Abstract)
|
|
||||||
return ambiguityError(m1, m2);
|
return ambiguityError(m1, m2);
|
||||||
// check that both signatures have the same erasure
|
|
||||||
if (!types.isSameTypes(m1.erasure(types).getParameterTypes(),
|
|
||||||
m2.erasure(types).getParameterTypes()))
|
|
||||||
return ambiguityError(m1, m2);
|
|
||||||
// both abstract, neither overridden; merge throws clause and result type
|
|
||||||
Type mst = mostSpecificReturnType(mt1, mt2);
|
|
||||||
if (mst == null) {
|
|
||||||
// Theoretically, this can't happen, but it is possible
|
|
||||||
// due to error recovery or mixing incompatible class files
|
|
||||||
return ambiguityError(m1, m2);
|
|
||||||
}
|
|
||||||
Symbol mostSpecific = mst == mt1 ? m1 : m2;
|
|
||||||
List<Type> allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes());
|
|
||||||
Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown);
|
|
||||||
MethodSymbol result = new MethodSymbol(
|
|
||||||
mostSpecific.flags(),
|
|
||||||
mostSpecific.name,
|
|
||||||
newSig,
|
|
||||||
mostSpecific.owner) {
|
|
||||||
@Override
|
|
||||||
public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) {
|
|
||||||
if (origin == site.tsym)
|
|
||||||
return this;
|
|
||||||
else
|
|
||||||
return super.implementation(origin, types, checkResult);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
if (m1SignatureMoreSpecific) return m1;
|
if (m1SignatureMoreSpecific) return m1;
|
||||||
if (m2SignatureMoreSpecific) return m2;
|
if (m2SignatureMoreSpecific) return m2;
|
||||||
return ambiguityError(m1, m2);
|
return ambiguityError(m1, m2);
|
||||||
case AMBIGUOUS:
|
case AMBIGUOUS:
|
||||||
|
//check if m1 is more specific than all ambiguous methods in m2
|
||||||
AmbiguityError e = (AmbiguityError)m2;
|
AmbiguityError e = (AmbiguityError)m2;
|
||||||
Symbol err1 = mostSpecific(argtypes, m1, e.sym, env, site, allowBoxing, useVarargs);
|
for (Symbol s : e.ambiguousSyms) {
|
||||||
Symbol err2 = mostSpecific(argtypes, m1, e.sym2, env, site, allowBoxing, useVarargs);
|
if (mostSpecific(argtypes, m1, s, env, site, allowBoxing, useVarargs) != m1) {
|
||||||
if (err1 == err2) return err1;
|
return e.addAmbiguousSymbol(m1);
|
||||||
if (err1 == e.sym && err2 == e.sym2) return m2;
|
}
|
||||||
if (err1 instanceof AmbiguityError &&
|
}
|
||||||
err2 instanceof AmbiguityError &&
|
return m1;
|
||||||
((AmbiguityError)err1).sym == ((AmbiguityError)err2).sym)
|
|
||||||
return ambiguityError(m1, m2);
|
|
||||||
else
|
|
||||||
return ambiguityError(err1, err2);
|
|
||||||
default:
|
default:
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
@ -2504,6 +2472,10 @@ public class Resolve {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
|
Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
|
||||||
|
if (sym.kind == AMBIGUOUS) {
|
||||||
|
AmbiguityError a_err = (AmbiguityError)sym;
|
||||||
|
sym = a_err.mergeAbstracts(site);
|
||||||
|
}
|
||||||
if (sym.kind >= AMBIGUOUS) {
|
if (sym.kind >= AMBIGUOUS) {
|
||||||
//if nothing is found return the 'first' error
|
//if nothing is found return the 'first' error
|
||||||
sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes);
|
sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes);
|
||||||
|
@ -2559,6 +2531,10 @@ public class Resolve {
|
||||||
abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym);
|
abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym);
|
||||||
|
|
||||||
Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
|
Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
|
||||||
|
if (sym.kind == AMBIGUOUS) {
|
||||||
|
AmbiguityError a_err = (AmbiguityError)sym;
|
||||||
|
sym = a_err.mergeAbstracts(site);
|
||||||
|
}
|
||||||
//skip error reporting
|
//skip error reporting
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
@ -2994,9 +2970,7 @@ public class Resolve {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol access(Name name, TypeSymbol location) {
|
public Symbol access(Name name, TypeSymbol location) {
|
||||||
if (sym.kind >= AMBIGUOUS)
|
if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0)
|
||||||
return ((ResolveError)sym).access(name, location);
|
|
||||||
else if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0)
|
|
||||||
return types.createErrorType(name, location, sym.type).tsym;
|
return types.createErrorType(name, location, sym.type).tsym;
|
||||||
else
|
else
|
||||||
return sym;
|
return sym;
|
||||||
|
@ -3318,14 +3292,32 @@ public class Resolve {
|
||||||
* (either methods, constructors or operands) are ambiguous
|
* (either methods, constructors or operands) are ambiguous
|
||||||
* given an actual arguments/type argument list.
|
* given an actual arguments/type argument list.
|
||||||
*/
|
*/
|
||||||
class AmbiguityError extends InvalidSymbolError {
|
class AmbiguityError extends ResolveError {
|
||||||
|
|
||||||
/** The other maximally specific symbol */
|
/** The other maximally specific symbol */
|
||||||
Symbol sym2;
|
List<Symbol> ambiguousSyms = List.nil();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
AmbiguityError(Symbol sym1, Symbol sym2) {
|
AmbiguityError(Symbol sym1, Symbol sym2) {
|
||||||
super(AMBIGUOUS, sym1, "ambiguity error");
|
super(AMBIGUOUS, "ambiguity error");
|
||||||
this.sym2 = sym2;
|
ambiguousSyms = flatten(sym2).appendList(flatten(sym1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Symbol> flatten(Symbol sym) {
|
||||||
|
if (sym.kind == AMBIGUOUS) {
|
||||||
|
return ((AmbiguityError)sym).ambiguousSyms;
|
||||||
|
} else {
|
||||||
|
return List.of(sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AmbiguityError addAmbiguousSymbol(Symbol s) {
|
||||||
|
ambiguousSyms = ambiguousSyms.prepend(s);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3336,24 +3328,60 @@ public class Resolve {
|
||||||
Name name,
|
Name name,
|
||||||
List<Type> argtypes,
|
List<Type> argtypes,
|
||||||
List<Type> typeargtypes) {
|
List<Type> typeargtypes) {
|
||||||
AmbiguityError pair = this;
|
List<Symbol> diagSyms = ambiguousSyms.reverse();
|
||||||
while (true) {
|
Symbol s1 = diagSyms.head;
|
||||||
if (pair.sym.kind == AMBIGUOUS)
|
Symbol s2 = diagSyms.tail.head;
|
||||||
pair = (AmbiguityError)pair.sym;
|
Name sname = s1.name;
|
||||||
else if (pair.sym2.kind == AMBIGUOUS)
|
if (sname == names.init) sname = s1.owner.name;
|
||||||
pair = (AmbiguityError)pair.sym2;
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
Name sname = pair.sym.name;
|
|
||||||
if (sname == names.init) sname = pair.sym.owner.name;
|
|
||||||
return diags.create(dkind, log.currentSource(),
|
return diags.create(dkind, log.currentSource(),
|
||||||
pos, "ref.ambiguous", sname,
|
pos, "ref.ambiguous", sname,
|
||||||
kindName(pair.sym),
|
kindName(s1),
|
||||||
pair.sym,
|
s1,
|
||||||
pair.sym.location(site, types),
|
s1.location(site, types),
|
||||||
kindName(pair.sym2),
|
kindName(s2),
|
||||||
pair.sym2,
|
s2,
|
||||||
pair.sym2.location(site, types));
|
s2.location(site, types));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If multiple applicable methods are found during overload and none of them
|
||||||
|
* is more specific than the others, attempt to merge their signatures.
|
||||||
|
*/
|
||||||
|
Symbol mergeAbstracts(Type site) {
|
||||||
|
Symbol fst = ambiguousSyms.last();
|
||||||
|
Symbol res = fst;
|
||||||
|
for (Symbol s : ambiguousSyms.reverse()) {
|
||||||
|
Type mt1 = types.memberType(site, res);
|
||||||
|
Type mt2 = types.memberType(site, s);
|
||||||
|
if ((s.flags() & ABSTRACT) == 0 ||
|
||||||
|
!types.overrideEquivalent(mt1, mt2) ||
|
||||||
|
!types.isSameTypes(fst.erasure(types).getParameterTypes(),
|
||||||
|
s.erasure(types).getParameterTypes())) {
|
||||||
|
//ambiguity cannot be resolved
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
Type mst = mostSpecificReturnType(mt1, mt2);
|
||||||
|
if (mst == null) {
|
||||||
|
// Theoretically, this can't happen, but it is possible
|
||||||
|
// due to error recovery or mixing incompatible class files
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
Symbol mostSpecific = mst == mt1 ? res : s;
|
||||||
|
List<Type> allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes());
|
||||||
|
Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown);
|
||||||
|
res = new MethodSymbol(
|
||||||
|
mostSpecific.flags(),
|
||||||
|
mostSpecific.name,
|
||||||
|
newSig,
|
||||||
|
mostSpecific.owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Symbol access(Name name, TypeSymbol location) {
|
||||||
|
return ambiguousSyms.last();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class TargetType21 {
|
||||||
<R,A> void call(SAM3<R,A> sam) { }
|
<R,A> void call(SAM3<R,A> sam) { }
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
call(x -> { throw new Exception(); }); //ok - resolves to call(SAM1)
|
call(x -> { throw new Exception(); }); //ambiguous
|
||||||
call(x -> { System.out.println(""); }); //ok - resolves to call(SAM2)
|
call(x -> { System.out.println(""); }); //ok - resolves to call(SAM2)
|
||||||
call(x -> { return (Object) null; }); //error - call(SAM3) is not applicable because of cyclic inference
|
call(x -> { return (Object) null; }); //error - call(SAM3) is not applicable because of cyclic inference
|
||||||
call(x -> { return null; }); ////ok - resolves to call(SAM1)
|
call(x -> { return null; }); ////ok - resolves to call(SAM1)
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, call(TargetType21.SAM2), TargetType21
|
TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, call(TargetType21.SAM2), TargetType21
|
||||||
TargetType21.java:30:9: compiler.err.cant.apply.symbols: kindname.method, call, @755,{(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.String)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, <R,A>call(TargetType21.SAM3<R,A>), (compiler.misc.cyclic.inference: A))}
|
TargetType21.java:30:9: compiler.err.cant.apply.symbols: kindname.method, call, @737,{(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM1), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.String)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, call(TargetType21.SAM2), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val)))),(compiler.misc.inapplicable.method: kindname.method, TargetType21, <R,A>call(TargetType21.SAM3<R,A>), (compiler.misc.cyclic.inference: A))}
|
||||||
2 errors
|
2 errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue