8005179: Cleanup Resolve.AmbiguityError
Linearize nested ambiguity errors Reviewed-by: jjg
This commit is contained in:
parent
159b251085
commit
c932023b04
@ -1122,52 +1122,20 @@ public class Resolve {
|
||||
if (m1Abstract && !m2Abstract) return m2;
|
||||
if (m2Abstract && !m1Abstract) return m1;
|
||||
// both abstract or both concrete
|
||||
if (!m1Abstract && !m2Abstract)
|
||||
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;
|
||||
return ambiguityError(m1, m2);
|
||||
}
|
||||
if (m1SignatureMoreSpecific) return m1;
|
||||
if (m2SignatureMoreSpecific) return m2;
|
||||
return ambiguityError(m1, m2);
|
||||
case AMBIGUOUS:
|
||||
//check if m1 is more specific than all ambiguous methods in m2
|
||||
AmbiguityError e = (AmbiguityError)m2;
|
||||
Symbol err1 = mostSpecific(argtypes, m1, e.sym, env, site, allowBoxing, useVarargs);
|
||||
Symbol err2 = mostSpecific(argtypes, m1, e.sym2, env, site, allowBoxing, useVarargs);
|
||||
if (err1 == err2) return err1;
|
||||
if (err1 == e.sym && err2 == e.sym2) return m2;
|
||||
if (err1 instanceof AmbiguityError &&
|
||||
err2 instanceof AmbiguityError &&
|
||||
((AmbiguityError)err1).sym == ((AmbiguityError)err2).sym)
|
||||
return ambiguityError(m1, m2);
|
||||
else
|
||||
return ambiguityError(err1, err2);
|
||||
for (Symbol s : e.ambiguousSyms) {
|
||||
if (mostSpecific(argtypes, m1, s, env, site, allowBoxing, useVarargs) != m1) {
|
||||
return e.addAmbiguousSymbol(m1);
|
||||
}
|
||||
}
|
||||
return m1;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
@ -2504,6 +2472,10 @@ public class Resolve {
|
||||
|
||||
@Override
|
||||
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 nothing is found return the 'first' error
|
||||
sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes);
|
||||
@ -2559,6 +2531,10 @@ public class Resolve {
|
||||
abstract JCMemberReference.ReferenceKind referenceKind(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
|
||||
return sym;
|
||||
}
|
||||
@ -2994,9 +2970,7 @@ public class Resolve {
|
||||
|
||||
@Override
|
||||
public Symbol access(Name name, TypeSymbol location) {
|
||||
if (sym.kind >= AMBIGUOUS)
|
||||
return ((ResolveError)sym).access(name, location);
|
||||
else if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0)
|
||||
if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0)
|
||||
return types.createErrorType(name, location, sym.type).tsym;
|
||||
else
|
||||
return sym;
|
||||
@ -3318,14 +3292,32 @@ public class Resolve {
|
||||
* (either methods, constructors or operands) are ambiguous
|
||||
* given an actual arguments/type argument list.
|
||||
*/
|
||||
class AmbiguityError extends InvalidSymbolError {
|
||||
class AmbiguityError extends ResolveError {
|
||||
|
||||
/** The other maximally specific symbol */
|
||||
Symbol sym2;
|
||||
List<Symbol> ambiguousSyms = List.nil();
|
||||
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return true;
|
||||
}
|
||||
|
||||
AmbiguityError(Symbol sym1, Symbol sym2) {
|
||||
super(AMBIGUOUS, sym1, "ambiguity error");
|
||||
this.sym2 = sym2;
|
||||
super(AMBIGUOUS, "ambiguity error");
|
||||
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
|
||||
@ -3336,24 +3328,60 @@ public class Resolve {
|
||||
Name name,
|
||||
List<Type> argtypes,
|
||||
List<Type> typeargtypes) {
|
||||
AmbiguityError pair = this;
|
||||
while (true) {
|
||||
if (pair.sym.kind == AMBIGUOUS)
|
||||
pair = (AmbiguityError)pair.sym;
|
||||
else if (pair.sym2.kind == AMBIGUOUS)
|
||||
pair = (AmbiguityError)pair.sym2;
|
||||
else break;
|
||||
}
|
||||
Name sname = pair.sym.name;
|
||||
if (sname == names.init) sname = pair.sym.owner.name;
|
||||
List<Symbol> diagSyms = ambiguousSyms.reverse();
|
||||
Symbol s1 = diagSyms.head;
|
||||
Symbol s2 = diagSyms.tail.head;
|
||||
Name sname = s1.name;
|
||||
if (sname == names.init) sname = s1.owner.name;
|
||||
return diags.create(dkind, log.currentSource(),
|
||||
pos, "ref.ambiguous", sname,
|
||||
kindName(pair.sym),
|
||||
pair.sym,
|
||||
pair.sym.location(site, types),
|
||||
kindName(pair.sym2),
|
||||
pair.sym2,
|
||||
pair.sym2.location(site, types));
|
||||
kindName(s1),
|
||||
s1,
|
||||
s1.location(site, types),
|
||||
kindName(s2),
|
||||
s2,
|
||||
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) { }
|
||||
|
||||
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 -> { return (Object) null; }); //error - call(SAM3) is not applicable because of cyclic inference
|
||||
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: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
|
||||
|
Loading…
Reference in New Issue
Block a user