changeset 747:fa6868eac2c4

More extension method fixes: *) Interface defining common overrider should resolve extension method conflicts in supertypes *) Default method should be attributed lazily (possibly during Symbol completion) - this is to avoid spurious failures that depend on the compilation-order
author mcimadamore
date Fri, 29 Oct 2010 13:38:49 +0100
parents 76f6f9e8b0ec
children cd26d488d641
files src/share/classes/com/sun/tools/javac/code/Symbol.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/comp/Lower.java src/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java test/tools/javac/defender/Pos07.java test/tools/javac/defender/Pos08.java
diffstat 8 files changed, 142 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Oct 28 13:04:00 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Oct 29 13:38:49 2010 +0100
@@ -1055,9 +1055,9 @@
         public List<Name> savedParameterNames;
 
         /** Symbol corresponding to the method's default implementation
-         * (used for defender methods);
+         * (used for defender methods) - lazily resolved (see getDefaultImpl);
          */
-        public Symbol defaultImpl = null;
+        protected Symbol defaultImpl = null;
 
         /** For an attribute field accessor, its default value if any.
          *  The value is null if none appeared in the method
@@ -1098,6 +1098,10 @@
             }
         }
 
+        public Symbol getDefaultImpl() {
+            return null;
+        }
+
         /** find a symbol that this (proxy method) symbol implements.
          *  @param    c       The class whose members are searched for
          *                    implementations
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Oct 28 13:04:00 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Oct 29 13:38:49 2010 +0100
@@ -818,19 +818,11 @@
                     }
                 }
 
-                // Attribute method body.
-                attribStat(tree.body, localEnv);
-
-                if (isDefender) {
-                    //check that default expression is of right type
-                    if (tree.body.stats.head.getTag() != JCTree.EXEC ||
-                            ((JCExpressionStatement)tree.body.stats.head).expr.getTag() != JCTree.APPLY) {
-                        log.error(tree.body.stats.head, "bad.defender.method.body");
-                    } else {
-                        JCTree defaultImpl = ((JCExpressionStatement)tree.body.stats.head).expr;
-                        chk.checkType(defaultImpl, localEnv, defaultImpl.type, m.type.getReturnType());
-                        m.defaultImpl = TreeInfo.symbol(((JCMethodInvocation)defaultImpl).meth);
-                    }
+                if (!isDefender) {
+                    // Attribute method body.
+                    attribStat(tree.body, localEnv);
+                } else {
+                    tree.sym.getDefaultImpl();
                 }
             }
             localEnv.info.scope.leave();
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Oct 28 13:04:00 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Oct 29 13:38:49 2010 +0100
@@ -1761,8 +1761,9 @@
                     String errKey = "types.incompatible.diff.ret";
                     if (compat && allowDefenderMethods) {
                         compat &= ((s1.flags() & DEFENDER) != (s2.flags() & DEFENDER)) ||
-                                (((MethodSymbol)s1).defaultImpl ==
-                                ((MethodSymbol)s2).defaultImpl);
+                                (((MethodSymbol) s1).getDefaultImpl() ==
+                                ((MethodSymbol) s2).getDefaultImpl()) ||
+                                checkCommonOverriderIn(s1,s2,site);
                         errKey = "types.incompatible.diff.default";
                     }
                     if (!compat) return new CompatibilityResult(s2, errKey);
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java	Thu Oct 28 13:04:00 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Oct 29 13:38:49 2010 +0100
@@ -2630,15 +2630,15 @@
             ListBuffer<Pair<MethodSymbol, Attribute>> values = ListBuffer.lb();
 
             MethodSymbol _className = lookupMethod(tree.pos(), names._className, syms.defenderMethodType, List.<Type>nil());
-            String _classNameVal = tree.sym.defaultImpl.enclClass().flatName().toString();
+            String _classNameVal = tree.sym.getDefaultImpl().enclClass().flatName().toString();
             values.append(new Pair<MethodSymbol, Attribute>(_className, new Attribute.Constant(syms.stringType, _classNameVal)));
 
             MethodSymbol _methodName = lookupMethod(tree.pos(), names._methodName, syms.defenderMethodType, List.<Type>nil());
-            String _methodNameVal = tree.sym.defaultImpl.name.toString();
+            String _methodNameVal = tree.sym.getDefaultImpl().name.toString();
             values.append(new Pair<MethodSymbol, Attribute>(_methodName, new Attribute.Constant(syms.stringType, _methodNameVal)));
 
             MethodSymbol _methodSignature = lookupMethod(tree.pos(), names._methodSignature, syms.defenderMethodType, List.<Type>nil());
-            String _methodSignatureVal = writer.typeSig(types.erasure(tree.sym.defaultImpl.type)).toString();
+            String _methodSignatureVal = writer.typeSig(types.erasure(tree.sym.getDefaultImpl().type)).toString();
             values.append(new Pair<MethodSymbol, Attribute>(_methodSignature, new Attribute.Constant(syms.stringType, _methodSignatureVal)));
 
             tree.sym.attributes_field = tree.sym.attributes_field.prepend(new Attribute.Compound(syms.defenderMethodType, values.toList()));
--- a/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Thu Oct 28 13:04:00 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Oct 29 13:38:49 2010 +0100
@@ -566,9 +566,35 @@
         }
     }
 
-    public void visitMethodDef(JCMethodDecl tree) {
+    public void visitMethodDef(final JCMethodDecl tree) {
         Scope enclScope = enter.enterScope(env);
-        MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
+        MethodSymbol m = (tree.mods.flags & DEFENDER) == 0 ?
+            new MethodSymbol(0, tree.name, null, enclScope.owner) :
+            new MethodSymbol(0, tree.name, null, enclScope.owner) {
+                @Override
+                public Symbol getDefaultImpl() {
+                    if (defaultImpl != null) return defaultImpl;
+                    else {
+                        Env<AttrContext> ownerEnv = enter.getClassEnv((TypeSymbol)owner);
+                        Env<AttrContext> localEnv = methodEnv(tree, ownerEnv);
+                        //enter method params in local scope (needed in order
+                        //to attribute fake defender body)
+                        for (Symbol param : params) {
+                            localEnv.info.scope.enter(param);
+                        }
+                        attr.attribStat(tree.body, localEnv);
+                        if (tree.body.stats.head.getTag() != JCTree.EXEC ||
+                            ((JCExpressionStatement)tree.body.stats.head).expr.getTag() != JCTree.APPLY) {
+                            log.error(tree.body.stats.head, "bad.defender.method.body");
+                            return defaultImpl = syms.errSymbol;
+                        } else {
+                            JCTree defaultImplTree = ((JCExpressionStatement)tree.body.stats.head).expr;
+                            chk.checkType(defaultImplTree, localEnv, defaultImplTree.type, type.getReturnType());
+                            return defaultImpl = TreeInfo.symbol(((JCMethodInvocation)defaultImplTree).meth);
+                        }
+                    }
+                }
+            };
         m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
         tree.sym = m;
 
@@ -970,7 +996,7 @@
 
             // If this is a class, enter symbols for this and super into
             // current scope.
-            if ((c.flags_field & INTERFACE) == 0) {
+            if ((c.flags_field & (DEFENDER | ~INTERFACE)) != 0) {
                 VarSymbol thisSym =
                     new VarSymbol(FINAL | HASINIT, names._this, c.type, c);
                 thisSym.pos = Position.FIRSTPOS;
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Thu Oct 28 13:04:00 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Oct 29 13:38:49 2010 +0100
@@ -641,13 +641,13 @@
     int writeDefenderAttribute(MethodSymbol m) {
         if (!target.hasDefenderAttribute() ||
                 (m.flags() & DEFENDER) == 0 ||
-                m.defaultImpl == null)
+                m.getDefaultImpl() == null)
             return 0;
 
         int alenIdx = writeAttr(names.Defender);
         ClassSymbol enclClass = m.enclClass();
         databuf.appendChar(pool.put(enclClass));
-        databuf.appendChar(pool.put(nameType(m.defaultImpl)));
+        databuf.appendChar(pool.put(nameType(m.getDefaultImpl())));
         endAttr(alenIdx);
         return 1;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Pos07.java	Fri Oct 29 13:38:49 2010 +0100
@@ -0,0 +1,44 @@
+/*
+ * 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 compilation order does not matter
+ * @author  Maurizio Cimadamore
+ * @compile Pos07.java
+ */
+
+class Pos07 {
+    interface A {
+         extension void foo() default Pos07.impl;
+         extension void bar() default Pos07.impl;
+    }
+
+    static class C implements B, A {}
+
+    interface B extends A {
+        extension void foo() default Pos07.impl;
+    }
+
+    static void impl(A a) {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Pos08.java	Fri Oct 29 13:38:49 2010 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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 common overrider solves default method conflicts
+ * @author  Maurizio Cimadamore
+ * @compile Pos08.java
+ */
+
+class Pos08 {
+    interface A {
+        extension void m() default Pos08.a;
+    }
+
+    interface B {
+        extension void m() default Pos08.b;
+    }
+
+    interface C extends A, B {
+        extension void m() default Pos08.b;
+    }
+
+    interface D extends A, B {
+        void m();
+    }
+
+    static void a(A o) { }
+    static void b(B o) { }
+}