langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
changeset 14443 91c05eb19277
parent 14359 d4099818ab70
child 14444 2069262b27c5
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Sat Nov 03 21:09:57 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Sun Nov 04 10:59:42 2012 +0000
@@ -52,6 +52,7 @@
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import javax.lang.model.element.ElementVisitor;
 
@@ -88,6 +89,7 @@
     public final boolean boxingEnabled; // = source.allowBoxing();
     public final boolean varargsEnabled; // = source.allowVarargs();
     public final boolean allowMethodHandles;
+    public final boolean allowDefaultMethods;
     private final boolean debugResolve;
     final EnumSet<VerboseResolutionMode> verboseResolutionMode;
 
@@ -122,6 +124,7 @@
         verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options);
         Target target = Target.instance(context);
         allowMethodHandles = target.hasMethodHandles();
+        allowDefaultMethods = source.allowDefaultMethods();
         polymorphicSignatureScope = new Scope(syms.noSymbol);
 
         inapplicableMethodException = new InapplicableMethodException(diags);
@@ -1327,6 +1330,42 @@
         }
     }
 
+    Symbol lookupMethod(Env<AttrContext> env,
+            Type site,
+            Name name,
+            List<Type> argtypes,
+            List<Type> typeargtypes,
+            Scope sc,
+            Symbol bestSoFar,
+            boolean allowBoxing,
+            boolean useVarargs,
+            boolean operator,
+            boolean abstractok) {
+        for (Symbol s : sc.getElementsByName(name, new LookupFilter(abstractok))) {
+            bestSoFar = selectBest(env, site, argtypes, typeargtypes, s,
+                    bestSoFar, allowBoxing, useVarargs, operator);
+        }
+        return bestSoFar;
+    }
+    //where
+        class LookupFilter implements Filter<Symbol> {
+
+            boolean abstractOk;
+
+            LookupFilter(boolean abstractOk) {
+                this.abstractOk = abstractOk;
+            }
+
+            public boolean accepts(Symbol s) {
+                long flags = s.flags();
+                return s.kind == MTH &&
+                        (flags & SYNTHETIC) == 0 &&
+                        (abstractOk ||
+                        (flags & DEFAULT) != 0 ||
+                        (flags & ABSTRACT) == 0);
+            }
+        };
+
     /** Find best qualified method matching given name, type and value
      *  arguments.
      *  @param env       The current environment.
@@ -1371,49 +1410,76 @@
                               boolean allowBoxing,
                               boolean useVarargs,
                               boolean operator) {
-        boolean abstractOk = true;
-        List<Type> itypes = List.nil();
+        @SuppressWarnings({"unchecked","rawtypes"})
+        List<Type>[] itypes = (List<Type>[])new List[] { List.<Type>nil(), List.<Type>nil() };
+        InterfaceLookupPhase iphase = InterfaceLookupPhase.ABSTRACT_OK;
         for (TypeSymbol s : superclasses(intype)) {
             bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes,
                     s.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
-            //We should not look for abstract methods if receiver is a concrete class
-            //(as concrete classes are expected to implement all abstracts coming
-            //from superinterfaces)
-            abstractOk &= (s.flags() & (ABSTRACT | INTERFACE | ENUM)) != 0;
-            if (abstractOk) {
+            if (name == names.init) return bestSoFar;
+            iphase = (iphase == null) ? null : iphase.update(s, this);
+            if (iphase != null) {
                 for (Type itype : types.interfaces(s.type)) {
-                    itypes = types.union(types.closure(itype), itypes);
+                    itypes[iphase.ordinal()] = types.union(types.closure(itype), itypes[iphase.ordinal()]);
                 }
             }
-            if (name == names.init) break;
         }
 
         Symbol concrete = bestSoFar.kind < ERR &&
                 (bestSoFar.flags() & ABSTRACT) == 0 ?
                 bestSoFar : methodNotFound;
 
-        if (name != names.init) {
+        for (InterfaceLookupPhase iphase2 : InterfaceLookupPhase.values()) {
+            if (iphase2 == InterfaceLookupPhase.DEFAULT_OK && !allowDefaultMethods) break;
             //keep searching for abstract methods
-            for (Type itype : itypes) {
+            for (Type itype : itypes[iphase2.ordinal()]) {
                 if (!itype.isInterface()) continue; //skip j.l.Object (included by Types.closure())
+                if (iphase2 == InterfaceLookupPhase.DEFAULT_OK &&
+                        (itype.tsym.flags() & DEFAULT) == 0) continue;
                 bestSoFar = lookupMethod(env, site, name, argtypes, typeargtypes,
-                    itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
-                    if (concrete != bestSoFar &&
-                            concrete.kind < ERR  && bestSoFar.kind < ERR &&
-                            types.isSubSignature(concrete.type, bestSoFar.type)) {
-                        //this is an hack - as javac does not do full membership checks
-                        //most specific ends up comparing abstract methods that might have
-                        //been implemented by some concrete method in a subclass and,
-                        //because of raw override, it is possible for an abstract method
-                        //to be more specific than the concrete method - so we need
-                        //to explicitly call that out (see CR 6178365)
-                        bestSoFar = concrete;
-                    }
+                        itype.tsym.members(), bestSoFar, allowBoxing, useVarargs, operator, true);
+                if (concrete != bestSoFar &&
+                        concrete.kind < ERR  && bestSoFar.kind < ERR &&
+                        types.isSubSignature(concrete.type, bestSoFar.type)) {
+                    //this is an hack - as javac does not do full membership checks
+                    //most specific ends up comparing abstract methods that might have
+                    //been implemented by some concrete method in a subclass and,
+                    //because of raw override, it is possible for an abstract method
+                    //to be more specific than the concrete method - so we need
+                    //to explicitly call that out (see CR 6178365)
+                    bestSoFar = concrete;
+                }
             }
         }
         return bestSoFar;
     }
 
+    enum InterfaceLookupPhase {
+        ABSTRACT_OK() {
+            @Override
+            InterfaceLookupPhase update(Symbol s, Resolve rs) {
+                //We should not look for abstract methods if receiver is a concrete class
+                //(as concrete classes are expected to implement all abstracts coming
+                //from superinterfaces)
+                if ((s.flags() & (ABSTRACT | INTERFACE | ENUM)) != 0) {
+                    return this;
+                } else if (rs.allowDefaultMethods) {
+                    return DEFAULT_OK;
+                } else {
+                    return null;
+                }
+            }
+        },
+        DEFAULT_OK() {
+            @Override
+            InterfaceLookupPhase update(Symbol s, Resolve rs) {
+                return this;
+            }
+        };
+
+        abstract InterfaceLookupPhase update(Symbol s, Resolve rs);
+    }
+
     /**
      * Return an Iterable object to scan the superclasses of a given type.
      * It's crucial that the scan is done lazily, as we don't want to accidentally
@@ -1467,34 +1533,6 @@
         };
     }
 
-    /**
-     * Lookup a method with given name and argument types in a given scope
-     */
-    Symbol lookupMethod(Env<AttrContext> env,
-            Type site,
-            Name name,
-            List<Type> argtypes,
-            List<Type> typeargtypes,
-            Scope sc,
-            Symbol bestSoFar,
-            boolean allowBoxing,
-            boolean useVarargs,
-            boolean operator,
-            boolean abstractok) {
-        for (Symbol s : sc.getElementsByName(name, lookupFilter)) {
-            bestSoFar = selectBest(env, site, argtypes, typeargtypes, s,
-                    bestSoFar, allowBoxing, useVarargs, operator);
-        }
-        return bestSoFar;
-    }
-    //where
-        Filter<Symbol> lookupFilter = new Filter<Symbol>() {
-            public boolean accepts(Symbol s) {
-                return s.kind == MTH &&
-                        (s.flags() & SYNTHETIC) == 0;
-            }
-        };
-
     /** Find unqualified method matching given name, type and value arguments.
      *  @param env       The current environment.
      *  @param name      The method's name.
@@ -1920,7 +1958,7 @@
     /** Check that sym is not an abstract method.
      */
     void checkNonAbstract(DiagnosticPosition pos, Symbol sym) {
-        if ((sym.flags() & ABSTRACT) != 0)
+        if ((sym.flags() & ABSTRACT) != 0 && (sym.flags() & DEFAULT) == 0)
             log.error(pos, "abstract.cant.be.accessed.directly",
                       kindName(sym), sym, sym.location());
     }
