7193913: Cleanup Resolve.findMethod

Tue, 25 Sep 2012 11:52:37 +0100

author
mcimadamore
date
Tue, 25 Sep 2012 11:52:37 +0100
changeset 1335
99983a4a593b
parent 1334
8987971bcb45
child 1336
26d93df3905a

7193913: Cleanup Resolve.findMethod
Summary: Refactor method lookup logic in Resolve.findMethod
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/comp/Resolve.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Sep 24 14:04:34 2012 -0700
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Sep 25 11:52:37 2012 +0100
     1.3 @@ -40,6 +40,7 @@
     1.4  import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
     1.5  import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
     1.6  
     1.7 +import java.util.ArrayList;
     1.8  import java.util.Arrays;
     1.9  import java.util.Collection;
    1.10  import java.util.EnumMap;
    1.11 @@ -57,6 +58,7 @@
    1.12  import static com.sun.tools.javac.code.TypeTags.*;
    1.13  import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*;
    1.14  import static com.sun.tools.javac.tree.JCTree.Tag.*;
    1.15 +import java.util.Iterator;
    1.16  
    1.17  /** Helper class for name resolution, used mostly by the attribution phase.
    1.18   *
    1.19 @@ -1035,8 +1037,8 @@
    1.20                              return this;
    1.21                          else
    1.22                              return super.implementation(origin, types, checkResult);
    1.23 -                    }
    1.24 -                };
    1.25 +                        }
    1.26 +                    };
    1.27                  return result;
    1.28              }
    1.29              if (m1SignatureMoreSpecific) return m1;
    1.30 @@ -1160,12 +1162,10 @@
    1.31                            argtypes,
    1.32                            typeargtypes,
    1.33                            site.tsym.type,
    1.34 -                          true,
    1.35                            bestSoFar,
    1.36                            allowBoxing,
    1.37                            useVarargs,
    1.38 -                          operator,
    1.39 -                          new HashSet<TypeSymbol>());
    1.40 +                          operator);
    1.41          reportVerboseResolutionDiagnostic(env.tree.pos(), name, site, argtypes, typeargtypes, bestSoFar);
    1.42          return bestSoFar;
    1.43      }
    1.44 @@ -1176,56 +1176,137 @@
    1.45                                List<Type> argtypes,
    1.46                                List<Type> typeargtypes,
    1.47                                Type intype,
    1.48 -                              boolean abstractok,
    1.49                                Symbol bestSoFar,
    1.50                                boolean allowBoxing,
    1.51                                boolean useVarargs,
    1.52 -                              boolean operator,
    1.53 -                              Set<TypeSymbol> seen) {
    1.54 -        for (Type ct = intype; ct.tag == CLASS || ct.tag == TYPEVAR; ct = types.supertype(ct)) {
    1.55 -            while (ct.tag == TYPEVAR)
    1.56 -                ct = ct.getUpperBound();
    1.57 -            ClassSymbol c = (ClassSymbol)ct.tsym;
    1.58 -            if (!seen.add(c)) return bestSoFar;
    1.59 -            if ((c.flags() & (ABSTRACT | INTERFACE | ENUM)) == 0)
    1.60 -                abstractok = false;
    1.61 -            for (Scope.Entry e = c.members().lookup(name);
    1.62 -                 e.scope != null;
    1.63 -                 e = e.next()) {
    1.64 -                //- System.out.println(" e " + e.sym);
    1.65 -                if (e.sym.kind == MTH &&
    1.66 -                    (e.sym.flags_field & SYNTHETIC) == 0) {
    1.67 -                    bestSoFar = selectBest(env, site, argtypes, typeargtypes,
    1.68 -                                           e.sym, bestSoFar,
    1.69 -                                           allowBoxing,
    1.70 -                                           useVarargs,
    1.71 -                                           operator);
    1.72 +                              boolean operator) {
    1.73 +        boolean abstractOk = true;
    1.74 +        List<Type> itypes = List.nil();
    1.75 +        for (TypeSymbol s : superclasses(intype)) {
    1.76 +            bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes,
    1.77 +                    s.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
    1.78 +            abstractOk &= excludeAbstractsFilter.accepts(s);
    1.79 +            if (abstractOk) {
    1.80 +                for (Type itype : types.interfaces(s.type)) {
    1.81 +                    itypes = types.union(types.closure(itype), itypes);
    1.82                  }
    1.83              }
    1.84 -            if (name == names.init)
    1.85 -                break;
    1.86 -            //- System.out.println(" - " + bestSoFar);
    1.87 -            if (abstractok) {
    1.88 -                Symbol concrete = methodNotFound;
    1.89 -                if ((bestSoFar.flags() & ABSTRACT) == 0)
    1.90 -                    concrete = bestSoFar;
    1.91 -                for (List<Type> l = types.interfaces(c.type);
    1.92 -                     l.nonEmpty();
    1.93 -                     l = l.tail) {
    1.94 -                    bestSoFar = findMethod(env, site, name, argtypes,
    1.95 -                                           typeargtypes,
    1.96 -                                           l.head, abstractok, bestSoFar,
    1.97 -                                           allowBoxing, useVarargs, operator, seen);
    1.98 -                }
    1.99 -                if (concrete != bestSoFar &&
   1.100 -                    concrete.kind < ERR  && bestSoFar.kind < ERR &&
   1.101 -                    types.isSubSignature(concrete.type, bestSoFar.type))
   1.102 -                    bestSoFar = concrete;
   1.103 +            if (name == names.init) break;
   1.104 +        }
   1.105 +
   1.106 +        Symbol concrete = bestSoFar.kind < ERR &&
   1.107 +                (bestSoFar.flags() & ABSTRACT) == 0 ?
   1.108 +                bestSoFar : methodNotFound;
   1.109 +
   1.110 +        if (name != names.init) {
   1.111 +            //keep searching for abstract methods
   1.112 +            for (Type itype : itypes) {
   1.113 +                if (!itype.isInterface()) continue; //skip j.l.Object (included by Types.closure())
   1.114 +                bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes,
   1.115 +                    itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
   1.116 +                    if (concrete != bestSoFar &&
   1.117 +                            concrete.kind < ERR  && bestSoFar.kind < ERR &&
   1.118 +                            types.isSubSignature(concrete.type, bestSoFar.type)) {
   1.119 +                        //this is an hack - as javac does not do full membership checks
   1.120 +                        //most specific ends up comparing abstract methods that might have
   1.121 +                        //been implemented by some concrete method in a subclass and,
   1.122 +                        //because of raw override, it is possible for an abstract method
   1.123 +                        //to be more specific than the concrete method - so we need
   1.124 +                        //to explicitly call that out (see CR 6178365)
   1.125 +                        bestSoFar = concrete;
   1.126 +                    }
   1.127              }
   1.128          }
   1.129          return bestSoFar;
   1.130      }
   1.131  
   1.132 +    /**
   1.133 +     * Return an Iterable object to scan the superclasses of a given type.
   1.134 +     * It's crucial that the scan is done lazily, as we don't want to accidentally
   1.135 +     * access more supertypes than strictly needed (as this could trigger completion
   1.136 +     * errors if some of the not-needed supertypes are missing/ill-formed).
   1.137 +     */
   1.138 +    Iterable<TypeSymbol> superclasses(final Type intype) {
   1.139 +        return new Iterable<TypeSymbol>() {
   1.140 +            public Iterator<TypeSymbol> iterator() {
   1.141 +                return new Iterator<TypeSymbol>() {
   1.142 +
   1.143 +                    List<TypeSymbol> seen = List.nil();
   1.144 +                    TypeSymbol currentSym = getSymbol(intype);
   1.145 +
   1.146 +                    public boolean hasNext() {
   1.147 +                        return currentSym != null;
   1.148 +                    }
   1.149 +
   1.150 +                    public TypeSymbol next() {
   1.151 +                        TypeSymbol prevSym = currentSym;
   1.152 +                        currentSym = getSymbol(types.supertype(currentSym.type));
   1.153 +                        return prevSym;
   1.154 +                    }
   1.155 +
   1.156 +                    public void remove() {
   1.157 +                        throw new UnsupportedOperationException("Not supported yet.");
   1.158 +                    }
   1.159 +
   1.160 +                    TypeSymbol getSymbol(Type intype) {
   1.161 +                        if (intype.tag != CLASS &&
   1.162 +                                intype.tag != TYPEVAR) {
   1.163 +                            return null;
   1.164 +                        }
   1.165 +                        while (intype.tag == TYPEVAR)
   1.166 +                            intype = intype.getUpperBound();
   1.167 +                        if (seen.contains(intype.tsym)) {
   1.168 +                            //degenerate case in which we have a circular
   1.169 +                            //class hierarchy - because of ill-formed classfiles
   1.170 +                            return null;
   1.171 +                        }
   1.172 +                        seen = seen.prepend(intype.tsym);
   1.173 +                        return intype.tsym;
   1.174 +                    }
   1.175 +                };
   1.176 +            }
   1.177 +        };
   1.178 +    }
   1.179 +
   1.180 +    /**
   1.181 +     * We should not look for abstract methods if receiver is a concrete class
   1.182 +     * (as concrete classes are expected to implement all abstracts coming
   1.183 +     * from superinterfaces)
   1.184 +     */
   1.185 +    Filter<Symbol> excludeAbstractsFilter = new Filter<Symbol>() {
   1.186 +        public boolean accepts(Symbol s) {
   1.187 +            return (s.flags() & (ABSTRACT | INTERFACE | ENUM)) != 0;
   1.188 +        }
   1.189 +    };
   1.190 +
   1.191 +    /**
   1.192 +     * Lookup a method with given name and argument types in a given scope
   1.193 +     */
   1.194 +    Symbol lookupMethod(Env<AttrContext> env,
   1.195 +            Type site,
   1.196 +            Name name,
   1.197 +            List<Type> argtypes,
   1.198 +            List<Type> typeargtypes,
   1.199 +            Scope sc,
   1.200 +            Symbol bestSoFar,
   1.201 +            boolean allowBoxing,
   1.202 +            boolean useVarargs,
   1.203 +            boolean operator,
   1.204 +            boolean abstractok) {
   1.205 +        for (Symbol s : sc.getElementsByName(name, lookupFilter)) {
   1.206 +            bestSoFar = selectBest(env, site, argtypes, typeargtypes, s,
   1.207 +                    bestSoFar, allowBoxing, useVarargs, operator);
   1.208 +        }
   1.209 +        return bestSoFar;
   1.210 +    }
   1.211 +    //where
   1.212 +        Filter<Symbol> lookupFilter = new Filter<Symbol>() {
   1.213 +            public boolean accepts(Symbol s) {
   1.214 +                return s.kind == MTH &&
   1.215 +                        (s.flags() & SYNTHETIC) == 0;
   1.216 +            }
   1.217 +        };
   1.218 +
   1.219      /** Find unqualified method matching given name, type and value arguments.
   1.220       *  @param env       The current environment.
   1.221       *  @param name      The method's name.

mercurial