Tue, 08 Jan 2013 10:16:26 +0100
8005179: Cleanup Resolve.AmbiguityError
Summary: Linearize nested ambiguity errors
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Tue Jan 08 10:15:30 2013 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Tue Jan 08 10:16:26 2013 +0100 1.3 @@ -1122,52 +1122,20 @@ 1.4 if (m1Abstract && !m2Abstract) return m2; 1.5 if (m2Abstract && !m1Abstract) return m1; 1.6 // both abstract or both concrete 1.7 - if (!m1Abstract && !m2Abstract) 1.8 - return ambiguityError(m1, m2); 1.9 - // check that both signatures have the same erasure 1.10 - if (!types.isSameTypes(m1.erasure(types).getParameterTypes(), 1.11 - m2.erasure(types).getParameterTypes())) 1.12 - return ambiguityError(m1, m2); 1.13 - // both abstract, neither overridden; merge throws clause and result type 1.14 - Type mst = mostSpecificReturnType(mt1, mt2); 1.15 - if (mst == null) { 1.16 - // Theoretically, this can't happen, but it is possible 1.17 - // due to error recovery or mixing incompatible class files 1.18 - return ambiguityError(m1, m2); 1.19 - } 1.20 - Symbol mostSpecific = mst == mt1 ? m1 : m2; 1.21 - List<Type> allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes()); 1.22 - Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown); 1.23 - MethodSymbol result = new MethodSymbol( 1.24 - mostSpecific.flags(), 1.25 - mostSpecific.name, 1.26 - newSig, 1.27 - mostSpecific.owner) { 1.28 - @Override 1.29 - public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) { 1.30 - if (origin == site.tsym) 1.31 - return this; 1.32 - else 1.33 - return super.implementation(origin, types, checkResult); 1.34 - } 1.35 - }; 1.36 - return result; 1.37 + return ambiguityError(m1, m2); 1.38 } 1.39 if (m1SignatureMoreSpecific) return m1; 1.40 if (m2SignatureMoreSpecific) return m2; 1.41 return ambiguityError(m1, m2); 1.42 case AMBIGUOUS: 1.43 + //check if m1 is more specific than all ambiguous methods in m2 1.44 AmbiguityError e = (AmbiguityError)m2; 1.45 - Symbol err1 = mostSpecific(argtypes, m1, e.sym, env, site, allowBoxing, useVarargs); 1.46 - Symbol err2 = mostSpecific(argtypes, m1, e.sym2, env, site, allowBoxing, useVarargs); 1.47 - if (err1 == err2) return err1; 1.48 - if (err1 == e.sym && err2 == e.sym2) return m2; 1.49 - if (err1 instanceof AmbiguityError && 1.50 - err2 instanceof AmbiguityError && 1.51 - ((AmbiguityError)err1).sym == ((AmbiguityError)err2).sym) 1.52 - return ambiguityError(m1, m2); 1.53 - else 1.54 - return ambiguityError(err1, err2); 1.55 + for (Symbol s : e.ambiguousSyms) { 1.56 + if (mostSpecific(argtypes, m1, s, env, site, allowBoxing, useVarargs) != m1) { 1.57 + return e.addAmbiguousSymbol(m1); 1.58 + } 1.59 + } 1.60 + return m1; 1.61 default: 1.62 throw new AssertionError(); 1.63 } 1.64 @@ -2504,6 +2472,10 @@ 1.65 1.66 @Override 1.67 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 1.68 + if (sym.kind == AMBIGUOUS) { 1.69 + AmbiguityError a_err = (AmbiguityError)sym; 1.70 + sym = a_err.mergeAbstracts(site); 1.71 + } 1.72 if (sym.kind >= AMBIGUOUS) { 1.73 //if nothing is found return the 'first' error 1.74 sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes); 1.75 @@ -2559,6 +2531,10 @@ 1.76 abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym); 1.77 1.78 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { 1.79 + if (sym.kind == AMBIGUOUS) { 1.80 + AmbiguityError a_err = (AmbiguityError)sym; 1.81 + sym = a_err.mergeAbstracts(site); 1.82 + } 1.83 //skip error reporting 1.84 return sym; 1.85 } 1.86 @@ -2994,9 +2970,7 @@ 1.87 1.88 @Override 1.89 public Symbol access(Name name, TypeSymbol location) { 1.90 - if (sym.kind >= AMBIGUOUS) 1.91 - return ((ResolveError)sym).access(name, location); 1.92 - else if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0) 1.93 + if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0) 1.94 return types.createErrorType(name, location, sym.type).tsym; 1.95 else 1.96 return sym; 1.97 @@ -3318,14 +3292,32 @@ 1.98 * (either methods, constructors or operands) are ambiguous 1.99 * given an actual arguments/type argument list. 1.100 */ 1.101 - class AmbiguityError extends InvalidSymbolError { 1.102 + class AmbiguityError extends ResolveError { 1.103 1.104 /** The other maximally specific symbol */ 1.105 - Symbol sym2; 1.106 + List<Symbol> ambiguousSyms = List.nil(); 1.107 + 1.108 + @Override 1.109 + public boolean exists() { 1.110 + return true; 1.111 + } 1.112 1.113 AmbiguityError(Symbol sym1, Symbol sym2) { 1.114 - super(AMBIGUOUS, sym1, "ambiguity error"); 1.115 - this.sym2 = sym2; 1.116 + super(AMBIGUOUS, "ambiguity error"); 1.117 + ambiguousSyms = flatten(sym2).appendList(flatten(sym1)); 1.118 + } 1.119 + 1.120 + private List<Symbol> flatten(Symbol sym) { 1.121 + if (sym.kind == AMBIGUOUS) { 1.122 + return ((AmbiguityError)sym).ambiguousSyms; 1.123 + } else { 1.124 + return List.of(sym); 1.125 + } 1.126 + } 1.127 + 1.128 + AmbiguityError addAmbiguousSymbol(Symbol s) { 1.129 + ambiguousSyms = ambiguousSyms.prepend(s); 1.130 + return this; 1.131 } 1.132 1.133 @Override 1.134 @@ -3336,24 +3328,60 @@ 1.135 Name name, 1.136 List<Type> argtypes, 1.137 List<Type> typeargtypes) { 1.138 - AmbiguityError pair = this; 1.139 - while (true) { 1.140 - if (pair.sym.kind == AMBIGUOUS) 1.141 - pair = (AmbiguityError)pair.sym; 1.142 - else if (pair.sym2.kind == AMBIGUOUS) 1.143 - pair = (AmbiguityError)pair.sym2; 1.144 - else break; 1.145 - } 1.146 - Name sname = pair.sym.name; 1.147 - if (sname == names.init) sname = pair.sym.owner.name; 1.148 + List<Symbol> diagSyms = ambiguousSyms.reverse(); 1.149 + Symbol s1 = diagSyms.head; 1.150 + Symbol s2 = diagSyms.tail.head; 1.151 + Name sname = s1.name; 1.152 + if (sname == names.init) sname = s1.owner.name; 1.153 return diags.create(dkind, log.currentSource(), 1.154 pos, "ref.ambiguous", sname, 1.155 - kindName(pair.sym), 1.156 - pair.sym, 1.157 - pair.sym.location(site, types), 1.158 - kindName(pair.sym2), 1.159 - pair.sym2, 1.160 - pair.sym2.location(site, types)); 1.161 + kindName(s1), 1.162 + s1, 1.163 + s1.location(site, types), 1.164 + kindName(s2), 1.165 + s2, 1.166 + s2.location(site, types)); 1.167 + } 1.168 + 1.169 + /** 1.170 + * If multiple applicable methods are found during overload and none of them 1.171 + * is more specific than the others, attempt to merge their signatures. 1.172 + */ 1.173 + Symbol mergeAbstracts(Type site) { 1.174 + Symbol fst = ambiguousSyms.last(); 1.175 + Symbol res = fst; 1.176 + for (Symbol s : ambiguousSyms.reverse()) { 1.177 + Type mt1 = types.memberType(site, res); 1.178 + Type mt2 = types.memberType(site, s); 1.179 + if ((s.flags() & ABSTRACT) == 0 || 1.180 + !types.overrideEquivalent(mt1, mt2) || 1.181 + !types.isSameTypes(fst.erasure(types).getParameterTypes(), 1.182 + s.erasure(types).getParameterTypes())) { 1.183 + //ambiguity cannot be resolved 1.184 + return this; 1.185 + } else { 1.186 + Type mst = mostSpecificReturnType(mt1, mt2); 1.187 + if (mst == null) { 1.188 + // Theoretically, this can't happen, but it is possible 1.189 + // due to error recovery or mixing incompatible class files 1.190 + return this; 1.191 + } 1.192 + Symbol mostSpecific = mst == mt1 ? res : s; 1.193 + List<Type> allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes()); 1.194 + Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown); 1.195 + res = new MethodSymbol( 1.196 + mostSpecific.flags(), 1.197 + mostSpecific.name, 1.198 + newSig, 1.199 + mostSpecific.owner); 1.200 + } 1.201 + } 1.202 + return res; 1.203 + } 1.204 + 1.205 + @Override 1.206 + protected Symbol access(Name name, TypeSymbol location) { 1.207 + return ambiguousSyms.last(); 1.208 } 1.209 } 1.210
2.1 --- a/test/tools/javac/lambda/TargetType21.java Tue Jan 08 10:15:30 2013 +0100 2.2 +++ b/test/tools/javac/lambda/TargetType21.java Tue Jan 08 10:16:26 2013 +0100 2.3 @@ -25,7 +25,7 @@ 2.4 <R,A> void call(SAM3<R,A> sam) { } 2.5 2.6 void test() { 2.7 - call(x -> { throw new Exception(); }); //ok - resolves to call(SAM1) 2.8 + call(x -> { throw new Exception(); }); //ambiguous 2.9 call(x -> { System.out.println(""); }); //ok - resolves to call(SAM2) 2.10 call(x -> { return (Object) null; }); //error - call(SAM3) is not applicable because of cyclic inference 2.11 call(x -> { return null; }); ////ok - resolves to call(SAM1)
3.1 --- a/test/tools/javac/lambda/TargetType21.out Tue Jan 08 10:15:30 2013 +0100 3.2 +++ b/test/tools/javac/lambda/TargetType21.out Tue Jan 08 10:16:26 2013 +0100 3.3 @@ -1,3 +1,3 @@ 3.4 TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, call(TargetType21.SAM2), TargetType21 3.5 -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))} 3.6 +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))} 3.7 2 errors