--- old/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java 2019-04-10 00:45:38.823997000 -0700 +++ new/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java 2019-04-10 00:45:37.979997000 -0700 @@ -46,8 +46,16 @@ // Declared types /** An enum type. */ ENUM, - /** A class not described by a more specific kind (like {@code ENUM}). */ + /** + * A class not described by a more specific kind (like {@code + * ENUM} or {@code RECORD}). + */ CLASS, + /** + * A record type. + * @since 13 + */ + RECORD, /** An annotation type. */ ANNOTATION_TYPE, /** @@ -56,6 +64,13 @@ */ INTERFACE, + // Neither fish nor fowl; necessary? + /** + * A state description of a {@code record}. + * @since 13 + */ + STATE_DESCRIPTION, + // Variables /** An enum constant. */ ENUM_CONSTANT, @@ -106,12 +121,12 @@ /** * Returns {@code true} if this is a kind of class: - * either {@code CLASS} or {@code ENUM}. + * either {@code CLASS} or {@code ENUM} or {@code RECORD}. * * @return {@code true} if this is a kind of class */ public boolean isClass() { - return this == CLASS || this == ENUM; + return this == CLASS || this == ENUM || this == RECORD; } /** --- old/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java 2019-04-10 00:45:40.379997000 -0700 +++ new/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java 2019-04-10 00:45:39.659997000 -0700 @@ -59,6 +59,11 @@ */ DEFAULT, /** The modifier {@code static} */ STATIC, + /** + * The modifier {@code sealed} + * @since amber + */ + SEALED, // Not sure this the best order; certainly after public/private. /** The modifier {@code final} */ FINAL, /** The modifier {@code transient} */ TRANSIENT, /** The modifier {@code volatile} */ VOLATILE, --- old/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java 2019-04-10 00:45:41.843997000 -0700 +++ new/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java 2019-04-10 00:45:41.163997000 -0700 @@ -156,6 +156,38 @@ List getTypeParameters(); /** + * Returns the state description elements of this type element + * in declaration order. + * + * @implSpec The default implementations of this method returns an + * empty and unmodifiable list. + * + * @return the state description elements, or an empty list + * if there are none + * + * @since 13 + */ + default List getStateDescription() { + return List.of(); + } + + /** + * Returns the permitted subtypes of this type element in + * declaration order. + * + * @implSpec The default implementations of this method returns an + * empty and unmodifiable list. + * + * @return the permitted subtypes, or an empty list + * if there are none + * + * @since 13 + */ + default List getPermittedSubtypes() { + return List.of(); + } + + /** * Returns the package of a top-level type and returns the * immediately lexically enclosing element for a {@linkplain * NestingKind#isNested nested} type. --- old/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java 2019-04-10 00:45:43.519997000 -0700 +++ new/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java 2019-04-10 00:45:42.471997000 -0700 @@ -154,6 +154,9 @@ case INTERFACE: return visitTypeAsInterface(e, p); + case RECORD: + return visitTypeAsRecord(e, p); + default: throw new AssertionError("Bad kind " + k + " for TypeElement" + e); } @@ -212,6 +215,21 @@ } /** + * Visits a {@code RECORD} type element. + * + * @implSpec This implementation calls {@code visitUnknown}. + *. + * @param e the element to visit + * @param p a visitor-specified parameter + * @return the result of {@code visitUnknown} + * + * @since 13 + */ + public R visitTypeAsRecord(TypeElement e, P p) { + return visitUnknown(e, p); + } + + /** * Visits a variable element * * @implSpec This implementation dispatches to the visit method for --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java 2019-04-10 00:45:45.371997000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java 2019-04-10 00:45:44.203997000 -0700 @@ -369,6 +369,7 @@ if (0 != (flags & PRIVATE)) modifiers.add(Modifier.PRIVATE); if (0 != (flags & ABSTRACT)) modifiers.add(Modifier.ABSTRACT); if (0 != (flags & STATIC)) modifiers.add(Modifier.STATIC); + if (0 != (flags & SEALED)) modifiers.add(Modifier.SEALED); if (0 != (flags & FINAL)) modifiers.add(Modifier.FINAL); if (0 != (flags & TRANSIENT)) modifiers.add(Modifier.TRANSIENT); if (0 != (flags & VOLATILE)) modifiers.add(Modifier.VOLATILE); --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java 2019-04-10 00:45:47.115997000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java 2019-04-10 00:45:46.187997000 -0700 @@ -1416,6 +1416,8 @@ return ElementKind.INTERFACE; else if ((flags & ENUM) != 0) return ElementKind.ENUM; + else if ((flags & RECORD) != 0) + return ElementKind.RECORD; else return ElementKind.CLASS; } --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java 2019-04-10 00:45:49.055997000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java 2019-04-10 00:45:47.963997000 -0700 @@ -3719,7 +3719,7 @@ if (mods.flags != 0) { log.error(mods.pos, Errors.RecordCantDeclareFieldModifiers); } - mods.flags |= Flags.RECORD | Flags.FINAL; + mods.flags |= Flags.RECORD | Flags.FINAL | Flags.PRIVATE; mods.flags |= (recordClassMods.flags & Flags.ABSTRACT) != 0 ? Flags.PROTECTED : 0; JCExpression type = parseType(); int pos = token.pos; --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java 2019-04-10 00:45:50.811997000 -0700 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java 2019-04-10 00:45:49.895997000 -0700 @@ -39,6 +39,8 @@ import java.io.Writer; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; + import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; @@ -216,6 +218,16 @@ printFormalTypeParameters(e, false); + if (kind == RECORD) { + // Print out state description... + writer.print("("); + writer.print(e.getStateDescription() + .stream() + .map(stateDes -> stateDes.getSimpleName()) + .collect(Collectors.joining(", "))); + writer.print(")"); + } + // Print superclass information if informative if (kind == CLASS) { TypeMirror supertype = e.getSuperclass(); @@ -228,6 +240,7 @@ } printInterfaces(e); + printPermittedSubtypes(e); } writer.println(" {"); indentation++; @@ -255,7 +268,13 @@ for(Element element : enclosedElements) this.visit(element); } else { - for(Element element : e.getEnclosedElements()) + for(Element element : + (kind != RECORD ? + e.getEnclosedElements() : + e.getEnclosedElements() + .stream() + .filter(elt -> elementUtils.getOrigin(elt) != Elements.Origin.EXPLICIT ) + .collect(Collectors.toList()) )) this.visit(element); } @@ -447,6 +466,10 @@ modifiers.remove(Modifier.ABSTRACT); break; + case RECORD: + modifiers.remove(Modifier.FINAL); + break; + case METHOD: case FIELD: Element enclosingElement = e.getEnclosingElement(); @@ -584,6 +607,16 @@ } } + private void printPermittedSubtypes(TypeElement e) { + List subtypes = e.getPermittedSubtypes(); + if (!subtypes.isEmpty()) { // could remove this check with more complicated joining call + writer.print("permits "); + writer.print(Stream.of(subtypes). + map(subtype -> subtype.toString()). + collect(Collectors.joining(", "))); + } + } + private void printThrows(ExecutableElement e) { List thrownTypes = e.getThrownTypes(); final int size = thrownTypes.size();