7034798: Ambiguity error for abstract method call is too eager

Mon, 01 Jul 2013 14:57:03 +0100

author
mcimadamore
date
Mon, 01 Jul 2013 14:57:03 +0100
changeset 1875
f559ef7568ce
parent 1874
891c5ecb8306
child 1876
1908e86ee49a

7034798: Ambiguity error for abstract method call is too eager
Summary: Javac should wait and see if ambiguous methods can be reconciled at the end of an overload resolution round
Reviewed-by: jjg, vromero

src/share/classes/com/sun/tools/javac/comp/Resolve.java file | annotate | diff | comparison | revisions
test/tools/javac/resolve/ResolveHarness.java file | annotate | diff | comparison | revisions
test/tools/javac/resolve/tests/AbstractMerge.java file | annotate | diff | comparison | revisions
test/tools/javac/resolve/tests/InnerOverOuter.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Sat Jun 29 20:12:24 2013 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Jul 01 14:57:03 2013 +0100
     1.3 @@ -1573,7 +1573,6 @@
     1.4                            allowBoxing,
     1.5                            useVarargs,
     1.6                            operator);
     1.7 -        reportVerboseResolutionDiagnostic(env.tree.pos(), name, site, argtypes, typeargtypes, bestSoFar);
     1.8          return bestSoFar;
     1.9      }
    1.10      // where
    1.11 @@ -2224,7 +2223,7 @@
    1.12          return lookupMethod(env, pos, env.enclClass.sym, resolveMethodCheck,
    1.13                  new BasicLookupHelper(name, env.enclClass.sym.type, argtypes, typeargtypes) {
    1.14                      @Override
    1.15 -                    Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.16 +                    Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.17                          return findFun(env, name, argtypes, typeargtypes,
    1.18                                  phase.isBoxingRequired(),
    1.19                                  phase.isVarargsRequired());
    1.20 @@ -2256,7 +2255,7 @@
    1.21                                    List<Type> typeargtypes) {
    1.22          return lookupMethod(env, pos, location, resolveContext, new BasicLookupHelper(name, site, argtypes, typeargtypes) {
    1.23              @Override
    1.24 -            Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.25 +            Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.26                  return findMethod(env, site, name, argtypes, typeargtypes,
    1.27                          phase.isBoxingRequired(),
    1.28                          phase.isVarargsRequired(), false);
    1.29 @@ -2355,7 +2354,7 @@
    1.30                                List<Type> typeargtypes) {
    1.31          return lookupMethod(env, pos, site.tsym, resolveContext, new BasicLookupHelper(names.init, site, argtypes, typeargtypes) {
    1.32              @Override
    1.33 -            Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.34 +            Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.35                  return findConstructor(pos, env, site, argtypes, typeargtypes,
    1.36                          phase.isBoxingRequired(),
    1.37                          phase.isVarargsRequired());
    1.38 @@ -2413,7 +2412,7 @@
    1.39          return lookupMethod(env, pos, site.tsym, resolveMethodCheck,
    1.40                  new BasicLookupHelper(names.init, site, argtypes, typeargtypes) {
    1.41                      @Override
    1.42 -                    Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.43 +                    Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.44                          return findDiamond(env, site, argtypes, typeargtypes,
    1.45                                  phase.isBoxingRequired(),
    1.46                                  phase.isVarargsRequired());
    1.47 @@ -2503,7 +2502,7 @@
    1.48              return lookupMethod(env, pos, syms.predefClass, currentResolutionContext,
    1.49                      new BasicLookupHelper(name, syms.predefClass.type, argtypes, null, BOX) {
    1.50                  @Override
    1.51 -                Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.52 +                Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.53                      return findMethod(env, site, name, argtypes, typeargtypes,
    1.54                              phase.isBoxingRequired(),
    1.55                              phase.isVarargsRequired(), true);
    1.56 @@ -2669,6 +2668,13 @@
    1.57          abstract Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase);
    1.58  
    1.59          /**
    1.60 +         * Dump overload resolution info
    1.61 +         */
    1.62 +        void debug(DiagnosticPosition pos, Symbol sym) {
    1.63 +            //do nothing
    1.64 +        }
    1.65 +
    1.66 +        /**
    1.67           * Validate the result of the lookup
    1.68           */
    1.69          abstract Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym);
    1.70 @@ -2685,17 +2691,30 @@
    1.71          }
    1.72  
    1.73          @Override
    1.74 -        Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
    1.75 +        final Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
    1.76 +            Symbol sym = doLookup(env, phase);
    1.77              if (sym.kind == AMBIGUOUS) {
    1.78                  AmbiguityError a_err = (AmbiguityError)sym;
    1.79                  sym = a_err.mergeAbstracts(site);
    1.80              }
    1.81 +            return sym;
    1.82 +        }
    1.83 +
    1.84 +        abstract Symbol doLookup(Env<AttrContext> env, MethodResolutionPhase phase);
    1.85 +
    1.86 +        @Override
    1.87 +        Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
    1.88              if (sym.kind >= AMBIGUOUS) {
    1.89                  //if nothing is found return the 'first' error
    1.90                  sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes);
    1.91              }
    1.92              return sym;
    1.93          }
    1.94 +
    1.95 +        @Override
    1.96 +        void debug(DiagnosticPosition pos, Symbol sym) {
    1.97 +            reportVerboseResolutionDiagnostic(pos, name, site, argtypes, typeargtypes, sym);
    1.98 +        }
    1.99      }
   1.100  
   1.101      /**
   1.102 @@ -2924,7 +2943,9 @@
   1.103                  MethodResolutionPhase prevPhase = currentResolutionContext.step;
   1.104                  Symbol prevBest = bestSoFar;
   1.105                  currentResolutionContext.step = phase;
   1.106 -                bestSoFar = phase.mergeResults(bestSoFar, lookupHelper.lookup(env, phase));
   1.107 +                Symbol sym = lookupHelper.lookup(env, phase);
   1.108 +                lookupHelper.debug(pos, sym);
   1.109 +                bestSoFar = phase.mergeResults(bestSoFar, sym);
   1.110                  env.info.pendingResolutionPhase = (prevBest == bestSoFar) ? prevPhase : phase;
   1.111              }
   1.112              return lookupHelper.access(env, pos, location, bestSoFar);
   1.113 @@ -3630,35 +3651,39 @@
   1.114           * is more specific than the others, attempt to merge their signatures.
   1.115           */
   1.116          Symbol mergeAbstracts(Type site) {
   1.117 -            Symbol fst = ambiguousSyms.last();
   1.118 -            Symbol res = fst;
   1.119 -            for (Symbol s : ambiguousSyms.reverse()) {
   1.120 -                Type mt1 = types.memberType(site, res);
   1.121 -                Type mt2 = types.memberType(site, s);
   1.122 -                if ((s.flags() & ABSTRACT) == 0 ||
   1.123 -                        !types.overrideEquivalent(mt1, mt2) ||
   1.124 -                        !types.isSameTypes(fst.erasure(types).getParameterTypes(),
   1.125 -                                       s.erasure(types).getParameterTypes())) {
   1.126 -                    //ambiguity cannot be resolved
   1.127 -                    return this;
   1.128 -                } else {
   1.129 -                    Type mst = mostSpecificReturnType(mt1, mt2);
   1.130 -                    if (mst == null) {
   1.131 -                        // Theoretically, this can't happen, but it is possible
   1.132 -                        // due to error recovery or mixing incompatible class files
   1.133 +            List<Symbol> ambiguousInOrder = ambiguousSyms.reverse();
   1.134 +            for (Symbol s : ambiguousInOrder) {
   1.135 +                Type mt = types.memberType(site, s);
   1.136 +                boolean found = true;
   1.137 +                List<Type> allThrown = mt.getThrownTypes();
   1.138 +                for (Symbol s2 : ambiguousInOrder) {
   1.139 +                    Type mt2 = types.memberType(site, s2);
   1.140 +                    if ((s2.flags() & ABSTRACT) == 0 ||
   1.141 +                        !types.overrideEquivalent(mt, mt2) ||
   1.142 +                        !types.isSameTypes(s.erasure(types).getParameterTypes(),
   1.143 +                                       s2.erasure(types).getParameterTypes())) {
   1.144 +                        //ambiguity cannot be resolved
   1.145                          return this;
   1.146                      }
   1.147 -                    Symbol mostSpecific = mst == mt1 ? res : s;
   1.148 -                    List<Type> allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes());
   1.149 -                    Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown);
   1.150 -                    res = new MethodSymbol(
   1.151 -                            mostSpecific.flags(),
   1.152 -                            mostSpecific.name,
   1.153 -                            newSig,
   1.154 -                            mostSpecific.owner);
   1.155 +                    Type mst = mostSpecificReturnType(mt, mt2);
   1.156 +                    if (mst == null || mst != mt) {
   1.157 +                        found = false;
   1.158 +                        break;
   1.159 +                    }
   1.160 +                    allThrown = chk.intersect(allThrown, mt2.getThrownTypes());
   1.161 +                }
   1.162 +                if (found) {
   1.163 +                    //all ambiguous methods were abstract and one method had
   1.164 +                    //most specific return type then others
   1.165 +                    return (allThrown == mt.getThrownTypes()) ?
   1.166 +                            s : new MethodSymbol(
   1.167 +                                s.flags(),
   1.168 +                                s.name,
   1.169 +                                types.createMethodTypeWithThrown(mt, allThrown),
   1.170 +                                s.owner);
   1.171                  }
   1.172              }
   1.173 -            return res;
   1.174 +            return this;
   1.175          }
   1.176  
   1.177          @Override
     2.1 --- a/test/tools/javac/resolve/ResolveHarness.java	Sat Jun 29 20:12:24 2013 +0100
     2.2 +++ b/test/tools/javac/resolve/ResolveHarness.java	Mon Jul 01 14:57:03 2013 +0100
     2.3 @@ -32,6 +32,8 @@
     2.4  
     2.5  import com.sun.source.util.JavacTask;
     2.6  import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper;
     2.7 +import com.sun.tools.javac.code.Flags;
     2.8 +import com.sun.tools.javac.code.Symbol;
     2.9  import com.sun.tools.javac.code.Type.MethodType;
    2.10  import com.sun.tools.javac.util.JCDiagnostic;
    2.11  
    2.12 @@ -154,7 +156,7 @@
    2.13          //check all candidates have been used up
    2.14          for (Map.Entry<ElementKey, Candidate> entry : candidatesMap.entrySet()) {
    2.15              if (!seenCandidates.contains(entry.getKey())) {
    2.16 -                error("Redundant @Candidate annotation on method " + entry.getKey().elem);
    2.17 +                error("Redundant @Candidate annotation on method " + entry.getKey().elem + " sig = " + entry.getKey().elem.asType());
    2.18              }
    2.19          }
    2.20      }
    2.21 @@ -250,7 +252,7 @@
    2.22          void process(Diagnostic<? extends JavaFileObject> diagnostic) {
    2.23              Element siteSym = getSiteSym(diagnostic);
    2.24              if (siteSym.getSimpleName().length() != 0 &&
    2.25 -                    siteSym.getAnnotation(TraceResolve.class) == null) {
    2.26 +                    ((Symbol)siteSym).outermostClass().getAnnotation(TraceResolve.class) == null) {
    2.27                  return;
    2.28              }
    2.29              int candidateIdx = 0;
    2.30 @@ -308,7 +310,11 @@
    2.31  
    2.32          @Override
    2.33          void process(Diagnostic<? extends JavaFileObject> diagnostic) {
    2.34 -            Element methodSym = methodSym(diagnostic);
    2.35 +            Symbol methodSym = (Symbol)methodSym(diagnostic);
    2.36 +            if ((methodSym.flags() & Flags.GENERATEDCONSTR) != 0) {
    2.37 +                //skip resolution of default constructor (put there by javac)
    2.38 +                return;
    2.39 +            }
    2.40              Candidate c = getCandidateAtPos(methodSym,
    2.41                      asJCDiagnostic(diagnostic).getLineNumber(),
    2.42                      asJCDiagnostic(diagnostic).getColumnNumber());
    2.43 @@ -470,23 +476,10 @@
    2.44          }
    2.45  
    2.46          String computeKey(Element e) {
    2.47 -            StringBuilder buf = new StringBuilder();
    2.48 -            if (predefTranslationMap.containsKey(e.getSimpleName().toString())) {
    2.49 -                //predef element
    2.50 -                buf.append("<predef>.");
    2.51 -                String replacedName = predefTranslationMap.get(e.getSimpleName().toString());
    2.52 -                buf.append(e.toString().replace(e.getSimpleName().toString(), replacedName));
    2.53 -            } else if (e.getSimpleName().toString().startsWith("_")) {
    2.54 -                buf.append("<predef>.");
    2.55 -                buf.append(e.toString());
    2.56 -            } else {
    2.57 -                while (e != null) {
    2.58 -                    buf.append(e.toString());
    2.59 -                    e = e.getEnclosingElement();
    2.60 -                }
    2.61 -                buf.append(jfo.getName());
    2.62 -            }
    2.63 -            return buf.toString();
    2.64 +            String simpleName = e.getSimpleName().toString();
    2.65 +            String opName = predefTranslationMap.get(simpleName);
    2.66 +            String name = opName != null ? opName : simpleName;
    2.67 +            return name + e.asType();
    2.68          }
    2.69  
    2.70          @Override
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/tools/javac/resolve/tests/AbstractMerge.java	Mon Jul 01 14:57:03 2013 +0100
     3.3 @@ -0,0 +1,107 @@
     3.4 +/*
     3.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.
    3.11 + *
    3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.15 + * version 2 for more details (a copy is included in the LICENSE file that
    3.16 + * accompanied this code).
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License version
    3.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.21 + *
    3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.23 + * or visit www.oracle.com if you need additional information or have any
    3.24 + * questions.
    3.25 + */
    3.26 +@TraceResolve
    3.27 +class AbstractMerge {
    3.28 +
    3.29 +    interface A {
    3.30 +        @Candidate(applicable=Phase.BASIC)
    3.31 +        java.io.Serializable m1();
    3.32 +        @Candidate(applicable=Phase.BASIC)
    3.33 +        java.io.Serializable m2();
    3.34 +        @Candidate(applicable=Phase.BASIC)
    3.35 +        java.io.Serializable m3();
    3.36 +        @Candidate(applicable=Phase.BASIC)
    3.37 +        java.io.Serializable m4();
    3.38 +        @Candidate(applicable=Phase.BASIC)
    3.39 +        java.io.Serializable m5();
    3.40 +        @Candidate(applicable=Phase.BASIC)
    3.41 +        java.io.Serializable m6();
    3.42 +    }
    3.43 +
    3.44 +    interface B {
    3.45 +        @Candidate(applicable=Phase.BASIC)
    3.46 +        Cloneable m1();
    3.47 +        @Candidate(applicable=Phase.BASIC)
    3.48 +        Cloneable m2();
    3.49 +        @Candidate(applicable=Phase.BASIC)
    3.50 +        Cloneable m3();
    3.51 +        @Candidate(applicable=Phase.BASIC)
    3.52 +        Cloneable m4();
    3.53 +        @Candidate(applicable=Phase.BASIC)
    3.54 +        Cloneable m5();
    3.55 +        @Candidate(applicable=Phase.BASIC)
    3.56 +        Cloneable m6();
    3.57 +    }
    3.58 +
    3.59 +    interface C {
    3.60 +        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
    3.61 +        Object[] m1();
    3.62 +        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
    3.63 +        Object[] m2();
    3.64 +        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
    3.65 +        Object[] m3();
    3.66 +        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
    3.67 +        Object[] m4();
    3.68 +        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
    3.69 +        Object[] m5();
    3.70 +        @Candidate(applicable=Phase.BASIC, mostSpecific=true)
    3.71 +        Object[] m6();
    3.72 +    }
    3.73 +
    3.74 +    interface ABC extends A, B, C { }
    3.75 +    interface ACB extends A, C, B { }
    3.76 +    interface BAC extends B, A, C { }
    3.77 +    interface BCA extends B, C, A { }
    3.78 +    interface CAB extends C, A, B { }
    3.79 +    interface CBA extends C, B, A { }
    3.80 +
    3.81 +    {
    3.82 +        ABC abc = null;
    3.83 +        abc.m1();
    3.84 +    }
    3.85 +
    3.86 +    {
    3.87 +        ACB acb = null;
    3.88 +        acb.m2();
    3.89 +    }
    3.90 +
    3.91 +    {
    3.92 +        BAC bac = null;
    3.93 +        bac.m3();
    3.94 +    }
    3.95 +
    3.96 +    {
    3.97 +        BCA bca = null;
    3.98 +        bca.m4();
    3.99 +    }
   3.100 +
   3.101 +    {
   3.102 +        CAB cab = null;
   3.103 +        cab.m5();
   3.104 +    }
   3.105 +
   3.106 +    {
   3.107 +        CBA cba = null;
   3.108 +        cba.m6();
   3.109 +    }
   3.110 +}
     4.1 --- a/test/tools/javac/resolve/tests/InnerOverOuter.java	Sat Jun 29 20:12:24 2013 +0100
     4.2 +++ b/test/tools/javac/resolve/tests/InnerOverOuter.java	Mon Jul 01 14:57:03 2013 +0100
     4.3 @@ -21,7 +21,7 @@
     4.4   * questions.
     4.5   */
     4.6  
     4.7 -@TraceResolve
     4.8 +@TraceResolve(keys={"compiler.err.cant.apply.symbol"})
     4.9  class Test {
    4.10  
    4.11      //no annotation here - this should NOT even be considered!
    4.12 @@ -30,7 +30,6 @@
    4.13      //no annotation here - this should NOT even be considered!
    4.14      void m(Object... o) { }
    4.15  
    4.16 -    @TraceResolve(keys={"compiler.err.cant.apply.symbol"})
    4.17      class Inner {
    4.18          @Candidate
    4.19          void m(String s) {

mercurial