changeset 756:3122e07ad069

More defender method fixes: *) re-abstracted methods should 'shadow' extension methods in superinterfaces *) conflict resolution problem when same extension method is inherithed twice
author mcimadamore
date Thu, 02 Dec 2010 10:35:09 +0000
parents b635a35cbb89
children 7af674c07fca
files src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Check.java test/tools/javac/defender/Neg03.java test/tools/javac/defender/Neg03.out test/tools/javac/defender/Pos11.java
diffstat 5 files changed, 199 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Mon Nov 29 16:58:44 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Dec 02 10:35:09 2010 +0000
@@ -2566,10 +2566,13 @@
             Entry e = cache.get(origin);
             if (e == null ||
                     !e.matches(implFilter, checkResult, scopeCounter)) {
-                MethodSymbol impl = implementationInternal(ms, origin, Types.this, checkResult, implFilter, false);
-                if (impl == null &&
+                MethodSymbol impl = implementationInternal(ms, origin, checkResult, implFilter);
+                if ((impl == null || (impl.flags() & ABSTRACT) != 0) &&
                         source.allowDefenderMethods()) {
-                    impl = implementationInternal(ms, origin, Types.this, checkResult, implFilter, true);
+                    MethodSymbol newImpl =
+                            findCompatibleDefendersInSite(origin.type, ms).head;
+                    if (newImpl != null)
+                        impl = newImpl; //we found a suitable defender impl
                 }
                 cache.put(origin, new Entry(impl, implFilter, checkResult, scopeCounter));
                 return impl;
@@ -2579,8 +2582,8 @@
             }
         }
 
-        private MethodSymbol implementationInternal(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult, Filter<Symbol> implFilter, boolean defenderAllowed) {
-            for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = types.supertype(t)) {
+        private MethodSymbol implementationInternal(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter) {
+            for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = supertype(t)) {
                 while (t.tag == TYPEVAR)
                     t = t.getUpperBound();
                 TypeSymbol c = t.tsym;
@@ -2588,18 +2591,9 @@
                      e.scope != null;
                      e = e.next()) {
                     if (e.sym != null &&
-                             e.sym.overrides(ms, origin, types, checkResult) &&
-                             (!defenderAllowed || !origin.isInterface() || (e.sym.flags() & DEFENDER) != 0))
+                             e.sym.overrides(ms, origin, Types.this, checkResult))
                         return (MethodSymbol)e.sym;
                 }
-                if (defenderAllowed) {
-                    for (Type t2 : interfaces(t)) {
-                        MethodSymbol impl = implementationInternal(ms, t2.tsym, types, checkResult, implFilter, defenderAllowed);
-                        if (impl != null) {
-                            return impl;
-                        }
-                    }
-                }
             }
             return null;
         }
@@ -2610,6 +2604,64 @@
     public MethodSymbol implementation(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult, Filter<Symbol> implFilter) {
         return implCache.get(ms, origin, checkResult, implFilter, scopeCounter);
     }
