8005179: Cleanup Resolve.AmbiguityError
authormcimadamore
Tue, 08 Jan 2013 10:16:26 +0100
changeset 15038 3ad27d268874
parent 15037 8ba16ac61b1a
child 15039 80190ab051c0
8005179: Cleanup Resolve.AmbiguityError Summary: Linearize nested ambiguity errors Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/test/tools/javac/lambda/TargetType21.java
langtools/test/tools/javac/lambda/TargetType21.out
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Jan 08 10:15:30 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Jan 08 10:16:26 2013 +0100
@@ -1122,52 +1122,20 @@
                 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 @@
 
         @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 @@
         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 @@
 
         @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 @@
      * (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 @@
                 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();
         }
     }
 
--- a/langtools/test/tools/javac/lambda/TargetType21.java	Tue Jan 08 10:15:30 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType21.java	Tue Jan 08 10:16:26 2013 +0100
@@ -25,7 +25,7 @@
     <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)
--- a/langtools/test/tools/javac/lambda/TargetType21.out	Tue Jan 08 10:15:30 2013 +0100
+++ b/langtools/test/tools/javac/lambda/TargetType21.out	Tue Jan 08 10:16:26 2013 +0100
@@ -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