changeset 3261:85d6aa1e1c79

Enhancement: add support for abstract peels in methods Example: interface Foo<any X> { void m() { __WhereRef(X) { System.out.println("Hello!"); } __WhereVal(X) abstract } } class SubRef implements Foo<String> { } //ok class SubVal implements Foo<int> { } //error
author mcimadamore
date Tue, 24 Nov 2015 13:13:51 +0000
parents 01e9ba0e9e8d
children 411dc20edc4e
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java test/tools/javac/valhalla/typespec/AbstractPeel01.java test/tools/javac/valhalla/typespec/AbstractPeel02.java test/tools/javac/valhalla/typespec/AbstractPeel02.out test/tools/javac/valhalla/typespec/AbstractPeel03.java test/tools/javac/valhalla/typespec/AbstractPeel03.out test/tools/javac/valhalla/typespec/TestRefOnly10.java test/tools/javac/valhalla/typespec/TestRefOnly10.out test/tools/javac/valhalla/typespec/items/tests/TestValOnly.java
diffstat 18 files changed, 214 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Nov 24 13:13:51 2015 +0000
@@ -1427,6 +1427,11 @@
          */
         public WhereClause whereClauses = WhereClause.emptyWhereClause;
 
+        /**
+         * Where clauses associated with abstract peels in this method.
+         */
+        public List<WhereClause> abstractWhereClauses = List.nil();
+
         /** regex for matching template method names */
         public final static Pattern templateMatcher = Pattern.compile("^(template)(\\$+)(.*)");
 
@@ -1674,10 +1679,15 @@
          */
         public boolean isApplicabilityRestrictedIn(Type site, Types types) {
             return whereClauses != WhereClause.emptyWhereClause &&
-                    !hasMatchingReceiver(site, types);
+                    !hasMatchingReceiver(site, types, whereClauses);
         }
 