+
+    //where
+    public List<MethodSymbol> findCompatibleDefendersInSite(Type site, MethodSymbol ms) {
+        ListBuffer<MethodSymbol> methods = ListBuffer.lb();
+        findCompatibleDefendersInSite(site, ms, site.tsym, methods);
+        ListBuffer<MethodSymbol> methodsMin = ListBuffer.lb();
+        for (MethodSymbol m1 : methods) {
+            boolean isMin_m1 = true;
+            for (MethodSymbol m2 : methods) {
+                if (m1 == m2) continue;
+                if (asSuper(m2.owner.type, m1.owner) != null) {
+                    isMin_m1 = false;
+                    break;
+                }
+            }
+            if (isMin_m1)
+                methodsMin.append(m1);
+        }
+        return methodsMin.toList();
+    }
+
+    private void findCompatibleDefendersInSite(Type site, MethodSymbol ms, TypeSymbol origin, ListBuffer<MethodSymbol> methods) {
+        for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = supertype(t)) {
+            while (t.tag == TYPEVAR)
+                t = t.getUpperBound();
+            TypeSymbol c = t.tsym;
+            for (Scope.Entry e = c.members().lookup(ms.name, new DefenderOrAbstractFilter(ms, site));
+                 e.scope != null;
+                 e = e.next()) {
+                if (e.sym != null) {
+                    if ((e.sym.flags() & DEFENDER) != 0 &&
+                            !methods.contains(e.sym))
+                        methods.append((MethodSymbol)e.sym);
+                    return;
+                }
+            }
+            for (Type t2 : interfaces(t)) {
+                findCompatibleDefendersInSite(site, ms, t2.tsym, methods);
+            }
+        }
+    }
+    // where
+            private class DefenderOrAbstractFilter implements Filter<Symbol> {
+
+                Symbol msym;
+                Type site;
+
+                DefenderOrAbstractFilter(Symbol msym, Type site) {
+                    this.msym = msym;
+                    this.site = site;
+                }
+
+                public boolean accepts(Symbol s) {
+                    return s.kind == Kinds.MTH &&
+                            overrideEquivalent(memberType(site, s), memberType(site, msym)) &&
+                            (s.flags() & DEFENDER | ABSTRACT) != 0;
+                }
+            };
     // </editor-fold>
 
     /**
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Nov 29 16:58:44 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Dec 02 10:35:09 2010 +0000
@@ -1774,10 +1774,16 @@
                          checkCommonOverriderIn(s1,s2,site);
                     String errKey = "types.incompatible.diff.ret";
                     if (compat && allowDefenderMethods) {
-                        compat &= ((s1.flags() & DEFENDER) != (s2.flags() & DEFENDER)) ||
-                                (((MethodSymbol) s1).getDefaultImpl() ==
-                                ((MethodSymbol) s2).getDefaultImpl()) ||
-                                checkCommonOverriderIn(s1,s2,site);
+                        Symbol defaultImpl = null;
+                        for (MethodSymbol defender :
+                                types.findCompatibleDefendersInSite(site, (MethodSymbol)s1)) {
+                            if (defaultImpl == null) {
+                                defaultImpl = defender.getDefaultImpl();
+                            } else {
+                                compat = compat &&
+                                        defaultImpl == defender.getDefaultImpl();
+                            }
+                        }
                         errKey = "types.incompatible.diff.default";
                     }
                     if (!compat) return new CompatibilityResult(s2, errKey);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Neg03.java	Thu Dec 02 10:35:09 2010 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary check that re-abstracted defender methods are skipped accordingly
+ * @author  Brian Goetz
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=Neg03.out -XDrawDiagnostics Neg03.java
+ */
+
+class Neg03 {
+    interface A {
+        void m() default Neg03.one;
+    }
+
+    interface B {
+        void m() default Neg03.two;
+    }
+
+    interface C extends A, B {
+      void m() default Neg03.one;
+    }
+
+    static class X implements C, A { } //ok - ignore extraneous remix of A
+
+    interface D extends A, B {
+      void m();  // reabstraction of m()
+    }
+
+    static class Y implements D, A { } // ok - m() is abstract in D but A provides the defender
+
+    interface E extends A {
+        void m();  // reabstraction of m()
+    }
+
+    static class W implements D, E { } // invalid - missing impl for m()
+
+    static class Z implements D, A, B { } // invalid - conflict between A and B
+
+    static void one(Object a) {  }
+    static void two(Object a) {  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Neg03.out	Thu Dec 02 10:35:09 2010 +0000
@@ -0,0 +1,3 @@
+Neg03.java:57:12: compiler.err.does.not.override.abstract: Neg03.W, m(), Neg03.D
+Neg03.java:59:12: compiler.err.types.incompatible.diff.default: Neg03.A, Neg03.D, m()
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Pos11.java	Thu Dec 02 10:35:09 2010 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary complex test with conflict resolution via overriding
+ * @author  Brian Goetz
+ * @compile Pos11.java
+ */
+
+class Pos11 {
+    interface A {
+        void get() default Pos11.one;
+    }
+
+    interface B {
+        void get() default Pos11.two;
+    }
+
+    interface C extends A {
+        void get() default Pos11.two;
+    }
+
+    interface D extends A, B {
+        void get() default Pos11.two;
+    }
+
+    static class X implements C { }
+
+    static class Y implements C, A { }
+
+    static class Z implements D, A, B { }
+
+    static void one(Object a) {  }
+    static void two(Object a) {  }
+}