langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
changeset 19914 d86271bd430a
parent 19660 7cc9663100f1
child 19930 b6181c0049f3
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Aug 30 17:36:47 2013 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Sep 02 22:38:36 2013 +0100
@@ -2368,7 +2368,10 @@
         //for each method m1 that is overridden (directly or indirectly)
         //by method 'sym' in 'site'...
         for (Symbol m1 : types.membersClosure(site, false).getElementsByName(sym.name, cf)) {
-            if (!sym.overrides(m1, site.tsym, types, false)) continue;
+             if (!sym.overrides(m1, site.tsym, types, false)) {
+                 checkPotentiallyAmbiguousOverloads(pos, site, sym, (MethodSymbol)m1);
+                 continue;
+             }
              //...check each method m2 that is a member of 'site'
              for (Symbol m2 : types.membersClosure(site, false).getElementsByName(sym.name, cf)) {
                 if (m2 == m1) continue;
@@ -2406,14 +2409,17 @@
         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), allowStrictMethodClashCheck) &&
-                    types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
-                log.error(pos,
-                        "name.clash.same.erasure.no.hide",
-                        sym, sym.location(),
-                        s, s.location());
-                return;
-             }
+            if (!types.isSubSignature(sym.type, types.memberType(site, s), allowStrictMethodClashCheck)) {
+                if (types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
+                    log.error(pos,
+                            "name.clash.same.erasure.no.hide",
+                            sym, sym.location(),
+                            s, s.location());
+                    return;
+                } else {
+                    checkPotentiallyAmbiguousOverloads(pos, site, sym, (MethodSymbol)s);
+                }
+            }
          }
      }
 
@@ -2496,6 +2502,62 @@
          }
      }
 
+    /**
+      * Report warnings for potentially ambiguous method declarations. Two declarations
+      * are potentially ambiguous if they feature two unrelated functional interface
+      * in same argument position (in which case, a call site passing an implicit
+      * lambda would be ambiguous).
+      */
+    void checkPotentiallyAmbiguousOverloads(DiagnosticPosition pos, Type site,
+            MethodSymbol msym1, MethodSymbol msym2) {
+        if (msym1 != msym2 &&
+                allowDefaultMethods &&
+                lint.isEnabled(LintCategory.OVERLOADS) &&
+                (msym1.flags() & POTENTIALLY_AMBIGUOUS) == 0 &&
+                (msym2.flags() & POTENTIALLY_AMBIGUOUS) == 0) {
+            Type mt1 = types.memberType(site, msym1);
+            Type mt2 = types.memberType(site, msym2);
+            //if both generic methods, adjust type variables
+            if (mt1.hasTag(FORALL) && mt2.hasTag(FORALL) &&
+                    types.hasSameBounds((ForAll)mt1, (ForAll)mt2)) {
+                mt2 = types.subst(mt2, ((ForAll)mt2).tvars, ((ForAll)mt1).tvars);
+            }
+            //expand varargs methods if needed
+            int maxLength = Math.max(mt1.getParameterTypes().length(), mt2.getParameterTypes().length());
+            List<Type> args1 = rs.adjustArgs(mt1.getParameterTypes(), msym1, maxLength, true);
+            List<Type> args2 = rs.adjustArgs(mt2.getParameterTypes(), msym2, maxLength, true);
+            //if arities don't match, exit
+            if (args1.length() != args2.length()) return;
+            boolean potentiallyAmbiguous = false;
+            while (args1.nonEmpty() && args2.nonEmpty()) {
+                Type s = args1.head;
+                Type t = args2.head;
+                if (!types.isSubtype(t, s) && !types.isSubtype(s, t)) {
+                    if (types.isFunctionalInterface(s) && types.isFunctionalInterface(t) &&
+                            types.findDescriptorType(s).getParameterTypes().length() > 0 &&
+                            types.findDescriptorType(s).getParameterTypes().length() ==
+                            types.findDescriptorType(t).getParameterTypes().length()) {
+                        potentiallyAmbiguous = true;
+                    } else {
+                        break;
+                    }
+                }
+                args1 = args1.tail;
+                args2 = args2.tail;
+            }
+            if (potentiallyAmbiguous) {
+                //we found two incompatible functional interfaces with same arity
+                //this means a call site passing an implicit lambda would be ambigiuous
+                msym1.flags_field |= POTENTIALLY_AMBIGUOUS;
+                msym2.flags_field |= POTENTIALLY_AMBIGUOUS;
+                log.warning(LintCategory.OVERLOADS, pos, "potentially.ambiguous.overload",
+                            msym1, msym1.location(),
+                            msym2, msym2.location());
+                return;
+            }
+        }
+    }
+
     /** Report a conflict between a user symbol and a synthetic symbol.
      */
     private void syntheticError(DiagnosticPosition pos, Symbol sym) {