-        private boolean hasMatchingReceiver(Type site, Types types) {
+        public boolean isAbstractIn(Type site, Types types) {
+            return abstractWhereClauses.isEmpty() ||
+                    abstractWhereClauses.stream().anyMatch(wc -> hasMatchingReceiver(site, types, wc));
+        }
+
+        private boolean hasMatchingReceiver(Type site, Types types, WhereClause whereClauses) {
             Type instSuper = types.asSuper(site, enclClass());
             return (!instSuper.isParameterized() ||
                     instSuper.isRaw() ||
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Tue Nov 24 13:13:51 2015 +0000
@@ -1767,6 +1767,11 @@
             sb.append(wildcard);
             return sb.toString();
         }
+
+        @Override
+        public boolean isReference() {
+            return bound.isReference();
+        }
     }
 
     public static abstract class DelegatedType extends Type {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Tue Nov 24 13:13:51 2015 +0000
@@ -3722,12 +3722,15 @@
                 Scope s = c.members();
                 for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
                     if (sym.kind == MTH &&
-                            (sym.flags() & (SYNTHETIC|ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
+                            (sym.flags() & (PEELED|SYNTHETIC|ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
                         //skip ref-only method as needed
                         if (c != impl &&
                                 ((MethodSymbol)sym).isApplicabilityRestrictedIn(impl.type, this)) {
                             continue;
                         }
+                        if (c != impl && !((MethodSymbol)sym).isAbstractIn(impl.type, this)) {
+                            continue;
+                        }
                         MethodSymbol absmeth = (MethodSymbol)sym;
                         MethodSymbol implmeth = absmeth.implementation(impl, this, true);
                         if (implmeth == null || implmeth == absmeth) {
@@ -5497,7 +5500,7 @@
         @Override
         public Type visitTypeVar(TypeVar t, Type target) {
             Type erased = erasureSource(target);
-            return isAnyTypeVar(t) ? t : asSuper(t, erased.tsym);
+            return isSpecializableTypeVar(t) ? t : asSuper(t, erased.tsym);
         }
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Nov 24 13:13:51 2015 +0000
@@ -1048,7 +1048,7 @@
                 if (isDefaultMethod || (tree.sym.flags() & (ABSTRACT | NATIVE)) == 0 &&
                     !relax)
                     log.error(tree.pos(), "missing.meth.body.or.decl.abstract");
-            } else if ((tree.sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
+            } else if (tree.sym.abstractWhereClauses.isEmpty() && (tree.sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
                 if ((owner.flags() & INTERFACE) != 0) {
                     log.error(tree.body.pos(), "intf.meth.cant.have.body");
                 } else {
@@ -1202,11 +1202,13 @@
                 env.dup(tree, env.info.dup(env.info.scope.dup()));
             TypeVarContext typeVarContext = null;
             if (tree.whereClauses != null) {
-                WhereClause whereClauses = attribWhereClause(localEnv, tree.whereClauses);
+                WhereClause whereClauses = WhereClause.getAttributedWhereClause(tree.whereClauses);
                 typeVarContext = types.withTypeVarContext(whereClauses);
             }
             try {
-                attribStats(tree.stats, localEnv);
+                if ((tree.flags & ABSTRACT) == 0) {
+                    attribStats(tree.stats, localEnv);
+                }
             } finally {
                 localEnv.info.scope.leave();
                 if (typeVarContext != null) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Nov 24 13:13:51 2015 +0000
@@ -414,11 +414,13 @@
             if (TreeInfo.isPeeledMethod(tree)) {
                 JCBlock prevBody = tree.body;
                 for (JCStatement block : tree.body.getStatements()) {
-                    try {
-                        tree.body = (JCBlock)block;
-                        visitMethod(tree);
-                    } finally {
-                        tree.body = prevBody;
+                    if ((((JCBlock)block).flags & ABSTRACT) == 0) {
+                        try {
+                            tree.body = (JCBlock)block;
+                            visitMethod(tree);
+                        } finally {
+                            tree.body = prevBody;
+                        }
                     }
                 }
             } else {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Nov 24 13:13:51 2015 +0000
@@ -236,6 +236,37 @@
         if (!tree.whereClauses.isEmpty()) {
             m.whereClauses = attr.attribWhereClause(localEnv, tree.whereClauses);
         }
+
+        WhereClauseChecker wcc = new WhereClauseChecker(localEnv);
+        wcc.scan(tree.body);
+        m.abstractWhereClauses = wcc.abstractWhereClauses;
+        if (wcc.hasConcrete && m.enclClass().isInterface()) {
+            m.enclClass().flags_field |= DEFAULT;
+        }
+    }
+
+    class WhereClauseChecker extends TreeScanner {
+
+        Env<AttrContext> localEnv;
+        boolean hasConcrete = false;
+        List<WhereClause> abstractWhereClauses = List.nil();
+
+        WhereClauseChecker(Env<AttrContext> localEnv) {
+            this.localEnv = localEnv;
+        }
+
+        @Override
+        public void visitBlock(JCBlock tree) {
+            super.visitBlock(tree);
+            if (tree.whereClauses != null) {
+                WhereClause wc = attr.attribWhereClause(localEnv, tree.whereClauses);
+                if ((tree.flags & ABSTRACT) != 0) {
+                    abstractWhereClauses = abstractWhereClauses.prepend(wc);
+                } else {
+                    hasConcrete = true;
+                }
+            }
+        }
     }
 
     /** Create a fresh environment for method bodies.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/SpecializeTypes.java	Tue Nov 24 13:13:51 2015 +0000
@@ -446,6 +446,7 @@
         //create new method symbol
         MethodSymbol msym = md.sym;
         MethodSymbol dupMethod = msym.clone(msym.owner);
+        dupMethod.flags_field |= body.flags;
         dupMethod.whereClauses = whereClauses;
 
         dupMethod.name =  templateMethodName(msym);
@@ -458,7 +459,10 @@
 
         //create new tree
         List<JCVariableDecl> paramTrees = dupParams.stream().map(p -> make.VarDef((VarSymbol)p, null)).collect(List.collector());
-        JCMethodDecl dupMd = make.MethodDef(md.mods, dupMethod.name, md.restype, md.typarams, null, paramTrees, md.thrown, body, null, body.whereClauses);
+
+        JCMethodDecl dupMd = make.MethodDef(make.Modifiers(md.mods.flags | body.flags),
+                dupMethod.name, md.restype, md.typarams, null, paramTrees, md.thrown,
+                (body.flags & Flags.ABSTRACT) == 0 ? body : null, null, body.whereClauses);
         dupMd.sym = dupMethod;
         dupMd.type = dupMethod.type;
         body.whereClauses = null;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Tue Nov 24 13:13:51 2015 +0000
@@ -1243,6 +1243,9 @@
      */
     void writeMethod(MethodSymbol m) {
         int flags = adjustFlags(m.flags());
+        if ((m.flags() & PEELED) != 0 && m.code != null) {
+            flags &= ~ABSTRACT;
+        }
         databuf.appendChar(flags);
         if (dumpMethodModifiers) {
             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
@@ -2021,7 +2024,6 @@
 
     int adjustFlags(final long flags) {
         int result = (int)flags;
-
         if ((flags & BRIDGE) != 0)
             result |= ACC_BRIDGE;
         if ((flags & VARARGS) != 0)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Tue Nov 24 13:13:51 2015 +0000
@@ -754,7 +754,7 @@
 
             @Override
             public Type visitTypeVar(TypeVar t, Type target) {
-                return  (types.isAnyTypeVar(t) && methodVars.contains(t)) ?
+                return  (types.isSpecializableTypeVar(t) && methodVars.contains(t)) ?
                         syms.objectType : super.visitTypeVar(t, target);
             }
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Nov 24 13:13:51 2015 +0000
@@ -3645,7 +3645,13 @@
             Map<JCIdent, WhereClause.Kind> whereClauses = whereOpt();
             ListBuffer<JCStatement> subBlocks = new ListBuffer<>();
             while (!whereClauses.isEmpty()) {
-                JCBlock subBlock = block();
+                JCBlock subBlock;
+                if (token.kind == ABSTRACT) {
+                    accept(ABSTRACT);
+                    subBlock = toP(F.at(pos).Block(Flags.ABSTRACT, List.nil()));
+                } else {
+                    subBlock = block();
+                }
                 subBlock.whereClauses = whereClauses;
                 subBlocks.add(subBlock);
                 whereClauses = whereOpt();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/AbstractPeel01.java	Tue Nov 24 13:13:51 2015 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 smoke test for abstract peeled methods
+ * @compile AbstractPeel01.java
+ * @run main AbstractPeel01
+ */
+public class AbstractPeel01 {
+    interface Foo<any X> {
+        void m() {
+            __WhereRef(X) { System.out.println("Hello!"); }
+            __WhereVal(X) abstract
+        }
+    }
+
+    static class Sub implements Foo<String> { } //ok
+
+    public static void main(String[] args) {
+        new Sub().m(); //prints "Hello!"
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/AbstractPeel02.java	Tue Nov 24 13:13:51 2015 +0000
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for abstract peels
+ * @compile/fail/ref=AbstractPeel02.out -XDrawDiagnostics AbstractPeel02.java
+ */
+
+class AbstractPeel02 {
+    interface Foo<any X> {
+       void m() {
+            __WhereRef(X) { System.out.println("Hello!"); }
+            __WhereVal(X) abstract
+       }
+    }
+
+    static class SubVal implements Foo<int> { } //error
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/AbstractPeel02.out	Tue Nov 24 13:13:51 2015 +0000
@@ -0,0 +1,2 @@
+AbstractPeel02.java:15:12: compiler.err.does.not.override.abstract: AbstractPeel02.SubVal, m(), AbstractPeel02.Foo
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/AbstractPeel03.java	Tue Nov 24 13:13:51 2015 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 smoke test for abstract peels and flow analysis
+ * @compile AbstractPeel03.java
+ */
+
+abstract class AbstractPeel03<any E> {
+     abstract boolean containsElement(E e) {
+        __WhereRef(E) { return true; }
+        __WhereVal(E) abstract
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/AbstractPeel03.out	Tue Nov 24 13:13:51 2015 +0000
@@ -0,0 +1,1 @@
+aa
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/TestRefOnly10.java	Tue Nov 24 13:13:51 2015 +0000
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary check that __RefOnly behaves correctly w.r.t. wildcards
+ * @compile/fail/ref=TestRefOnly10.out -XDrawDiagnostics TestRefOnly10.java
+ */
+
+class TestRefOnly10<any X> {
+    static class Foo<any E> {
+        __WhereRef(E) Object[] toArray() { return null; }
+    }
+
+    void test(Foo<? extends X> c) {
+        Object[] a = c.toArray();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/typespec/TestRefOnly10.out	Tue Nov 24 13:13:51 2015 +0000
@@ -0,0 +1,2 @@
+TestRefOnly10.java:13:31: compiler.err.illegal.restricted.call: TestRefOnly10.Foo<compiler.misc.type.captureof: 1, ? extends X>
+1 error
--- a/test/tools/javac/valhalla/typespec/items/tests/TestValOnly.java	Tue Nov 24 10:01:41 2015 +0000
+++ b/test/tools/javac/valhalla/typespec/items/tests/TestValOnly.java	Tue Nov 24 13:13:51 2015 +0000
@@ -36,7 +36,22 @@
     @TemplateMethod(name = "template$m2")
     __WhereVal(T) void m2(T t) { Foo.g(t); };
 
+    @TemplateMethod(name = "template$m3")
+    @BytecodeMapping(opcode=Opcodes.INVOKEVIRTUAL, sig = "LTestValOnly$Box<TT;>;::()TT;")
+    @BytecodeMapping(opcode=Opcodes.ASTORE_2)
+    __WhereVal(T) void m3(Box<T> bt) {
+        T t = bt.get();
+    }
+
     static class Foo {
         static <any Z> void g(Z z) { }
     }
+
+    static class Box<any X> {
+        X x;
+
+        @BytecodeMapping(opcode=Opcodes.GETFIELD)
+        @BytecodeMapping(opcode=Opcodes.ARETURN)
+        X get() { return x; }
+    }
 }