langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
changeset 14443 91c05eb19277
parent 14369 3d660d08d1f7
child 14547 86d8d242b0c4
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Sat Nov 03 21:09:57 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Sun Nov 04 10:59:42 2012 +0000
@@ -119,6 +119,9 @@
         allowAnnotations = source.allowAnnotations();
         allowCovariantReturns = source.allowCovariantReturns();
         allowSimplifiedVarargs = source.allowSimplifiedVarargs();
+        allowDefaultMethods = source.allowDefaultMethods();
+        allowStrictMethodClashCheck = source.allowStrictMethodClashCheck() &&
+                options.isSet("strictMethodClashCheck"); //pre-lambda guard
         complexInference = options.isSet("complexinference");
         warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
         suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile");
@@ -162,6 +165,14 @@
      */
     boolean allowSimplifiedVarargs;
 
+    /** Switch: default methods enabled?
+     */
+    boolean allowDefaultMethods;
+
+    /** Switch: should unrelated return types trigger a method clash?
+     */
+    boolean allowStrictMethodClashCheck;
+
     /** Switch: -complexinference option set?
      */
     boolean complexInference;
@@ -1114,7 +1125,7 @@
             }  else if ((sym.owner.flags_field & INTERFACE) != 0) {
                 if ((flags & DEFAULT) != 0) {
                     mask = InterfaceDefaultMethodMask;
-                    implicit = PUBLIC;
+                    implicit = PUBLIC | ABSTRACT;
                 } else {
                     mask = implicit = InterfaceMethodFlags;
                 }
@@ -2047,11 +2058,21 @@
                      undef == null && e != null;
                      e = e.sibling) {
                     if (e.sym.kind == MTH &&
-                        (e.sym.flags() & (ABSTRACT|IPROXY)) == ABSTRACT) {
+                        (e.sym.flags() & (ABSTRACT|IPROXY|DEFAULT)) == ABSTRACT) {
                         MethodSymbol absmeth = (MethodSymbol)e.sym;
                         MethodSymbol implmeth = absmeth.implementation(impl, types, true);
-                        if (implmeth == null || implmeth == absmeth)
+                        if (implmeth == null || implmeth == absmeth) {
+                            //look for default implementations
+                            if (allowDefaultMethods) {
+                                MethodSymbol prov = types.interfaceCandidates(impl.type, absmeth).head;
+                                if (prov != null && prov.overrides(absmeth, impl, types, true)) {
+                                    implmeth = prov;
+                                }
+                            }
+                        }
+                        if (implmeth == null || implmeth == absmeth) {
                             undef = absmeth;
+                        }
                     }
                 }
                 if (undef == null) {
@@ -2354,7 +2375,7 @@
                 if (m2 == m1) continue;
                 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
                 //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error
-                if (!types.isSubSignature(sym.type, types.memberType(site, m2), false) &&
+                if (!types.isSubSignature(sym.type, types.memberType(site, m2), allowStrictMethodClashCheck) &&
                         types.hasSameArgs(m2.erasure(types), m1.erasure(types))) {
                     sym.flags_field |= CLASH;
                     String key = m1 == sym ?
@@ -2386,7 +2407,7 @@
         for (Symbol s : types.membersClosure(site, true).getElementsByName(sym.name, cf)) {
             //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
             //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error
-            if (!types.isSubSignature(sym.type, types.memberType(site, s), false) &&
+            if (!types.isSubSignature(sym.type, types.memberType(site, s), allowStrictMethodClashCheck) &&
                     types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
                 log.error(pos,
                         "name.clash.same.erasure.no.hide",
@@ -2420,6 +2441,62 @@
          }
      }
 
+    void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) {
+        DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site);
+        for (Symbol m : types.membersClosure(site, false).getElements(dcf)) {
+            Assert.check(m.kind == MTH);
+            List<MethodSymbol> prov = types.interfaceCandidates(site, (MethodSymbol)m);
+            if (prov.size() > 1) {
+                ListBuffer<Symbol> abstracts = ListBuffer.lb();
+                ListBuffer<Symbol> defaults = ListBuffer.lb();
+                for (MethodSymbol provSym : prov) {
+                    if ((provSym.flags() & DEFAULT) != 0) {
+                        defaults = defaults.append(provSym);
+                    } else if ((provSym.flags() & ABSTRACT) != 0) {
+                        abstracts = abstracts.append(provSym);
+                    }
+                    if (defaults.nonEmpty() && defaults.size() + abstracts.size() >= 2) {
+                        //strong semantics - issue an error if two sibling interfaces
+                        //have two override-equivalent defaults - or if one is abstract
+                        //and the other is default
+                        String errKey;
+                        Symbol s1 = defaults.first();
+                        Symbol s2;
+                        if (defaults.size() > 1) {
+                            errKey = "types.incompatible.unrelated.defaults";
+                            s2 = defaults.toList().tail.head;
+                        } else {
+                            errKey = "types.incompatible.abstract.default";
+                            s2 = abstracts.first();
+                        }
+                        log.error(pos, errKey,
+                                Kinds.kindName(site.tsym), site,
+                                m.name, types.memberType(site, m).getParameterTypes(),
+                                s1.location(), s2.location());
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    //where
+     private class DefaultMethodClashFilter implements Filter<Symbol> {
+
+         Type site;
+
+         DefaultMethodClashFilter(Type site) {
+             this.site = site;
+         }
+
+         public boolean accepts(Symbol s) {
+             return s.kind == MTH &&
+                     (s.flags() & DEFAULT) != 0 &&
+                     s.isInheritedIn(site.tsym, types) &&
+                     !s.isConstructor();
+         }
+     }
+
     /** Report a conflict between a user symbol and a synthetic symbol.
      */
     private void syntheticError(DiagnosticPosition pos, Symbol sym) {