Skip to content

Commit

Permalink
8279368: [lworld] Add parser support for declaration of value classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Srikanth Adayapalam committed Jan 10, 2022
1 parent d555db6 commit 063c1c4
Show file tree
Hide file tree
Showing 23 changed files with 284 additions and 54 deletions.
40 changes: 40 additions & 0 deletions src/java.base/share/classes/java/lang/__value__.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2022 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.
*/

package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

/**
* A class annotated {@code @__value__} is a value class.
* This is a temporary workaround to enable use of value classes
* in editors and IDEs that do not yet understand the 'value' modifier.
* @since 18
*/
@Retention(RetentionPolicy.SOURCE)
@Target(value={ElementType.TYPE, ElementType.TYPE_USE})
public @interface __value__ {
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ public enum Modifier {
* @since 1.8
*/
DEFAULT,
/**
* The modifier {@code primitive}
* @since 1.17
*/
PRIMITIVE,

/** The modifier {@code static} */ STATIC,

Expand All @@ -86,6 +81,19 @@ public String toString() {
return "non-sealed";
}
},

/**
* The modifier {@code primitive}
* @since 18
*/
PRIMITIVE,

/**
* The modifier {@code value}
* @since 18
*/
VALUE,

/** The modifier {@code final} */ FINAL,
/** The modifier {@code transient} */ TRANSIENT,
/** The modifier {@code volatile} */ VOLATILE,
Expand Down
24 changes: 13 additions & 11 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public static EnumSet<Flag> asFlagSet(long flags) {
public static final int ACC_SUPER = 0x0020;
public static final int ACC_BRIDGE = 0x0040;
public static final int ACC_VARARGS = 0x0080;
public static final int ACC_VALUE = 0x0100;
public static final int ACC_PRIMITIVE = 0x0800;
public static final int ACC_MODULE = 0x8000;

Expand Down Expand Up @@ -148,9 +149,8 @@ public static EnumSet<Flag> asFlagSet(long flags) {
*/
public static final int BLOCK = 1<<20;

/** Flag bit 21 is available. (used earlier to tag compiler-generated abstract methods that implement
* an interface method (Miranda methods)).
*/
/** Marks a type as a value class */
public static final int VALUE_CLASS = 1<<21;

/** Flag is set for nested classes that do not access instance members
* or `this' of an outer class and therefore don't need to be passed
Expand Down Expand Up @@ -416,7 +416,7 @@ public static EnumSet<Flag> asFlagSet(long flags) {
*/
public static final int
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
LocalClassFlags = FINAL | ABSTRACT | ENUM | SYNTHETIC | ACC_PRIMITIVE,
LocalClassFlags = FINAL | ABSTRACT | ENUM | SYNTHETIC | ACC_PRIMITIVE | ACC_VALUE,
StaticLocalClassFlags = LocalClassFlags | STATIC | INTERFACE,
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
MemberStaticClassFlags = MemberClassFlags | STATIC,
Expand All @@ -431,13 +431,13 @@ public static EnumSet<Flag> asFlagSet(long flags) {
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
SYNCHRONIZED | FINAL | STRICTFP;
public static final long
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED | PRIMITIVE_CLASS,
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED | PRIMITIVE_CLASS,
ExtendedMemberStaticClassFlags = (long) MemberStaticClassFlags | SEALED | NON_SEALED | PRIMITIVE_CLASS,
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED | PRIMITIVE_CLASS,
ExtendedLocalClassFlags = (long) LocalClassFlags | PRIMITIVE_CLASS,
ExtendedStaticLocalClassFlags = (long) StaticLocalClassFlags | PRIMITIVE_CLASS,
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED | PRIMITIVE_CLASS,
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED | PRIMITIVE_CLASS | VALUE_CLASS,
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED | PRIMITIVE_CLASS | VALUE_CLASS,
ExtendedMemberStaticClassFlags = (long) MemberStaticClassFlags | SEALED | NON_SEALED | PRIMITIVE_CLASS | VALUE_CLASS,
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED | PRIMITIVE_CLASS | VALUE_CLASS,
ExtendedLocalClassFlags = (long) LocalClassFlags | PRIMITIVE_CLASS | VALUE_CLASS,
ExtendedStaticLocalClassFlags = (long) StaticLocalClassFlags | PRIMITIVE_CLASS | VALUE_CLASS,
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED | PRIMITIVE_CLASS | VALUE_CLASS,
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
LocalVarFlags = FINAL | PARAMETER,
Expand All @@ -464,6 +464,7 @@ public static Set<Modifier> asModifierSet(long flags) {
if (0 != (flags & STRICTFP)) modifiers.add(Modifier.STRICTFP);
if (0 != (flags & DEFAULT)) modifiers.add(Modifier.DEFAULT);
if (0 != (flags & PRIMITIVE_CLASS)) modifiers.add(Modifier.PRIMITIVE);
if (0 != (flags & VALUE_CLASS)) modifiers.add(Modifier.VALUE);
modifiers = Collections.unmodifiableSet(modifiers);
modifierSets.put(flags, modifiers);
}
Expand Down Expand Up @@ -511,6 +512,7 @@ public enum Flag {
ENUM(Flags.ENUM),
MANDATED(Flags.MANDATED),
PRIMITIVE(Flags.PRIMITIVE_CLASS),
VALUE(Flags.VALUE_CLASS),
NOOUTERTHIS(Flags.NOOUTERTHIS),
EXISTS(Flags.EXISTS),
COMPOUND(Flags.COMPOUND),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,12 @@ public enum Feature {
PATTERN_MATCHING_IN_INSTANCEOF(JDK16, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL),
REIFIABLE_TYPES_INSTANCEOF(JDK16, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL),
RECORDS(JDK16, Fragments.FeatureRecords, DiagKind.PLURAL),
PRIMITIVE_CLASSES(JDK17, Fragments.FeaturePrimitiveClasses, DiagKind.NORMAL),
SEALED_CLASSES(JDK17, Fragments.FeatureSealedClasses, DiagKind.PLURAL),
CASE_NULL(JDK17, Fragments.FeatureCaseNull, DiagKind.NORMAL),
PATTERN_SWITCH(JDK17, Fragments.FeaturePatternSwitch, DiagKind.PLURAL),
REDUNDANT_STRICTFP(JDK17),
PRIMITIVE_CLASSES(JDK18, Fragments.FeaturePrimitiveClasses, DiagKind.PLURAL),
VALUE_CLASSES(JDK18, Fragments.FeatureValueClasses, DiagKind.PLURAL),
;

enum DiagKind {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ public class ClassReader {
*/
boolean allowPrimitiveClasses;

/** Switch: allow value classes.
*/
boolean allowValueClasses;

/** Switch: allow sealed
*/
boolean allowSealedTypes;
Expand Down Expand Up @@ -282,7 +286,10 @@ protected ClassReader(Context context) {
Source source = Source.instance(context);
preview = Preview.instance(context);
allowModules = Feature.MODULES.allowedInSource(source);
allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source);
allowPrimitiveClasses = (!preview.isPreview(Feature.PRIMITIVE_CLASSES) || preview.isEnabled()) &&
Feature.PRIMITIVE_CLASSES.allowedInSource(source);
allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
Feature.VALUE_CLASSES.allowedInSource(source);
allowRecords = Feature.RECORDS.allowedInSource(source);
allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);

Expand Down Expand Up @@ -2789,6 +2796,12 @@ long adjustClassFlags(long flags) {
flags |= PRIMITIVE_CLASS;
}
}
if ((flags & ACC_VALUE) != 0) {
flags &= ~ACC_VALUE;
if (allowValueClasses) {
flags |= VALUE_CLASS;
}
}
return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,8 @@ int adjustFlags(final long flags) {
result &= ~ABSTRACT;
if ((flags & PRIMITIVE_CLASS) != 0)
result |= ACC_PRIMITIVE;
if ((flags & VALUE_CLASS) != 0)
result |= ACC_VALUE;
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ protected JavacParser(ParserFactory fac,
this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
this.allowPrimitiveClasses = (!preview.isPreview(Feature.PRIMITIVE_CLASSES) || preview.isEnabled()) &&
Feature.PRIMITIVE_CLASSES.allowedInSource(source);
this.allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
Feature.VALUE_CLASSES.allowedInSource(source);
}

protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
Expand Down Expand Up @@ -239,6 +241,10 @@ protected DocCommentTable newDocCommentTable(boolean keepDocComments, ParserFact
*/
boolean allowPrimitiveClasses;

/** Switch: are value classes allowed in this source level?
*/
boolean allowValueClasses;

/** Switch: are sealed types allowed in this source level?
*/
boolean allowSealedTypes;
Expand Down Expand Up @@ -2371,7 +2377,7 @@ JCExpression creator(int newpos, List<JCExpression> typeArgs) {
case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
case DOUBLE: case BOOLEAN:
if (mods.flags != 0) {
long badModifiers = (mods.flags & Flags.PRIMITIVE_CLASS) != 0 ? mods.flags & ~Flags.FINAL : mods.flags;
long badModifiers = (mods.flags & (Flags.PRIMITIVE_CLASS | Flags.VALUE_CLASS)) != 0 ? mods.flags & ~Flags.FINAL : mods.flags;
log.error(token.pos, Errors.ModNotAllowedHere(asFlagSet(badModifiers)));
}
if (typeArgs == null) {
Expand Down Expand Up @@ -2442,7 +2448,7 @@ else if (typeArgs != null) {
}
return e;
} else if (token.kind == LPAREN) {
long badModifiers = mods.flags & ~(Flags.PRIMITIVE_CLASS | Flags.FINAL);
long badModifiers = mods.flags & ~(Flags.PRIMITIVE_CLASS | Flags.VALUE_CLASS | Flags.FINAL);
if (badModifiers != 0)
log.error(token.pos, Errors.ModNotAllowedHere(asFlagSet(badModifiers)));
// handle type annotations for instantiations and anonymous classes
Expand All @@ -2451,7 +2457,7 @@ else if (typeArgs != null) {
}
JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t, mods.flags);
if ((newClass.def == null) && (mods.flags != 0)) {
badModifiers = (mods.flags & Flags.PRIMITIVE_CLASS) != 0 ? mods.flags & ~Flags.FINAL : mods.flags;
badModifiers = (mods.flags & (Flags.PRIMITIVE_CLASS | Flags.VALUE_CLASS)) != 0 ? mods.flags & ~Flags.FINAL : mods.flags;
log.error(newClass.pos, Errors.ModNotAllowedHere(asFlagSet(badModifiers)));
}
return newClass;
Expand Down Expand Up @@ -2802,7 +2808,7 @@ List<JCStatement> blockStatement() {
}
}
}
if (isPrimitiveModifier()) {
if ((isPrimitiveModifier() && allowPrimitiveClasses) || isValueModifier() && allowValueClasses) {
dc = token.comment(CommentStyle.JAVADOC);
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
}
Expand Down Expand Up @@ -3346,6 +3352,10 @@ protected JCModifiers modifiersOpt(JCModifiers partial) {
flag = Flags.PRIMITIVE_CLASS;
break;
}
if (isValueModifier()) {
flag = Flags.VALUE_CLASS;
break;
}
break loop;
}
default: break loop;
Expand All @@ -3362,6 +3372,8 @@ protected JCModifiers modifiersOpt(JCModifiers partial) {
final Name name = TreeInfo.name(ann.annotationType);
if (name == names.__primitive__ || name == names.java_lang___primitive__) {
flag = Flags.PRIMITIVE_CLASS;
} else if (name == names.__value__ || name == names.java_lang___value__) {
flag = Flags.VALUE_CLASS;
} else {
annotations.append(ann);
flag = 0;
Expand All @@ -3386,6 +3398,11 @@ protected JCModifiers modifiersOpt(JCModifiers partial) {
flags |= Flags.FINAL;
}

// Force value classes to be automatically final.
if ((flags & (Flags.VALUE_CLASS | Flags.ABSTRACT | Flags.INTERFACE | Flags.ENUM)) == Flags.VALUE_CLASS) {
flags |= Flags.FINAL;
}

JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList());
if (pos != Position.NOPOS)
storeEnd(mods, S.prevToken().endPos);
Expand Down Expand Up @@ -3612,9 +3629,16 @@ Source restrictedTypeNameStartingAtSource(Name name, int pos, boolean shouldWarn
}
if (name == names.primitive) {
if (allowPrimitiveClasses) {
return Source.JDK17;
return Source.JDK18;
} else if (shouldWarn) {
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK17));
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK18));
}
}
if (name == names.value) {
if (allowValueClasses) {
return Source.JDK18;
} else if (shouldWarn) {
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK18));
}
}
if (name == names.sealed) {
Expand Down Expand Up @@ -4508,16 +4532,50 @@ protected boolean isNonSealedIdentifier(Token someToken, int lookAheadOffset) {
}

protected boolean isPrimitiveModifier() {
if (allowPrimitiveClasses && token.kind == IDENTIFIER && token.name() == names.primitive) {
if (token.kind == IDENTIFIER && token.name() == names.primitive) {
boolean isPrimitiveModifier = false;
Token next = S.token(1);
switch (next.kind) {
case PRIVATE: case PROTECTED: case PUBLIC: case STATIC: case TRANSIENT:
case FINAL: case ABSTRACT: case NATIVE: case VOLATILE: case SYNCHRONIZED:
case STRICTFP: case MONKEYS_AT: case DEFAULT: case BYTE: case SHORT:
case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
case CLASS: case INTERFACE: case ENUM: case IDENTIFIER: // new primitive Comparable() {}
checkSourceLevel(Feature.PRIMITIVE_CLASSES);
return true;
case CLASS: case INTERFACE: case ENUM:
isPrimitiveModifier = true;
break;
case IDENTIFIER: // primitive record R || new primitive Comparable() {}
if (next.name() == names.record || (mode & EXPR) != 0)
isPrimitiveModifier = true;
break;
}
if (isPrimitiveModifier) {
checkSourceLevel(Feature.PRIMITIVE_CLASSES);
return true;
}
}
return false;
}

protected boolean isValueModifier() {
if (token.kind == IDENTIFIER && token.name() == names.value) {
boolean isValueModifier = false;
Token next = S.token(1);
switch (next.kind) {
case PRIVATE: case PROTECTED: case PUBLIC: case STATIC: case TRANSIENT:
case FINAL: case ABSTRACT: case NATIVE: case VOLATILE: case SYNCHRONIZED:
case STRICTFP: case MONKEYS_AT: case DEFAULT: case BYTE: case SHORT:
case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
case CLASS: case INTERFACE: case ENUM:
isValueModifier = true;
break;
case IDENTIFIER: // value record R || new value Comparable() {} ??
if (next.name() == names.record || (mode & EXPR) != 0)
isValueModifier = true;
break;
}
if (isValueModifier) {
checkSourceLevel(Feature.VALUE_CLASSES);
return true;
}
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3912,6 +3912,9 @@ compiler.err.preview.without.source.or.release=\
compiler.misc.feature.primitive.classes=\
primitive classes

compiler.misc.feature.value.classes=\
value classes

# 0: symbol
compiler.err.cyclic.primitive.class.membership=\
cyclic primitive class membership involving {0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public static Names instance(Context context) {
public final Name java_lang_System;
public final Name __primitive__;
public final Name java_lang___primitive__;
public final Name __value__;
public final Name java_lang___value__;
public final Name java_lang_IdentityObject;

// names of builtin classes
Expand Down Expand Up @@ -309,6 +311,8 @@ public Names(Context context) {
java_lang_System = fromString("java.lang.System");
__primitive__ = fromString("__primitive__");
java_lang___primitive__ = fromString("java.lang.__primitive__");
__value__ = fromString("__value__");
java_lang___value__ = fromString("java.lang.__value__");
java_lang_IdentityObject = fromString("java.lang.IdentityObject");

// names of builtin classes
Expand Down
Loading

0 comments on commit 063c1c4

Please sign in to comment.