@@ -2744,9 +2782,47 @@
             if ((env1.enclClass.sym.flags() & STATIC) != 0) staticOnly = true;
             env1 = env1.outer;
         }
+        if (allowDefaultMethods && c.isInterface() &&
+                name == names._super && !isStatic(env) &&
+                types.isDirectSuperInterface(c.type, env.enclClass.sym)) {
+            //this might be a default super call if one of the superinterfaces is 'c'
+            for (Type t : pruneInterfaces(env.enclClass.type)) {
+                if (t.tsym == c) {
+                    env.info.defaultSuperCallSite = t;
+                    return new VarSymbol(0, names._super,
+                            types.asSuper(env.enclClass.type, c), env.enclClass.sym);
+                }
+            }
+            //find a direct superinterface that is a subtype of 'c'
+            for (Type i : types.interfaces(env.enclClass.type)) {
+                if (i.tsym.isSubClass(c, types) && i.tsym != c) {
+                    log.error(pos, "illegal.default.super.call", c,
+                            diags.fragment("redundant.supertype", c, i));
+                    return syms.errSymbol;
+                }
+            }
+            Assert.error();
+        }
         log.error(pos, "not.encl.class", c);
         return syms.errSymbol;
     }
+    //where
+    private List<Type> pruneInterfaces(Type t) {
+        ListBuffer<Type> result = ListBuffer.lb();
+        for (Type t1 : types.interfaces(t)) {
+            boolean shouldAdd = true;
+            for (Type t2 : types.interfaces(t)) {
+                if (t1 != t2 && types.isSubtypeNoCapture(t2, t1)) {
+                    shouldAdd = false;
+                }
+            }
+            if (shouldAdd) {
+                result.append(t1);
+            }
+        }
+        return result.toList();
+    }
+
 
     /**
      * Resolve `c.this' for an enclosing class c that contains the