changeset 52230:e7216b29214d lworld

8211910: [lworld] Reinstate support for local value classes.
author sadayapalam
date Tue, 09 Oct 2018 15:46:13 +0530
parents 0cafe4547a4f
children 10438ad636e9
files src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java test/langtools/tools/javac/valhalla/lworld-values/AnonymousValueType.java test/langtools/tools/javac/valhalla/lworld-values/CheckLocalClasses.java test/langtools/tools/javac/valhalla/lworld-values/IllegalByValueTest.java test/langtools/tools/javac/valhalla/lworld-values/IllegalByValueTest2.java test/langtools/tools/javac/valhalla/lworld-values/ValueModifierTest.java test/langtools/tools/javac/valhalla/lworld-values/ValueModifierTest.out
diffstat 9 files changed, 191 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Oct 09 09:28:51 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Oct 09 15:46:13 2018 +0530
@@ -58,6 +58,7 @@
 import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
+import static com.sun.tools.javac.parser.Tokens.TokenKind.SYNCHRONIZED;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.ImplicitAndExplicitNotAllowed;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndExplicitNotAllowed;
@@ -2218,8 +2219,11 @@
     /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
      */
     JCExpression creator(int newpos, List<JCExpression> typeArgs) {
-        List<JCAnnotation> newAnnotations = typeAnnotationsOpt();
-        final JCModifiers mods = F.at(Position.NOPOS).Modifiers(0, newAnnotations);
+        final JCModifiers mods = modifiersOpt();
+        List<JCAnnotation> newAnnotations = mods.annotations;
+        if (!newAnnotations.isEmpty()) {
+            checkSourceLevel(newAnnotations.head.pos, Feature.TYPE_ANNOTATIONS);
+        }
         switch (token.kind) {
         case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
         case DOUBLE: case BOOLEAN:
@@ -2569,6 +2573,7 @@
      */
     List<JCStatement> blockStatement() {
         //todo: skip to anchor on error(?)
+        token = recastToken(token);
         int pos = token.pos;
         switch (token.kind) {
         case RBRACE: case CASE: case DEFAULT: case EOF:
@@ -2578,6 +2583,7 @@
         case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
         case ASSERT:
             return List.of(parseSimpleStatement());
+        case VALUE:
         case MONKEYS_AT:
         case FINAL: {
             Comment dc = token.comment(CommentStyle.JAVADOC);
@@ -3038,6 +3044,7 @@
     loop:
         while (true) {
             long flag;
+            token = recastToken(token);
             switch (token.kind) {
             case PRIVATE     : flag = Flags.PRIVATE; break;
             case PROTECTED   : flag = Flags.PROTECTED; break;
@@ -3049,16 +3056,14 @@
             case FINAL       : flag = Flags.FINAL; break;
             case ABSTRACT    : flag = Flags.ABSTRACT; break;
             case NATIVE      : flag = Flags.NATIVE; break;
+            case VALUE       : flag = Flags.VALUE; break;
             case VOLATILE    : flag = Flags.VOLATILE; break;
             case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
             case STRICTFP    : flag = Flags.STRICTFP; break;
             case MONKEYS_AT  : flag = Flags.ANNOTATION; break;
             case DEFAULT     : checkSourceLevel(Feature.DEFAULT_METHODS); flag = Flags.DEFAULT; break;
             case ERROR       : flag = 0; nextToken(); break;
-            default:           if (token.kind == IDENTIFIER && token.name() == names.value) {
-                                   checkSourceLevel(Feature.VALUE_TYPES); flag = Flags.VALUE; break;
-                               }
-                               break loop;
+            default: break loop;
             }
             if ((flags & flag) != 0) log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
             lastPos = token.pos;
@@ -3284,6 +3289,44 @@
         return result;
     }
 
+    // Does the given token signal a value modifier ? If yes, suitably reclassify token.
+    Token recastToken(Token token) {
+        if (token.kind != IDENTIFIER || token.name() != names.value) {
+            return token;
+        }
+        if (peekToken(t->t == PRIVATE ||
+                         t == PROTECTED ||
+                         t == PUBLIC ||
+                         t == STATIC ||
+                         t == TRANSIENT ||
+                         t == FLATTENABLE ||
+                         t == NOTFLATTENED ||
+                         t == FINAL ||
+                         t == ABSTRACT ||
+                         t == NATIVE ||
+                         t == VOLATILE ||
+                         t == SYNCHRONIZED ||
+                         t == STRICTFP ||
+                         t == MONKEYS_AT ||
+                         t == DEFAULT ||
+                         t == BYTE ||
+                         t == SHORT ||
+                         t == CHAR ||
+                         t == INT ||
+                         t == LONG ||
+                         t == FLOAT ||
+                         t == DOUBLE ||
+                         t == BOOLEAN ||
+                         t == CLASS ||
+                         t == INTERFACE ||
+                         t == ENUM ||
+                         t == IDENTIFIER)) { // new value Comparable() {}
+            checkSourceLevel(Feature.VALUE_TYPES);
+            return new Token(VALUE, token.pos, token.endPos, token.comments);
+        }
+        return token;
+    }
+
     boolean isRestrictedLocalVarTypeName(JCExpression e, boolean shouldWarn) {
         switch (e.getTag()) {
             case IDENT:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Tue Oct 09 09:28:51 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Tue Oct 09 15:46:13 2018 +0530
@@ -165,6 +165,7 @@
         FLATTENABLE("__Flattenable"),
         NOTFLATTENED("__NotFlattened"),
         TRY("try"),
+        VALUE(), // a phantom token never returned by the scanner, but can result from a reclassification by the parser.
         VOID("void", Tag.NAMED),
         VOLATILE("volatile"),
         WHILE("while"),
@@ -269,6 +270,8 @@
                 return "token.double";
             case ERROR:
                 return "token.bad-symbol";
+            case VALUE:
+                return "value";
             case EOF:
                 return "token.end-of-input";
             case DOT: case COMMA: case SEMI: case LPAREN: case RPAREN:
--- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Tue Oct 09 09:28:51 2018 +0200
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Tue Oct 09 15:46:13 2018 +0530
@@ -224,6 +224,7 @@
         FLATTENABLE(TokenKind.FLATTENABLE, XDECL1),  //  __Flattenable
         NOTFLATTENED(TokenKind.NOTFLATTENED, XDECL1),  //  __NotFlattened
         VOLATILE(TokenKind.VOLATILE, XDECL1),  //  volatile
+        VALUE(TokenKind.VALUE, 0),
 
         // Declarations and type parameters (thus expressions)
         EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL),  //  extends
--- a/test/langtools/tools/javac/valhalla/lworld-values/AnonymousValueType.java	Tue Oct 09 09:28:51 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/AnonymousValueType.java	Tue Oct 09 15:46:13 2018 +0530
@@ -22,6 +22,7 @@
  */
 
 /**
+ * @test
  * @bug 8209400
  * @summary Allow anonymous classes to be value types
  * @run main/othervm -Xverify:none -XX:+EnableValhalla AnonymousValueType
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/CheckLocalClasses.java	Tue Oct 09 15:46:13 2018 +0530
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, 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
+ * @bug 8211910
+ * @summary [lworld] Reinstate support for local value classes.
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ * @run main/othervm -XX:+EnableValhalla CheckLocalClasses
+ */
+
+import com.sun.tools.classfile.*;
+
+public class CheckLocalClasses {
+    public class RefOuter {
+        void foo() {
+            RefOuter o = new RefOuter();
+            value  class Inner {
+                private final int value2;
+                public Inner(int value2) {
+                    System.out.println(o);
+                    this.value2 = value2;
+                }
+            }
+        }
+    }
+    public value class ValueOuter {
+        int x = 10;
+        void foo() {
+            ValueOuter o = new ValueOuter();
+            value class Inner {
+                private final int value2;
+                public Inner(int value2) {
+                    System.out.println(o);
+                    this.value2 = value2;
+                }
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        ClassFile cls = ClassFile.read(CheckLocalClasses.class.getResourceAsStream("CheckLocalClasses$ValueOuter$1Inner.class"));
+
+        if (!cls.access_flags.is(AccessFlags.ACC_VALUE))
+            throw new Exception("Value flag not set");
+
+        if (!cls.access_flags.is(AccessFlags.ACC_FINAL))
+            throw new Exception("Final flag not set");
+
+        Field [] flds = cls.fields;
+
+        for (Field fld : flds) {
+            if (fld.getName(cls.constant_pool).equals("this$1")) {
+                if (!fld.access_flags.is(AccessFlags.ACC_FLATTENABLE))
+                    throw new Exception("Flattenable flag not set");
+            } else if (fld.getName(cls.constant_pool).equals("val$o")) {
+                if (!fld.access_flags.is(AccessFlags.ACC_FLATTENABLE))
+                    throw new Exception("Flattenable flag not set");
+            } else if (fld.getName(cls.constant_pool).equals("value2")) {
+                if (fld.access_flags.is(AccessFlags.ACC_FLATTENABLE))
+                    throw new Exception("Flattenable flag set");
+            }
+        }
+
+        cls = ClassFile.read(CheckLocalClasses.class.getResourceAsStream("CheckLocalClasses$RefOuter$1Inner.class"));
+
+        if (!cls.access_flags.is(AccessFlags.ACC_VALUE))
+            throw new Exception("Value flag not set");
+
+        if (!cls.access_flags.is(AccessFlags.ACC_FINAL))
+            throw new Exception("Final flag not set");
+
+        flds = cls.fields;
+
+        for (Field fld : flds) {
+            if (fld.getName(cls.constant_pool).equals("this$1")) {
+                if (fld.access_flags.is(AccessFlags.ACC_FLATTENABLE))
+                    throw new Exception("Flattenable flag is set");
+            } else if (fld.getName(cls.constant_pool).equals("val$o")) {
+                if (fld.access_flags.is(AccessFlags.ACC_FLATTENABLE))
+                    throw new Exception("Flattenable flag is set");
+            } else if (fld.getName(cls.constant_pool).equals("value2")) {
+                if (fld.access_flags.is(AccessFlags.ACC_FLATTENABLE))
+                    throw new Exception("Flattenable flag set");
+            }
+        }
+    }
+}
--- a/test/langtools/tools/javac/valhalla/lworld-values/IllegalByValueTest.java	Tue Oct 09 09:28:51 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/IllegalByValueTest.java	Tue Oct 09 15:46:13 2018 +0530
@@ -1,4 +1,5 @@
 /*
+ * @test /nodynamiccopyright/
  * @bug 8209400
  * @summary Allow anonymous classes to be value types
  * @compile/fail/ref=IllegalByValueTest.out -XDrawDiagnostics -XDdev IllegalByValueTest.java
--- a/test/langtools/tools/javac/valhalla/lworld-values/IllegalByValueTest2.java	Tue Oct 09 09:28:51 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/IllegalByValueTest2.java	Tue Oct 09 15:46:13 2018 +0530
@@ -1,4 +1,5 @@
 /*
+ * @test /nodynamiccopyright/
  * @bug 8209400
  * @summary Allow anonymous classes to be value types
  * @compile/fail/ref=IllegalByValueTest2.out -XDrawDiagnostics -XDdev IllegalByValueTest2.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ValueModifierTest.java	Tue Oct 09 15:46:13 2018 +0530
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8211910
+ * @summary Reinstate support for local value classes.
+ * @compile/fail/ref=ValueModifierTest.out -XDrawDiagnostics -XDdev ValueModifierTest.java
+ */
+
+public class ValueModifierTest {
+    interface value {}
+    void foo() {
+        new value value() {};
+    }
+    void goo() {
+        value class value {}
+        new value() {};
+        new value value() {};
+        new value();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ValueModifierTest.out	Tue Oct 09 15:46:13 2018 +0530
@@ -0,0 +1,6 @@
+ValueModifierTest.java:11:27: compiler.err.empty.value.not.yet
+ValueModifierTest.java:14:15: compiler.err.empty.value.not.yet
+ValueModifierTest.java:15:13: compiler.err.cant.inherit.from.final: value
+ValueModifierTest.java:16:27: compiler.err.value.may.not.extend
+ValueModifierTest.java:16:19: compiler.err.cant.inherit.from.final: value
+5 errors