changeset 49707:3ec295599b1f datum-old

bulk datum development with experimental features
author vromero
date Fri, 06 Apr 2018 13:08:14 -0400
parents 2205fba7d191
children 10a1f1d40b73
files make/autoconf/spec.gmk.in src/java.base/share/classes/java/lang/AbstractRecord.java src/java.base/share/classes/java/lang/annotation/Data.java src/java.base/share/classes/java/lang/compiler/Extractor.java src/java.base/share/classes/java/lang/compiler/ExtractorCarriers.java src/java.base/share/classes/java/lang/compiler/ExtractorImpl.java src/java.base/share/classes/java/lang/compiler/PatternSim.java src/java.base/share/classes/java/lang/compiler/_pattern.java src/java.base/share/classes/java/lang/invoke/ObjectMethodBuilders.java src/java.base/share/classes/module-info.java src/java.compiler/share/classes/javax/lang/model/util/Elements.java src/jdk.compiler/share/classes/com/sun/source/doctree/AccessorTree.java src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.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/AttrContext.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java 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.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/AccessorTaglet.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java test/jdk/java/lang/compiler/ExtractorTest.java test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java test/langtools/jdk/jshell/CompletenessTest.java test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out test/langtools/tools/javac/datum/AllowStaticFieldsInRecordsTest.java test/langtools/tools/javac/datum/BadUseOfRecordTest.java test/langtools/tools/javac/datum/BadUseOfRecordTest.out test/langtools/tools/javac/datum/CheckDatumMembersAccess.java test/langtools/tools/javac/datum/DataClassAsSuper.java test/langtools/tools/javac/datum/DataClassAsSuper.out test/langtools/tools/javac/datum/DataClassTest.java test/langtools/tools/javac/datum/DatumCanNotDeclaredFieldsWithSameName.java test/langtools/tools/javac/datum/DatumCanNotDeclaredFieldsWithSameName.out test/langtools/tools/javac/datum/DatumShouldDeclareAtLeastOneFieldTest.java test/langtools/tools/javac/datum/DatumShouldDeclareAtLeastOneFieldTest.out test/langtools/tools/javac/datum/GuardsInRecordsTest.java test/langtools/tools/javac/datum/Neg01.java test/langtools/tools/javac/datum/Neg01.out test/langtools/tools/javac/datum/Neg02.java test/langtools/tools/javac/datum/Neg02.out test/langtools/tools/javac/datum/Neg03.java test/langtools/tools/javac/datum/Neg03.out test/langtools/tools/javac/datum/NoAddFieldsCanBeDeclaredInDatumTest.java test/langtools/tools/javac/datum/NoAddFieldsCanBeDeclaredInDatumTest.out test/langtools/tools/javac/datum/ParameterLessConstructorsTest.java test/langtools/tools/javac/datum/Pos01.java test/langtools/tools/javac/datum/Pos02.java test/langtools/tools/javac/datum/RecordsMustBeStaticTest.java test/langtools/tools/javac/datum/SubDatumCannotPassDuplicateArgsToSuperTest.java test/langtools/tools/javac/datum/SubDatumCannotPassDuplicateArgsToSuperTest.out test/langtools/tools/javac/datum/SubDatumFieldsMustBeAPrefixOfParentTest.java test/langtools/tools/javac/datum/SubDatumFieldsMustBeAPrefixOfParentTest.out test/langtools/tools/javac/datum/UserDefinedMethodsTest.java test/langtools/tools/javac/diags/examples.not-yet.txt test/langtools/tools/javac/diags/examples/Expected3.java test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java test/langtools/tools/javac/doctree/AccessorsTest.java test/langtools/tools/javac/doctree/DocCommentTester.java test/langtools/tools/javac/enum/EnumMembersOrder.out test/langtools/tools/javac/lib/DPrinter.java test/langtools/tools/javac/parser/JavacParserTest.java test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out test/langtools/tools/javac/parser/extend/TrialParser.java test/langtools/tools/javac/tree/JavacTreeScannerTest.java test/langtools/tools/javac/tree/SourceTreeScannerTest.java test/langtools/tools/javadoc/api/basic/GetTask_DiagListenerTest.java
diffstat 108 files changed, 4813 insertions(+), 400 deletions(-) [+]
line wrap: on
line diff
--- a/make/autoconf/spec.gmk.in	Fri Apr 06 13:05:03 2018 -0400
+++ b/make/autoconf/spec.gmk.in	Fri Apr 06 13:08:14 2018 -0400
@@ -612,6 +612,7 @@
     --add-exports java.base/sun.reflect.annotation=jdk.compiler.interim \
     --add-exports java.base/jdk.internal.jmod=jdk.compiler.interim \
     --add-exports java.base/jdk.internal.misc=jdk.compiler.interim \
+    --add-exports java.base/sun.invoke.util=jdk.compiler.interim \
     #
 INTERIM_LANGTOOLS_MODULES_COMMA := $(strip $(subst $(SPACE),$(COMMA),$(strip \
     $(INTERIM_LANGTOOLS_MODULES))))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/AbstractRecord.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017, 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.Data;
+
+/**
+ * AbstractRecord
+ *
+ * @author Brian Goetz
+ */
+@Data
+public abstract class AbstractRecord {
+
+    @Override
+    public abstract int hashCode();
+
+    @Override
+    public abstract boolean equals(Object obj);
+
+    @Override
+    public abstract String toString();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/annotation/Data.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, 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.annotation;
+
+/**
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Data {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/compiler/Extractor.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import sun.invoke.util.BytecodeName;
+
+import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface;
+import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic;
+import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual;
+import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
+
+/**
+ * Supporting type for implementation of pattern matching.  An {@linkplain Extractor}
+ * is a constant bundle of method handles that describe a particular pattern, and
+ * suitable for storing in the constant pool.
+ *
+ * <p>An {@linkplain Extractor} is describe by a {@code descriptor} in the form
+ * of a {@link MethodType}.  The return value of the descriptor is ignored; the
+ * argument types of the descriptor indicate the types of the output binding
+ * variables.
+ *
+ * @author Brian Goetz
+ */
+public interface Extractor {
+    /**
+     * A method handle that attempts to perform a match.  It will have type
+     * {@code (Object)Object}.  It accepts the target to be matched, and returns
+     * an opaque carrier if the match succeeds, or {@code null} if it fails.
+     *
+     * @return the {@code tryMatch} method handle
+     */
+    MethodHandle tryMatch();
+
+    /**
+     * A method handle that extracts a component from the match carrier.  It
+     * will take the match carrier and return the corresponding match binding.
+     *
+     * @param i the index of the component
+     * @return the {@code component} method handle
+     */
+    MethodHandle component(int i);
+
+    /**
+     * The descriptor of the {@linkplain Extractor}.  The parameter types of
+     * the descriptor are the types of the binding variables.  The return type
+     * is ignored.
+     *
+     * @return the descriptor
+     */
+    MethodType descriptor();
+
+    /**
+     * Compose an extractor with a method handle that receives the bindings
+     *
+     * @param target method handle to receive the bindings
+     * @return the composed method handle
+     */
+    default MethodHandle compose(MethodHandle target) {
+        int count = descriptor().parameterCount();
+        MethodHandle[] components = new MethodHandle[count];
+        int[] reorder = new int[count];
+        for (int i=0; i<count; i++) {
+            components[i] = component(i);
+            reorder[i] = 0;
+        }
+
+        MethodHandle mh = MethodHandles.filterArguments(target, 0, components);
+        mh = MethodHandles.permuteArguments(mh, MethodType.methodType(target.type().returnType(), tryMatch().type().returnType()),
+                                            reorder);
+        mh = MethodHandles.filterArguments(mh, 0, tryMatch());
+        // @@@ What if pattern doesn't match?
+        return mh;
+    }
+
+
+    /**
+     * Create an {@linkplain Extractor} from its components
+     *
+     * @param descriptor the descriptor method type
+     * @param tryMatch the {@code tryMatch} method handle
+     * @param components the {@code components} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor of(MethodType descriptor,
+                               MethodHandle tryMatch,
+                               MethodHandle... components) {
+        return new ExtractorImpl(descriptor, tryMatch, components);
+    }
+
+    /**
+     * Create a lazy, self-carrier {@linkplain Extractor}
+     *
+     * @param descriptor the descriptor method type
+     * @param components the {@code component} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofLazy(MethodType descriptor,
+                                   MethodHandle... components) {
+        return of(descriptor, MethodHandles.identity(descriptor.returnType()), components);
+    }
+
+    /**
+     * Create a lazy, partial, self-carrier {@linkplain Extractor}
+     *
+     * @param descriptor the descriptor method type
+     * @param components the {@code component} method handles
+     * @param predicate a {@link MethodHandle} that accepts the target and returns
+     *                  boolean, indicating whether the pattern matched
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofLazyPartial(MethodType descriptor,
+                                          MethodHandle predicate,
+                                          MethodHandle... components) {
+        Class<?> targetType = descriptor.returnType();
+        MethodHandle tryMatch = MethodHandles.guardWithTest(predicate,
+                                                            MethodHandles.identity(targetType),
+                                                            MethodHandles.dropArguments(MethodHandles.constant(targetType, null), 0, targetType));
+        return of(descriptor, tryMatch, components);
+    }
+
+    /**
+     * Create a partial, self-carrier {@linkplain Extractor}
+     * @param descriptor the descriptor method type
+     * @param copier a {@link MethodHandle} that clones the target
+     * @param predicate a {@link MethodHandle} that accepts the target and returns
+     *                  boolean, indicating whether the pattern matched
+     * @param components the {@code component} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofPartial(MethodType descriptor,
+                                      MethodHandle copier,
+                                      MethodHandle predicate,
+                                      MethodHandle... components) {
+
+        Class<?> targetType = descriptor.returnType();
+        MethodHandle guarded = MethodHandles.guardWithTest(predicate,
+                                                           MethodHandles.identity(targetType),
+                                                           MethodHandles.dropArguments(MethodHandles.constant(targetType, null), 0, targetType));
+        MethodHandle tryMatch = MethodHandles.filterArguments(guarded, 0, copier);
+        return of(descriptor, tryMatch, components);
+    }
+
+    // target digester = (R, MH[CDESC]->Obj) -> Obj, where MH[...] is carrier ctor
+
+    /**
+     * Create a {@linkplain Extractor} using a carrier specified by a descriptor.
+     *
+     * <p>
+     *
+     * @param descriptor the extractor descriptor
+     * @param carrierFactory a method handle to create the carrier from the target
+     * @param digester a {@link MethodHandle} that accepts a target and a carrier
+     *                 factory method handle, and which calls the factory with the
+     *                 values extracted from the target
+     * @param components the {@code component} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofCarrier(MethodType descriptor,
+                                      MethodHandle carrierFactory,
+                                      MethodHandle digester,
+                                      MethodHandle... components) {
+        MethodHandle tryMatch = MethodHandles.insertArguments(digester, 1, carrierFactory);
+        return of(descriptor, tryMatch, components);
+    }
+
+    /**
+     * Create a {@linkplain Extractor} using a carrier specified by a descriptor.
+     *
+     * <p>
+     *
+     * @param descriptor the extractor descriptor
+     * @param carrierFactory a method handle to create the carrier from the target
+     * @param digester a {@link MethodHandle} that accepts a target and a carrier
+     *                 factory method handle, and which calls the factory with the
+     *                 values extracted from the target
+     * @param predicate Predicate, applied to the carrier values, determining
+     *                  whether there was a match
+     * @param components the {@code component} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofCarrierPartial(MethodType descriptor,
+                                             MethodHandle carrierFactory,
+                                             MethodHandle digester,
+                                             MethodHandle predicate,
+                                             MethodHandle... components) {
+        MethodHandle nuller = MethodHandles.constant(Object.class, null);
+        nuller = MethodHandles.dropArguments(nuller, 0, carrierFactory.type().parameterList());
+        MethodHandle guarded = MethodHandles.guardWithTest(predicate, carrierFactory, nuller);
+        MethodHandle tryMatch = MethodHandles.insertArguments(digester, 1, guarded);
+        return of(descriptor, tryMatch, components);
+    }
+
+    /**
+     * Create an {@linkplain Extractor} for a type pattern, with a single binding
+     * variable
+     *
+     * @param type the type to match against
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofType(Class<?> type) {
+        // tryMatch = (t instanceof type) ? t : null
+        // component = (type) o
+        return null;
+    }
+
+    /**
+     * Bootstrap for creating an {@linkplain Extractor} from components
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code Extractor.class}
+     * @param descriptor the descriptor method type
+     * @param tryMatch the {@code tryMatch} method handle
+     * @param components the {@code components} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor of(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                               MethodType descriptor, MethodHandle tryMatch, MethodHandle... components) {
+        return Extractor.of(descriptor, tryMatch, components);
+    }
+
+    /**
+     * Bootstrap for creating a lazy, partial, self-carrier {@linkplain Extractor} from components
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code Extractor.class}
+     * @param descriptor the descriptor method type
+     * @param components the {@code components} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofLazy(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                                   MethodType descriptor, MethodHandle... components) {
+        return Extractor.ofLazy(descriptor, components);
+    }
+
+    /**
+     * Bootstrap for creating a lazy, partial, self-carrier {@linkplain Extractor} from components
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType doc
+     * @param descriptor the descriptor method type
+     * @param components the {@code components} method handles
+     * @return a callsite
+     * @throws Throwable doc
+     */
+    public static CallSite makeLazyExtractor(MethodHandles.Lookup lookup, String constantName, MethodType constantType,
+                                             MethodType descriptor, MethodHandle... components) throws Throwable {
+        return new ConstantCallSite(MethodHandles.constant(Extractor.class, ofLazy(descriptor, components)));
+    }
+
+    /**
+     * Bootstrap for creating a lazy, partial, self-carrier {@linkplain Extractor} from components
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code Extractor.class}
+     * @param descriptor the descriptor method type
+     * @param predicate predicate method handle, applied to target
+     * @param components the {@code components} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofLazyPartial(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                                          MethodType descriptor, MethodHandle predicate, MethodHandle... components) {
+        return ofLazyPartial(descriptor, predicate, components);
+    }
+
+    /**
+     * Bootstrap for creating a lazy, partial, self-carrier {@linkplain Extractor} from components
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code Extractor.class}
+     * @param descriptor the descriptor method type
+     * @param copier a {@link MethodHandle} that clones the target
+     * @param predicate predicate method handle, applied to target
+     * @param components the {@code components} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor ofPartial(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                                      MethodType descriptor, MethodHandle copier, MethodHandle predicate, MethodHandle... components) {
+        return ofPartial(descriptor, copier, predicate, components);
+    }
+
+
+    /**
+     * Create a {@linkplain Extractor} using a carrier specified by a descriptor.
+     *
+     * <p>
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code Extractor.class}
+     * @param descriptor the extractor descriptor
+     * @param carrierFactory a method handle to create the carrier from the target
+     * @param digester a {@link MethodHandle} that accepts a target and a carrier
+     *                 factory method handle, and which calls the factory with the
+     *                 values extracted from the target
+     * @param components the {@code component} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor makeCarrierExtractor(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                                                 MethodType descriptor,
+                                                 MethodHandle carrierFactory,
+                                                 MethodHandle digester,
+                                                 MethodHandle... components) {
+        return ofCarrier(descriptor, carrierFactory, digester, components);
+    }
+
+    /**
+     * Create a {@linkplain Extractor} using a carrier specified by a descriptor.
+     *
+     * <p>
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code Extractor.class}
+     * @param descriptor the extractor descriptor
+     * @param carrierFactory a method handle to create the carrier from the target
+     * @param digester a {@link MethodHandle} that accepts a target and a carrier
+     *                 factory method handle, and which calls the factory with the
+     *                 values extracted from the target
+     * @param predicate Predicate, applied to the carrier values, determining
+     *                  whether there was a match
+     * @param components the {@code component} method handles
+     * @return the {@linkplain Extractor}
+     */
+    public static Extractor makeCarrierPartialExtractor(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                                                        MethodType descriptor,
+                                                        MethodHandle carrierFactory,
+                                                        MethodHandle digester,
+                                                        MethodHandle predicate,
+                                                        MethodHandle... components) {
+        return ofCarrierPartial(descriptor, carrierFactory, digester, predicate, components);
+    }
+
+    /**
+     * Condy bootstrap for creating lazy extractors
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType ignored
+     * @param descriptor the extractor descriptor
+     * @param components the extractor components
+     * @return the extractor factory
+     * @throws Throwable if something went wrong
+     */
+
+    public static Extractor makeLazyExtractor(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                                              MethodType descriptor, MethodHandle... components) throws Throwable {
+        return ofLazy(descriptor, components);
+    }
+
+
+    /**
+     * Condy bootstrap for finding extractors
+     *
+     * @param lookup the lookup context
+     * @param constantName ignored
+     * @param constantType ignored
+     * @param owner the class containing the extractor
+     * @param descriptor the extractor descriptor
+     * @param name the extractor name
+     * @param refKind the kind of method
+     * @return the extractor
+     * @throws Throwable if something went wrong
+     */
+    public static Extractor findExtractor(MethodHandles.Lookup lookup, String constantName, Class<Extractor> constantType,
+                                          Class<?> owner, MethodType descriptor, String name, int refKind) throws Throwable {
+        String dd = descriptor.toMethodDescriptorString();
+        dd = dd.substring(0, dd.indexOf(')') + 1);
+        String patternMethodName
+                = BytecodeName.toBytecodeName(String.format("$pattern$%s$%s",
+                                                            (refKind == REF_newInvokeSpecial ? owner.getSimpleName() : name),
+                                                            dd));
+        MethodType factoryDesc = MethodType.methodType(Extractor.class);
+        MethodHandle mh;
+        switch (refKind) {
+            case REF_invokeStatic:
+            case REF_newInvokeSpecial:
+                mh = lookup.findStatic(owner, patternMethodName, factoryDesc);
+                break;
+            case REF_invokeVirtual:
+            case REF_invokeInterface:
+                mh = lookup.findVirtual(owner, patternMethodName, factoryDesc);
+                break;
+            default:
+                throw new IllegalAccessException(Integer.toString(refKind));
+        }
+
+        return (Extractor) mh.invoke();
+    }
+
+    /**
+     * Bootstrap for extracting the {@code tryMatch} method handle from a {@linkplain Extractor}
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code MethodHandle.class}
+     * @param extractor the {@linkplain Extractor}
+     * @return the {@code tryMatch} method handle
+     */
+
+
+    public static MethodHandle extractorTryMatch(MethodHandles.Lookup lookup, String constantName, Class<MethodHandle> constantType,
+                                                 Extractor extractor) {
+        return extractor.tryMatch();
+    }
+
+    /**
+     * Bootstrap for extracting a {@code component} method handle from a {@linkplain Extractor}
+     *
+     * @param lookup ignored
+     * @param constantName ignored
+     * @param constantType Must be {@code MethodHandle.class}
+     * @param extractor the {@linkplain Extractor}
+     * @param i the component index
+     * @return the {@code component} method handle
+     */
+    public static MethodHandle extractorComponent(MethodHandles.Lookup lookup, String constantName, Class<MethodHandle> constantType,
+                                                  Extractor extractor, int i) {
+        return extractor.component(i);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/compiler/ExtractorCarriers.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+/**
+ * PatternCarriers
+ */
+public class ExtractorCarriers {
+    private static final MethodHandle CARRIER_CTOR;
+    private static final MethodHandle CARRIER_GET;
+    static {
+        try {
+            CARRIER_CTOR = MethodHandles.lookup().findConstructor(DumbCarrier.class, MethodType.methodType(void.class, Object[].class));
+            CARRIER_GET = MethodHandles.lookup().findVirtual(DumbCarrier.class, "get", MethodType.methodType(Object.class, int.class));
+        }
+        catch (ReflectiveOperationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    /**
+     * Returns a method handle with the given method type that instantiates
+     * a new carrier object.
+     *
+     * @param methodType the types of the carrier elements
+     * @return the carrier factory
+     */
+    public static MethodHandle carrierFactory(MethodType methodType) {
+        return CARRIER_CTOR.asType(methodType.changeReturnType(Object.class));
+    }
+
+    /**
+     * Returns a method handle that accepts a carrier and returns the i'th component
+     *
+     * @param methodType the type of the carrier elements
+     * @param i the index of the component
+     * @return the component method handle
+     */
+    public static MethodHandle carrierComponent(MethodType methodType, int i) {
+        return MethodHandles.insertArguments(CARRIER_GET, 1, i)
+                .asType(MethodType.methodType(methodType.parameterType(i), Object.class));
+    }
+
+    static class DumbCarrier {
+        Object[] args;
+
+        DumbCarrier(Object... args) {
+            this.args = args.clone();
+        }
+
+        Object get(int i) {
+            return args[i];
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/compiler/ExtractorImpl.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+import java.util.List;
+
+/**
+ * Non-public implementation of {@link Extractor}
+ */
+class ExtractorImpl implements Extractor {
+    private final MethodHandle tryMatch;
+    private final List<MethodHandle> components;
+    private final MethodType descriptor;
+
+    /**
+     * Construct an {@link Extractor} from components
+     * Constraints:
+     *  - output of tryMatch must match input of components
+     *  - input of tryMatch must match descriptor
+     *  - output of components must match descriptor
+     *
+     * @param descriptor The {@code descriptor} method type
+     * @param tryMatch The {@code tryMatch} method handle
+     * @param components The {@code component} method handles
+     */
+    ExtractorImpl(MethodType descriptor, MethodHandle tryMatch, MethodHandle[] components) {
+        Class<?> carrierType = tryMatch.type().returnType();
+        if (descriptor.parameterCount() != components.length)
+            throw new IllegalArgumentException(String.format("MethodType %s arity should match component count %d", descriptor, components.length));
+        if (!descriptor.returnType().equals(tryMatch.type().parameterType(0)))
+            throw new IllegalArgumentException(String.format("Descriptor %s should match tryMatch input %s", descriptor, tryMatch.type()));
+        for (int i = 0; i < components.length; i++) {
+            MethodHandle component = components[i];
+            if (component.type().parameterCount() != 1
+                || component.type().returnType().equals(void.class)
+                || !component.type().parameterType(0).equals(carrierType))
+                throw new IllegalArgumentException("Invalid component descriptor " + component.type());
+            if (!component.type().returnType().equals(descriptor.parameterType(i)))
+                throw new IllegalArgumentException(String.format("Descriptor %s should match %d'th component %s", descriptor, i, component));
+        }
+
+        this.descriptor = descriptor;
+        this.tryMatch = tryMatch;
+        this.components = List.of(components);
+    }
+
+    @Override
+    public MethodHandle tryMatch() {
+        return tryMatch;
+    }
+
+    @Override
+    public MethodHandle component(int i) {
+        return components.get(i);
+    }
+
+    @Override
+    public MethodType descriptor() {
+        return descriptor;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/compiler/PatternSim.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * Temporary scaffolding to allow matching / switching on constrained patterns
+ * without language support.
+ */
+public class PatternSim {
+    private static String DEFAULT_LABEL = "";
+
+    /**
+     * Simulator for statement switch
+     * @param label the switch label
+     * @param target the switch target
+     * @return the switch simulator
+     */
+    public static StatementSwitch _switch(String label, Object target) {
+        return new SwitchImpl(target, label);
+    }
+
+    /**
+     * Simulator for statement switch
+     * @param target the switch target
+     * @return the switch simulator
+     */
+    public static StatementSwitch _switch(Object target) {
+        return new SwitchImpl(target, DEFAULT_LABEL);
+    }
+
+    /**
+     * Simulator for expression switch
+     * @param label the switch label
+     * @param target the switch target
+     * @param <T> the the return type
+     * @return the switch simulator
+     */
+    public static<T> ExpressionSwitch<T> _expswitch(String label, Object target) {
+        return new ExprSwitchImpl<>(target, label);
+    }
+
+    /**
+     * Simulator for expression switch
+     * @param target the switch target
+     * @param <T> the the return type
+     * @return the switch simulator
+     */
+    public static<T> ExpressionSwitch<T> _expswitch(Object target) {
+        return new ExprSwitchImpl<>(target, DEFAULT_LABEL);
+    }
+
+    /**
+     * Simulator for continuing out of a switch
+     */
+    public static void _continue() {
+        throw new ContinueSignal(DEFAULT_LABEL);
+    }
+
+    /**
+     * Simulator for continuing out of the labeled switch
+     *
+     * @param label the label of the switch to continue at
+     */
+    public static void _continue(String label) {
+        throw new ContinueSignal(label);
+    }
+
+    /**
+     * Simulator type for statement switch
+     */
+    public interface StatementSwitch {
+        /**
+         * Simulate a case of a statement switch
+         * @param pattern the pattern to match against
+         * @param action the success action
+         * @param <B> the type of the binding variable
+         * @return the switch
+         */
+        <B> StatementSwitch _case(Supplier<_pattern<B>> pattern, Consumer<B> action);
+
+        /**
+         * Simulate a case of a statement switch
+         * @param pattern the pattern to match against
+         * @param action the success action
+         * @param <B> the type of the binding variable
+         * @return the switch
+         */
+        <B> StatementSwitch _case(Supplier<_pattern<B>> pattern, Runnable action);
+
+        /**
+         * Simulate the default clause of a statement switch
+         * @param r the action
+         * @return the switch
+         */
+        StatementSwitch _default(Runnable r);
+    }
+
+    /**
+     * Simulator type for expression switch
+     * @param <T> the switch type
+     */
+    public interface ExpressionSwitch<T> {
+        /**
+         * Simulate a case of an expression switch
+         * @param pattern the pattern to match against
+         * @param action the success action
+         * @param <B> the type of the binding variable
+         * @return the switch
+         */
+        <B> ExpressionSwitch<T> _case(Supplier<_pattern<B>> pattern, Function<B, T> action);
+
+        /**
+         * Simulate a case of an expression switch
+         * @param pattern the pattern to match against
+         * @param action the success action
+         * @param <B> the type of the binding variable
+         * @return the switch
+         */
+        <B> ExpressionSwitch<T> _case(Supplier<_pattern<B>> pattern, Supplier<T> action);
+
+        /**
+         * Simulate the default clause of an expression switch
+         * @param r the action
+         * @return the switch
+         */
+        ExpressionSwitch<T> _default(Supplier<T> r);
+
+        /**
+         * Get the result of an expression switch
+         * @return the result
+         */
+        T result();
+    }
+
+    /**
+     * Helper method for nested pattern in a statement switch
+     * @param target the nested target
+     * @param pattern the nested pattern
+     * @param action the success action
+     * @param <B> the type of the nested target
+     */
+    public static<B> void _nest(Object target, Supplier<_pattern<B>> pattern, Consumer<B> action) {
+        Optional<B> match = pattern.get().match(target);
+        if (match.isPresent())
+            action.accept(match.get());
+        else
+            throw new ContinueSignal("<$nested$>");
+    }
+
+    /**
+     * Helper method for nested pattern in a statement switch
+     * @param target the nested target
+     * @param pattern the nested pattern
+     * @param action the success action
+     * @param <B> the type of the nested target
+     */
+    public static<B> void _nest(Object target, Supplier<_pattern<B>> pattern, Runnable action) {
+        Optional<B> match = pattern.get().match(target);
+        if (match.isPresent())
+            action.run();
+        else
+            throw new ContinueSignal("<$nested$>");
+    }
+
+    /**
+     * Helper method for nested pattern in an expression switch
+     * @param target the nested target
+     * @param pattern the nested pattern
+     * @param action the success action
+     * @param <B> the type of the nested target
+     * @param <T> the return type of the success action
+     * @return the return value of the success action
+     */
+    public static<B, T> T _expnest(Object target, Supplier<_pattern<B>> pattern, Function<B, T> action) {
+        Optional<B> match = pattern.get().match(target);
+        if (match.isPresent())
+            return action.apply(match.get());
+        else
+            throw new ContinueSignal("<$nested$>");
+    }
+
+    /**
+     * Helper method for nested pattern in an expression switch
+     * @param target the nested target
+     * @param pattern the nested pattern
+     * @param action the success action
+     * @param <B> the type of the nested target
+     * @param <T> the return type of the success action
+     * @return the return value of the success action
+     */
+    public static<B, T> T _expnest(Object target, Supplier<_pattern<B>> pattern, Supplier<T> action) {
+        Optional<B> match = pattern.get().match(target);
+        if (match.isPresent())
+            return action.get();
+        else
+            throw new ContinueSignal("<$nested$>");
+    }
+
+    @SuppressWarnings("serial")
+    static class ContinueSignal extends RuntimeException {
+        String label;
+
+        ContinueSignal(String label) {
+            super();
+            this.label = label;
+        }
+
+        void maybeRethrow(String label) {
+            if (!this.label.equals(label))
+                throw this;
+        }
+    }
+}
+
+class SwitchImpl implements PatternSim.StatementSwitch {
+    private final Object target;
+    private final String label;
+    private boolean done = false;
+
+    SwitchImpl(Object target,
+               String label) {
+        this.target = target;
+        this.label = label;
+    }
+
+    public <B> PatternSim.StatementSwitch _case(Supplier<_pattern<B>> pattern, Consumer<B> action) {
+        if (!done) {
+            Optional<B> match = pattern.get().match(target);
+            if (match.isPresent()) {
+                try {
+                    action.accept(match.get());
+                    done = true;
+                }
+                catch (PatternSim.ContinueSignal signal) {
+                    signal.maybeRethrow(label);
+                }
+            }
+        }
+        return this;
+    }
+
+    public <B> PatternSim.StatementSwitch _case(Supplier<_pattern<B>> pattern, Runnable action) {
+        if (!done) {
+            Optional<B> match = pattern.get().match(target);
+            if (match.isPresent()) {
+                try {
+                    action.run();
+                    done = true;
+                }
+                catch (PatternSim.ContinueSignal signal) {
+                    signal.maybeRethrow(label);
+                }
+            }
+        }
+        return this;
+    }
+
+    public PatternSim.StatementSwitch _default(Runnable r) {
+        if (!done) {
+            try {
+                r.run();
+                done = true;
+            }
+            catch (PatternSim.ContinueSignal signal) {
+                signal.maybeRethrow(label);
+            }
+        }
+        return this;
+    }
+
+}
+
+class ExprSwitchImpl<T> implements PatternSim.ExpressionSwitch<T> {
+    private final Object target;
+    private final String label;
+    private boolean done = false;
+    private T result = null;
+
+    ExprSwitchImpl(Object target,
+                   String label) {
+        this.target = target;
+        this.label = label;
+    }
+
+    public<B> PatternSim.ExpressionSwitch<T> _case(Supplier<_pattern<B>> pattern, Function<B, T> action) {
+        if (!done) {
+            Optional<B> match = pattern.get().match(target);
+            if (match.isPresent()) {
+                try {
+                    result = action.apply(match.get());
+                    done = true;
+                }
+                catch (PatternSim.ContinueSignal signal) {
+                    signal.maybeRethrow(label);
+                }
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public <B> PatternSim.ExpressionSwitch<T> _case(Supplier<_pattern<B>> pattern, Supplier<T> action) {
+        if (!done) {
+            Optional<B> match = pattern.get().match(target);
+            if (match.isPresent()) {
+                try {
+                    result = action.get();
+                    done = true;
+                }
+                catch (PatternSim.ContinueSignal signal) {
+                    signal.maybeRethrow(label);
+                }
+            }
+        }
+        return this;
+    }
+
+    public PatternSim.ExpressionSwitch<T> _default(Supplier<T> r) {
+        if (!done) {
+            try {
+                result = r.get();
+                done = true;
+            }
+            catch (PatternSim.ContinueSignal signal) {
+                signal.maybeRethrow(label);
+            }
+        }
+        return this;
+    }
+
+    public T result() {
+        return result;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/compiler/_pattern.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, 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.compiler;
+
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Temporary scaffolding to allow declaration of constrained patterns
+ * without language support.
+ */
+public interface _pattern<B> {
+    /**
+     * Attempt to match
+     * @param o the target
+     * @return the result, or an empty optional
+     */
+    Optional<B> match(Object o);
+
+    /**
+     * Construct a PatternDecl for a partial pattern
+     * @param predicate the applicability test
+     * @param extract the extraction logic
+     * @param <T> the type of a successful target
+     * @param <B> the type of the binding
+     * @return the PatternDecl
+     */
+    @SuppressWarnings("unchecked")
+    static<T, B> _pattern<B> of(Predicate<T> predicate, Function<T, B> extract) {
+        return (Object o) ->
+                (predicate.test((T) o))
+                ? Optional.of(extract.apply((T) o))
+                : Optional.empty();
+    }
+
+    /**
+     * Construct a PatternDecl for a total pattern on Object
+     * @param extract the extraction logic
+     * @param <B> the type of the binding
+     * @return the PatternDecl
+     */
+    static<B> _pattern<B> of(Function<?, B> extract) {
+        return of(o -> true, extract);
+    }
+
+    /**
+     * Construct a PatternDecl for a type test pattern
+     * @param clazz The type to test against
+     * @param extract the extraction logic
+     * @param <T> the type of a successful target
+     * @param <B> the type of the binding
+     * @return the PatternDecl
+     */
+    static<T, B> _pattern<B> ofType(Class<T> clazz, Function<T, B> extract) {
+        return of(o -> clazz.isAssignableFrom(o.getClass()),
+                  o -> extract.apply(clazz.cast(o)));
+    }
+
+    /**
+     * Construct a PatternDecl for a type test pattern
+     * @param clazz The type to test against
+     * @param <T> the type of a successful target
+     * @return the PatternDecl
+     */
+    static<T> _pattern<T> ofType(Class<T> clazz) {
+        return of(o -> clazz.isAssignableFrom(o.getClass()), clazz::cast);
+    }
+
+    /**
+     * Construct a PatternDecl for a constant
+     * @param constant the constant
+     * @param <T> the type of the constant
+     * @return the PatternDecl
+     */
+    static<T> _pattern<T> ofConstant(T constant) {
+        return of(constant::equals, o -> constant);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/ObjectMethodBuilders.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2017, 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.invoke;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * ObjectMethodBuilders
+ *
+ * @author Brian Goetz
+ */
+public class ObjectMethodBuilders {
+    private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class);
+    private static final MethodType NAMES_MT = MethodType.methodType(List.class);
+    private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false);
+    private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
+    private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0);
+    private static final MethodHandle CLASS_IS_INSTANCE;
+    private static final MethodHandle OBJECT_EQUALS;
+    private static final MethodHandle OBJECTS_EQUALS;
+    private static final MethodHandle OBJECTS_HASHCODE;
+    private static final MethodHandle OBJECTS_TOSTRING;
+    private static final MethodHandle OBJECT_EQ;
+    private static final MethodHandle OBJECT_HASHCODE;
+    private static final MethodHandle OBJECT_TO_STRING;
+    private static final MethodHandle STRING_FORMAT;
+    private static final MethodHandle HASH_COMBINER;
+
+    private static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();
+    private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
+    private static final HashMap<Class<?>, MethodHandle> primitiveToString = new HashMap<>();
+
+    static {
+        try {
+            MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
+            MethodHandles.Lookup lookup = MethodHandles.Lookup.IMPL_LOOKUP;
+
+            CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance", MethodType.methodType(boolean.class, Object.class));
+            OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class));
+            OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode", MethodType.fromMethodDescriptorString("()I", null));
+            OBJECT_TO_STRING = publicLookup.findVirtual(Object.class, "toString", MethodType.methodType(String.class));
+            STRING_FORMAT = publicLookup.findStatic(String.class, "format", MethodType.methodType(String.class, String.class, Object[].class));
+            OBJECTS_EQUALS = publicLookup.findStatic(Objects.class, "equals", MethodType.methodType(boolean.class, Object.class, Object.class));
+            OBJECTS_HASHCODE = publicLookup.findStatic(Objects.class, "hashCode", MethodType.methodType(int.class, Object.class));
+            OBJECTS_TOSTRING = publicLookup.findStatic(Objects.class, "toString", MethodType.methodType(String.class, Object.class));
+
+            OBJECT_EQ = lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.methodType(boolean.class, Object.class, Object.class));
+            HASH_COMBINER = lookup.findStatic(ObjectMethodBuilders.class, "hashCombiner", MethodType.fromMethodDescriptorString("(II)I", null));
+            primitiveEquals.put(byte.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(BB)Z", null)));
+            primitiveEquals.put(short.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(SS)Z", null)));
+            primitiveEquals.put(char.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(CC)Z", null)));
+            primitiveEquals.put(int.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(II)Z", null)));
+            primitiveEquals.put(long.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(JJ)Z", null)));
+            primitiveEquals.put(float.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(FF)Z", null)));
+            primitiveEquals.put(double.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(DD)Z", null)));
+            primitiveEquals.put(boolean.class, lookup.findStatic(ObjectMethodBuilders.class, "eq", MethodType.fromMethodDescriptorString("(ZZ)Z", null)));
+
+            primitiveHashers.put(byte.class, lookup.findStatic(Byte.class, "hashCode", MethodType.fromMethodDescriptorString("(B)I", null)));
+            primitiveHashers.put(short.class, lookup.findStatic(Short.class, "hashCode", MethodType.fromMethodDescriptorString("(S)I", null)));
+            primitiveHashers.put(char.class, lookup.findStatic(Character.class, "hashCode", MethodType.fromMethodDescriptorString("(C)I", null)));
+            primitiveHashers.put(int.class, lookup.findStatic(Integer.class, "hashCode", MethodType.fromMethodDescriptorString("(I)I", null)));
+            primitiveHashers.put(long.class, lookup.findStatic(Long.class, "hashCode", MethodType.fromMethodDescriptorString("(J)I", null)));
+            primitiveHashers.put(float.class, lookup.findStatic(Float.class, "hashCode", MethodType.fromMethodDescriptorString("(F)I", null)));
+            primitiveHashers.put(double.class, lookup.findStatic(Double.class, "hashCode", MethodType.fromMethodDescriptorString("(D)I", null)));
+            primitiveHashers.put(boolean.class, lookup.findStatic(Boolean.class, "hashCode", MethodType.fromMethodDescriptorString("(Z)I", null)));
+
+            primitiveToString.put(byte.class, lookup.findStatic(Byte.class, "toString", MethodType.methodType(String.class, byte.class)));
+            primitiveToString.put(short.class, lookup.findStatic(Short.class, "toString", MethodType.methodType(String.class, short.class)));
+            primitiveToString.put(char.class, lookup.findStatic(Character.class, "toString", MethodType.methodType(String.class, char.class)));
+            primitiveToString.put(int.class, lookup.findStatic(Integer.class, "toString", MethodType.methodType(String.class, int.class)));
+            primitiveToString.put(long.class, lookup.findStatic(Long.class, "toString", MethodType.methodType(String.class, long.class)));
+            primitiveToString.put(float.class, lookup.findStatic(Float.class, "toString", MethodType.methodType(String.class, float.class)));
+            primitiveToString.put(double.class, lookup.findStatic(Double.class, "toString", MethodType.methodType(String.class, double.class)));
+            primitiveToString.put(boolean.class, lookup.findStatic(Boolean.class, "toString", MethodType.methodType(String.class, boolean.class)));
+        }
+        catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static int hashCombiner(int x, int y) {
+        return x*31 + y;
+    }
+
+    private static boolean eq(Object a, Object b) { return a == b; }
+    private static boolean eq(byte a, byte b) { return a == b; }
+    private static boolean eq(short a, short b) { return a == b; }
+    private static boolean eq(char a, char b) { return a == b; }
+    private static boolean eq(int a, int b) { return a == b; }
+    private static boolean eq(long a, long b) { return a == b; }
+    private static boolean eq(float a, float b) { return Float.compare(a, b) == 0; }
+    private static boolean eq(double a, double b) { return Double.compare(a, b) == 0; }
+    private static boolean eq(boolean a, boolean b) { return a == b; }
+
+    /** Get the method handle for combining two values of a given type */
+    private static MethodHandle equalator(Class<?> clazz) {
+        return (clazz.isPrimitive()
+                ? primitiveEquals.get(clazz)
+                : OBJECTS_EQUALS.asType(MethodType.methodType(boolean.class, clazz, clazz)));
+    }
+
+    /** Get the hasher for a value of a given type */
+    private static MethodHandle hasher(Class<?> clazz) {
+        return (clazz.isPrimitive()
+                ? primitiveHashers.get(clazz)
+                : OBJECTS_HASHCODE.asType(MethodType.methodType(int.class, clazz)));
+    }
+
+    /** Get the stringifier for a value of a given type */
+    private static MethodHandle stringifier(Class<?> clazz) {
+        return (clazz.isPrimitive()
+                ? primitiveToString.get(clazz)
+                : OBJECTS_TOSTRING.asType(MethodType.methodType(String.class, clazz)));
+    }
+
+    /**
+     * Generates a method handle for the {@code equals} method for a given data class
+     * @param receiverClass   the data class
+     * @param getters         the list of getters
+     * @return the method handle
+     */
+    private static MethodHandle makeEquals(Class<?> receiverClass,
+                                          List<MethodHandle> getters) {
+        MethodType rr = MethodType.methodType(boolean.class, receiverClass, receiverClass);
+        MethodType ro = MethodType.methodType(boolean.class, receiverClass, Object.class);
+        MethodHandle instanceFalse = MethodHandles.dropArguments(FALSE, 0, receiverClass, Object.class); // (RO)Z
+        MethodHandle instanceTrue = MethodHandles.dropArguments(TRUE, 0, receiverClass, Object.class); // (RO)Z
+        MethodHandle isSameObject = OBJECT_EQ.asType(ro); // (RO)Z
+        MethodHandle isInstance = MethodHandles.dropArguments(CLASS_IS_INSTANCE.bindTo(receiverClass), 0, receiverClass); // (RO)Z
+        MethodHandle accumulator = MethodHandles.dropArguments(TRUE, 0, receiverClass, receiverClass); // (RR)Z
+
+        for (MethodHandle getter : getters) {
+            MethodHandle equalator = equalator(getter.type().returnType()); // (TT)Z
+            MethodHandle thisFieldEqual = MethodHandles.filterArguments(equalator, 0, getter, getter); // (RR)Z
+            accumulator = MethodHandles.guardWithTest(thisFieldEqual, accumulator, instanceFalse.asType(rr));
+        }
+
+        return MethodHandles.guardWithTest(isSameObject,
+                                           instanceTrue,
+                                           MethodHandles.guardWithTest(isInstance, accumulator.asType(ro), instanceFalse));
+    }
+
+    /**
+     * Generates a method handle for the {@code hashCode} method for a given data class
+     * @param receiverClass   the data class
+     * @param getters         the list of getters
+     * @return the method handle
+     */
+    private static MethodHandle makeHashCode(Class<?> receiverClass,
+                                            List<MethodHandle> getters) {
+        MethodHandle accumulator = MethodHandles.dropArguments(ZERO, 0, receiverClass); // (R)I
+
+        // @@@ Use loop combinator instead?
+        for (MethodHandle getter : getters) {
+            MethodHandle hasher = hasher(getter.type().returnType()); // (T)I
+            MethodHandle hashThisField = MethodHandles.filterArguments(hasher, 0, getter);    // (R)I
+            MethodHandle combineHashes = MethodHandles.filterArguments(HASH_COMBINER, 0, accumulator, hashThisField); // (RR)I
+            accumulator = MethodHandles.permuteArguments(combineHashes, accumulator.type(), 0, 0); // adapt (R)I to (RR)I
+        }
+
+        return accumulator;
+    }
+
+    /**
+     * Generates a method handle for the {@code toString} method for a given data class
+     * @param receiverClass   the data class
+     * @param getters         the list of getters
+     * @param names           the names
+     * @return the method handle
+     */
+    private static MethodHandle makeToString(Class<?> receiverClass,
+                                            List<MethodHandle> getters,
+                                            List<String> names) {
+        // This is a pretty lousy algorithm; we spread the receiver over N places,
+        // apply the N getters, apply N toString operations, and concat the result with String.format
+        // Better to use String.format directly, or delegate to StringConcatFactory
+        // Also probably want some quoting around String components
+
+        assert getters.size() == names.size();
+
+        int[] invArgs = new int[getters.size()];
+        Arrays.fill(invArgs, 0);
+        MethodHandle[] filters = new MethodHandle[getters.size()];
+        StringBuilder sb = new StringBuilder();
+        sb.append(receiverClass.getSimpleName()).append("[");
+        for (int i=0; i<getters.size(); i++) {
+            MethodHandle getter = getters.get(i); // (R)T
+            MethodHandle stringify = stringifier(getter.type().returnType()); // (T)String
+            MethodHandle stringifyThisField = MethodHandles.filterArguments(stringify, 0, getter);    // (R)String
+            filters[i] = stringifyThisField;
+            sb.append(names.get(i)).append("=%s");
+            if (i != getters.size() - 1)
+                sb.append(", ");
+        }
+        sb.append(']');
+        String formatString = sb.toString();
+        MethodHandle formatter = MethodHandles.insertArguments(STRING_FORMAT, 0, formatString)
+                                              .asCollector(String[].class, getters.size()); // (R*)String
+        if (getters.size() == 0) {
+            // Add back extra R
+            formatter = MethodHandles.dropArguments(formatter, 0, receiverClass);
+        }
+        else {
+            MethodHandle filtered = MethodHandles.filterArguments(formatter, 0, filters);
+            formatter = MethodHandles.permuteArguments(filtered, MethodType.methodType(String.class, receiverClass), invArgs);
+        }
+
+        return formatter;
+    }
+
+    /**
+     * Bootstrap method to generate the {@code equals} method for a given data class
+     * @param lookup    the lookup
+     * @param invName   the name
+     * @param invType   the method type
+     * @param dataClass the data class
+     * @param getters   the list of getters
+     * @return a call site
+     * @throws Throwable if any exception is thrown during call site construction
+     */
+    public static CallSite makeEquals(MethodHandles.Lookup lookup, String invName, MethodType invType,
+                                      Class<?> dataClass, MethodHandle... getters) throws Throwable {
+        return new ConstantCallSite(makeEquals(dataClass, List.of(getters)));
+    }
+
+    /**
+     * Bootstrap method to generate the {@code hashCode} method for a given data class
+     * @param lookup    the lookup
+     * @param invName   the name
+     * @param invType   the method type
+     * @param dataClass the data class
+     * @param getters   the list of getters
+     * @return a call site
+     * @throws Throwable if any exception is thrown during call site construction
+     */
+    public static CallSite makeHashCode(MethodHandles.Lookup lookup, String invName, MethodType invType,
+                                        Class<?> dataClass, MethodHandle... getters) throws Throwable {
+        return new ConstantCallSite(makeHashCode(dataClass, List.of(getters)));
+    }
+
+    /**
+     * Bootstrap method to generate the {@code toString} method for a given data class
+     * @param lookup    the lookup
+     * @param invName   the name
+     * @param invType   the method type
+     * @param dataClass the data class
+     * @param names     the list of field names joined into a string, separated by ";"
+     * @param getters   the list of getters
+     * @return a call site
+     * @throws Throwable if any exception is thrown during call site construction
+     */
+    public static CallSite makeToString(MethodHandles.Lookup lookup, String invName, MethodType invType,
+                                        Class<?> dataClass, String names, MethodHandle... getters) throws Throwable {
+        return new ConstantCallSite(makeToString(dataClass, List.of(getters), List.of(names.split(";"))));
+    }
+}
--- a/src/java.base/share/classes/module-info.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/java.base/share/classes/module-info.java	Fri Apr 06 13:08:14 2018 -0400
@@ -79,6 +79,7 @@
     exports java.io;
     exports java.lang;
     exports java.lang.annotation;
+    exports java.lang.compiler;
     exports java.lang.invoke;
     exports java.lang.module;
     exports java.lang.ref;
@@ -128,10 +129,11 @@
     exports javax.security.auth.x500;
     exports javax.security.cert;
 
-
     // additional qualified exports may be inserted at build time
     // see make/gensrc/GenModuleInfo.gmk
 
+    exports sun.invoke.util to
+        jdk.compiler;
     exports com.sun.security.ntlm to
         java.security.sasl;
     exports jdk.internal.jimage to
--- a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java	Fri Apr 06 13:08:14 2018 -0400
@@ -612,4 +612,18 @@
      * @since 1.8
      */
     boolean isFunctionalInterface(TypeElement type);
+
+    /**
+     * Returns the executable element for the getter associated with the given variable element.
+     * @param variableElement the field for which the getter is to be found.
+     * @return the field's getter.
+     */
+    ExecutableElement getterFor(VariableElement variableElement);
+
+    /**
+     * Returns the executable element for the setter associated with the given variable element.
+     * @param variableElement the field for which the setter is to be found.
+     * @return the field's setter.
+     */
+    ExecutableElement setterFor(VariableElement variableElement);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/AccessorTree.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, 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 com.sun.source.doctree;
+
+import java.util.List;
+
+/**
+ *
+ * A tree node for an @getter or @setter block tag.
+ *
+ * <p>
+ * &#064;getter description <br>
+ * &#064;setter description <br>
+ *
+ * @since 1.10
+ */
+public interface AccessorTree extends BlockTagTree {
+    /**
+     * Returns the description of the {@code @getter} or {@code @setter} tag.
+     * @return the description associated with this tag
+     */
+    List<? extends DocTree> getDescription();
+}
--- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java	Fri Apr 06 13:08:14 2018 -0400
@@ -35,6 +35,19 @@
      * Enumerates all kinds of trees.
      */
     enum Kind {
+
+        /**
+         * Used for instances of {@link AccessorTree}
+         * representing an embedded getter JavaDoc.
+         */
+        GETTER("getter"),
+
+        /**
+         * Used for instances of {@link AccessorTree}
+         * representing an embedded getter JavaDoc.
+         */
+        SETTER("setter"),
+
         /**
          * Used for instances of {@link AttributeTree}
          * representing an HTML attribute.
--- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java	Fri Apr 06 13:08:14 2018 -0400
@@ -57,6 +57,14 @@
 public interface DocTreeVisitor<R,P> {
 
     /**
+     * Visits an AaccessorTree node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    R visitAccessor(AccessorTree node, P p);
+
+    /**
      * Visits an AttributeTree node.
      * @param node the node being visited
      * @param p a parameter value
--- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java	Fri Apr 06 13:08:14 2018 -0400
@@ -31,6 +31,7 @@
 import javax.tools.Diagnostic;
 import javax.tools.JavaFileObject;
 
+import com.sun.source.doctree.AccessorTree;
 import com.sun.source.doctree.AttributeTree;
 import com.sun.source.doctree.AttributeTree.ValueKind;
 import com.sun.source.doctree.AuthorTree;
@@ -39,6 +40,7 @@
 import com.sun.source.doctree.DocCommentTree;
 import com.sun.source.doctree.DocRootTree;
 import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.DocTree.Kind;
 import com.sun.source.doctree.DocTypeTree;
 import com.sun.source.doctree.EndElementTree;
 import com.sun.source.doctree.EntityTree;
@@ -234,6 +236,13 @@
     LiteralTree newLiteralTree(TextTree text);
 
     /**
+     * Create a new {@code AccessorTree} object, to represent a {@code @getter} tag.
+     * @param description the content of the tag
+     * @return a {@code AccessorTree} object
+     */
+    AccessorTree newAccessorTree(Kind kind, List<? extends DocTree> description);
+
+    /**
      * Create a new {@code ParamTree} object, to represent a {@code @param } tag.
      * @param isTypeParameter true if this is a type parameter, and false otherwise
      * @param name the parameter being described
--- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java	Fri Apr 06 13:08:14 2018 -0400
@@ -476,6 +476,18 @@
     }
 
     /**
+     * {@inheritDoc} This implementation returns {@code null}.
+     *
+     * @param node  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return the result of scanning
+     */
+    @Override
+    public R visitAccessor(AccessorTree node, P p) {
+        return scan(node.getDescription(), p);
+    }
+
+    /**
      * {@inheritDoc} This implementation scans the children in left to right order.
      *
      * @param node  {@inheritDoc}
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java	Fri Apr 06 13:08:14 2018 -0400
@@ -298,6 +298,18 @@
      * @return  the result of {@code defaultAction}
      */
     @Override
+    public R visitAccessor(AccessorTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    /**
+     * {@inheritDoc} This implementation calls {@code defaultAction}.
+     *
+     * @param node {@inheritDoc}
+     * @param p {@inheritDoc}
+     * @return  the result of {@code defaultAction}
+     */
+    @Override
     public R visitParam(ParamTree node, P p) {
         return defaultAction(node, p);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, 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 com.sun.tools.javac.code;
+
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+
+import java.util.function.Function;
+
+public class Accessors {
+
+    public enum Kind {
+        GET(names -> names.get) {
+            @Override
+            public Type accessorType(Symtab syms, Type type) {
+                return new MethodType(List.nil(), type, List.nil(), syms.methodClass);
+            }
+        },
+        SET(names -> names.set) {
+            @Override
+            public Type accessorType(Symtab syms, Type type) {
+                return new MethodType(List.of(type), syms.voidType, List.nil(), syms.methodClass);
+            }
+        };
+
+        private final Function<Names, Name> nameFunc;
+
+        Kind(Function<Names, Name> nameFunc) {
+            this.nameFunc = nameFunc;
+        }
+
+        public Name name(Names names) {
+            return nameFunc.apply(names);
+        }
+
+        public abstract Type accessorType(Symtab syms, Type type);
+    }
+
+    public static Kind fromName(Name name) {
+        for (Kind k : Kind.values()) {
+            if (k.name(name.table.names).equals(name)) {
+                return k;
+            }
+        }
+        return null;
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Fri Apr 06 13:08:14 2018 -0400
@@ -313,20 +313,33 @@
      */
     public static final long ANONCONSTR_BASED = 1L<<57;
 
+    /**
+     * Flag to indicate that a class is a record. The flag is also used to mark fields that are
+     * part of the state vector of a record.
+     */
+    public static final long RECORD = 1L<<58;
+
+    /**
+     * Flag to indicate that a record field is non-final.
+     */
+    public static final long NON_FINAL = 1L<<59;
+
     /** Modifier masks.
      */
     public static final int
-        AccessFlags           = PUBLIC | PROTECTED | PRIVATE,
-        LocalClassFlags       = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
-        MemberClassFlags      = LocalClassFlags | INTERFACE | AccessFlags,
-        ClassFlags            = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
-        InterfaceVarFlags     = FINAL | STATIC | PUBLIC,
-        VarFlags              = AccessFlags | FINAL | STATIC |
-                                VOLATILE | TRANSIENT | ENUM,
-        ConstructorFlags      = AccessFlags,
-        InterfaceMethodFlags  = ABSTRACT | PUBLIC,
-        MethodFlags           = AccessFlags | ABSTRACT | STATIC | NATIVE |
-                                SYNCHRONIZED | FINAL | STRICTFP;
+        AccessFlags                 = PUBLIC | PROTECTED | PRIVATE,
+        LocalClassFlags             = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
+        LocalRecordFlags            = LocalClassFlags | STATIC,
+        MemberClassFlags            = LocalClassFlags | INTERFACE | AccessFlags,
+        MemberRecordClassFlags      = MemberClassFlags | STATIC,
+        ClassFlags                  = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
+        InterfaceVarFlags           = FINAL | STATIC | PUBLIC,
+        VarFlags                    = AccessFlags | FINAL | STATIC |
+                                      VOLATILE | TRANSIENT | ENUM,
+        ConstructorFlags            = AccessFlags,
+        InterfaceMethodFlags        = ABSTRACT | PUBLIC,
+        MethodFlags                 = AccessFlags | ABSTRACT | STATIC | NATIVE |
+                                      SYNCHRONIZED | FINAL | STRICTFP;
     public static final long
         ExtendedStandardFlags       = (long)StandardFlags | DEFAULT,
         ModifierFlags               = ((long)StandardFlags & ~INTERFACE) | DEFAULT,
@@ -427,7 +440,9 @@
         SYSTEM_MODULE(Flags.SYSTEM_MODULE),
         DEPRECATED_ANNOTATION(Flags.DEPRECATED_ANNOTATION),
         DEPRECATED_REMOVAL(Flags.DEPRECATED_REMOVAL),
-        HAS_RESOURCE(Flags.HAS_RESOURCE);
+        HAS_RESOURCE(Flags.HAS_RESOURCE),
+        RECORD(Flags.RECORD),
+        NON_FINAL(Flags.NON_FINAL);
 
         Flag(long flag) {
             this.value = flag;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Fri Apr 06 13:08:14 2018 -0400
@@ -181,7 +181,8 @@
         DIAMOND_WITH_ANONYMOUS_CLASS_CREATION(JDK9, Fragments.FeatureDiamondAndAnonClass, DiagKind.NORMAL),
         UNDERSCORE_IDENTIFIER(MIN, JDK8),
         PRIVATE_INTERFACE_METHODS(JDK9, Fragments.FeaturePrivateIntfMethods, DiagKind.PLURAL),
-        LOCAL_VARIABLE_TYPE_INFERENCE(JDK10);
+        LOCAL_VARIABLE_TYPE_INFERENCE(JDK10),
+        DATA_CLASSES(JDK10);
 
         enum DiagKind {
             NORMAL,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Fri Apr 06 13:08:14 2018 -0400
@@ -359,6 +359,10 @@
         return (flags_field & DEPRECATED) != 0;
     }
 
+    public boolean isDatum() {
+        return (flags_field & RECORD) != 0;
+    }
+
     public boolean hasDeprecatedAnnotation() {
         return (flags_field & DEPRECATED_ANNOTATION) != 0;
     }
@@ -391,6 +395,10 @@
         return (flags() & INTERFACE) != 0;
     }
 
+    public boolean isAbstract() {
+        return (flags() & ABSTRACT) != 0;
+    }
+
     public boolean isPrivate() {
         return (flags_field & Flags.AccessFlags) == PRIVATE;
     }
@@ -1522,6 +1530,8 @@
          */
         public int adr = -1;
 
+        public List<Pair<Accessors.Kind, MethodSymbol>> accessors = List.nil();
+
         /** Construct a variable symbol, given its flags, name, type and owner.
          */
         public VarSymbol(long flags, Name name, Type type, Symbol owner) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Fri Apr 06 13:08:14 2018 -0400
@@ -159,6 +159,9 @@
     /** Predefined types.
      */
     public final Type objectType;
+    public final Type abstractRecordType;
+    public final Type dataAnnotationType;
+    public final Type objectMethodBuildersType;
     public final Type objectsType;
     public final Type classType;
     public final Type classLoaderType;
@@ -211,6 +214,7 @@
     public final Type documentedType;
     public final Type elementTypeType;
     public final Type functionalInterfaceType;
+    public final Type extractorType;
 
     /** The symbol representing the length field of an array.
      */
@@ -483,6 +487,9 @@
 
         // Enter predefined classes. All are assumed to be in the java.base module.
         objectType = enterClass("java.lang.Object");
+        abstractRecordType = enterClass("java.lang.AbstractRecord");
+        dataAnnotationType = enterClass("java.lang.annotation.Data");
+        objectMethodBuildersType = enterClass("java.lang.invoke.ObjectMethodBuilders");
         objectsType = enterClass("java.util.Objects");
         classType = enterClass("java.lang.Class");
         stringType = enterClass("java.lang.String");
@@ -544,6 +551,7 @@
         lambdaMetafactory = enterClass("java.lang.invoke.LambdaMetafactory");
         stringConcatFactory = enterClass("java.lang.invoke.StringConcatFactory");
         functionalInterfaceType = enterClass("java.lang.FunctionalInterface");
+        extractorType = enterClass("java.lang.compiler.Extractor");
 
         synthesizeEmptyInterfaceIfMissing(autoCloseableType);
         synthesizeEmptyInterfaceIfMissing(cloneableType);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Fri Apr 06 13:08:14 2018 -0400
@@ -1468,6 +1468,19 @@
 
     // </editor-fold>
 
+    public List<VarSymbol> recordVars(Type t) {
+        List<VarSymbol> vars = List.nil();
+        while (!t.hasTag(NONE)) {
+            if (t.hasTag(CLASS)) {
+                for (Symbol s : t.tsym.members().getSymbols(s -> s.kind == VAR && (s.flags() & RECORD) != 0)) {
+                    vars = vars.prepend((VarSymbol)s);
+                }
+            }
+            t = supertype(t);
+        }
+        return vars;
+    }
+
     // <editor-fold defaultstate="collapsed" desc="Contains Type">
     public boolean containedBy(Type t, Type s) {
         switch (t.getTag()) {
@@ -5143,7 +5156,7 @@
             append('>');
         }
 
-        private void assembleSig(List<Type> types) {
+        public void assembleSig(List<Type> types) {
             for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail) {
                 assembleSig(ts.head);
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Apr 06 13:08:14 2018 -0400
@@ -26,6 +26,7 @@
 package com.sun.tools.javac.comp;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 import javax.lang.model.element.ElementKind;
 import javax.tools.JavaFileObject;
@@ -1072,12 +1073,11 @@
                 if (tree.name == names.init && owner.type != syms.objectType) {
                     JCBlock body = tree.body;
                     if (body.stats.isEmpty() ||
-                            !TreeInfo.isSelfCall(body.stats.head)) {
-                        body.stats = body.stats.
-                                prepend(typeEnter.SuperCall(make.at(body.pos),
-                                        List.nil(),
-                                        List.nil(),
-                                        false));
+                            !TreeInfo.hasConstructorInvocation(body.stats, names,
+                                    (env.enclClass.sym.flags() & RECORD) != 0)) {
+                        JCStatement supCall = make.at(body.pos).Exec(make.Apply(List.nil(),
+                                make.Ident(names._super), make.Idents(List.nil())));
+                        body.stats = body.stats.prepend(supCall);
                     } else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
                             (tree.mods.flags & GENERATEDCONSTR) == 0 &&
                             TreeInfo.isSuperCall(body.stats.head)) {
@@ -1911,85 +1911,80 @@
 
         ListBuffer<Type> argtypesBuf = new ListBuffer<>();
         if (isConstructorCall) {
-            // We are seeing a ...this(...) or ...super(...) call.
-            // Check that this is the first statement in a constructor.
-            if (checkFirstConstructorStat(tree, env)) {
-
-                // Record the fact
-                // that this is a constructor call (using isSelfCall).
-                localEnv.info.isSelfCall = true;
-
-                // Attribute arguments, yielding list of argument types.
-                KindSelector kind = attribArgs(KindSelector.MTH, tree.args, localEnv, argtypesBuf);
-                argtypes = argtypesBuf.toList();
-                typeargtypes = attribTypes(tree.typeargs, localEnv);
-
-                // Variable `site' points to the class in which the called
-                // constructor is defined.
-                Type site = env.enclClass.sym.type;
-                if (methName == names._super) {
-                    if (site == syms.objectType) {
-                        log.error(tree.meth.pos(), Errors.NoSuperclass(site));
-                        site = types.createErrorType(syms.objectType);
-                    } else {
-                        site = types.supertype(site);
+            // Record the fact
+            // that this is a constructor call (using isSelfCall).
+            localEnv.info.isSelfCall = true;
+
+            // Attribute arguments, yielding list of argument types.
+            KindSelector kind = attribArgs(KindSelector.MTH, tree.args, localEnv, argtypesBuf);
+            argtypes = argtypesBuf.toList();
+            typeargtypes = attribTypes(tree.typeargs, localEnv);
+
+            // Variable `site' points to the class in which the called
+            // constructor is defined.
+            Type site = env.enclClass.sym.type;
+            if (methName == names._super) {
+                if (site == syms.objectType) {
+                    log.error(tree.meth.pos(), Errors.NoSuperclass(site));
+                    site = types.createErrorType(syms.objectType);
+                } else {
+                    site = types.supertype(site);
+                }
+            }
+
+            if (site.hasTag(CLASS)) {
+                Type encl = site.getEnclosingType();
+                while (encl != null && encl.hasTag(TYPEVAR))
+                    encl = encl.getUpperBound();
+                if (encl.hasTag(CLASS)) {
+                    // we are calling a nested class
+
+                    if (tree.meth.hasTag(SELECT)) {
+                        JCTree qualifier = ((JCFieldAccess) tree.meth).selected;
+
+                        // We are seeing a prefixed call, of the form
+                        //     <expr>.super(...).
+                        // Check that the prefix expression conforms
+                        // to the outer instance type of the class.
+                        chk.checkRefType(qualifier.pos(),
+                                         attribExpr(qualifier, localEnv,
+                                                    encl));
+                    } else if (methName == names._super) {
+                        // qualifier omitted; check for existence
+                        // of an appropriate implicit qualifier.
+                        rs.resolveImplicitThis(tree.meth.pos(),
+                                               localEnv, site, true);
                     }
+                } else if (tree.meth.hasTag(SELECT)) {
+                    log.error(tree.meth.pos(),
+                              Errors.IllegalQualNotIcls(site.tsym));
                 }
 
-                if (site.hasTag(CLASS)) {
-                    Type encl = site.getEnclosingType();
-                    while (encl != null && encl.hasTag(TYPEVAR))
-                        encl = encl.getUpperBound();
-                    if (encl.hasTag(CLASS)) {
-                        // we are calling a nested class
-
-                        if (tree.meth.hasTag(SELECT)) {
-                            JCTree qualifier = ((JCFieldAccess) tree.meth).selected;
-
-                            // We are seeing a prefixed call, of the form
-                            //     <expr>.super(...).
-                            // Check that the prefix expression conforms
-                            // to the outer instance type of the class.
-                            chk.checkRefType(qualifier.pos(),
-                                             attribExpr(qualifier, localEnv,
-                                                        encl));
-                        } else if (methName == names._super) {
-                            // qualifier omitted; check for existence
-                            // of an appropriate implicit qualifier.
-                            rs.resolveImplicitThis(tree.meth.pos(),
-                                                   localEnv, site, true);
-                        }
-                    } else if (tree.meth.hasTag(SELECT)) {
-                        log.error(tree.meth.pos(),
-                                  Errors.IllegalQualNotIcls(site.tsym));
-                    }
-
-                    // if we're calling a java.lang.Enum constructor,
-                    // prefix the implicit String and int parameters
-                    if (site.tsym == syms.enumSym)
-                        argtypes = argtypes.prepend(syms.intType).prepend(syms.stringType);
-
-                    // Resolve the called constructor under the assumption
-                    // that we are referring to a superclass instance of the
-                    // current instance (JLS ???).
-                    boolean selectSuperPrev = localEnv.info.selectSuper;
-                    localEnv.info.selectSuper = true;
-                    localEnv.info.pendingResolutionPhase = null;
-                    Symbol sym = rs.resolveConstructor(
-                        tree.meth.pos(), localEnv, site, argtypes, typeargtypes);
-                    localEnv.info.selectSuper = selectSuperPrev;
-
-                    // Set method symbol to resolved constructor...
-                    TreeInfo.setSymbol(tree.meth, sym);
-
-                    // ...and check that it is legal in the current context.
-                    // (this will also set the tree's type)
-                    Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
-                    checkId(tree.meth, site, sym, localEnv,
-                            new ResultInfo(kind, mpt));
-                }
-                // Otherwise, `site' is an error type and we do nothing
+                // if we're calling a java.lang.Enum constructor,
+                // prefix the implicit String and int parameters
+                if (site.tsym == syms.enumSym)
+                    argtypes = argtypes.prepend(syms.intType).prepend(syms.stringType);
+
+                // Resolve the called constructor under the assumption
+                // that we are referring to a superclass instance of the
+                // current instance (JLS ???).
+                boolean selectSuperPrev = localEnv.info.selectSuper;
+                localEnv.info.selectSuper = true;
+                localEnv.info.pendingResolutionPhase = null;
+                Symbol sym = rs.resolveConstructor(
+                    tree.meth.pos(), localEnv, site, argtypes, typeargtypes);
+                localEnv.info.selectSuper = selectSuperPrev;
+
+                // Set method symbol to resolved constructor...
+                TreeInfo.setSymbol(tree.meth, sym);
+
+                // ...and check that it is legal in the current context.
+                // (this will also set the tree's type)
+                Type mpt = newMethodTemplate(resultInfo.pt, argtypes, typeargtypes);
+                checkId(tree.meth, site, sym, localEnv,
+                        new ResultInfo(kind, mpt));
             }
+            // Otherwise, `site' is an error type and we do nothing
             result = tree.type = syms.voidType;
         } else {
             // Otherwise, we are seeing a regular method call.
@@ -4608,6 +4603,44 @@
                     env.info.isSerializable = true;
                 }
 
+                if ((c.flags() & RECORD) != 0) {
+                    Type sup = types.supertype(c.type);
+                    List<JCVariableDecl> superFields = TreeInfo.superRecordFields(env.enclClass);
+                    if (sup.tsym != syms.abstractRecordType.tsym &&
+                            (sup.tsym.flags() & (ABSTRACT | RECORD)) != (ABSTRACT | RECORD)) {
+                        log.error(env.enclClass.extending.pos(), Errors.CantExtendRecord(Fragments.BadRecordSuper));
+                    }
+
+                    if (superFields.nonEmpty()) {
+                        if (c.members().findFirst(names.init, s -> (s.flags() & RECORD) == 0) != null) {
+                            log.error(env.enclClass.extending.pos(), Errors.CantExtendRecord(Fragments.BadSuperFields));
+                        }
+                    }
+
+                    List<VarSymbol> supRecordFields = types.recordVars(sup);
+                    for (JCTree supField : superFields) {
+                        JCVariableDecl supVarDecl = (JCVariableDecl)supField;
+                        if (supRecordFields.isEmpty()) break; //arity mismatches will be checked inside implicit constructor
+                        if (supRecordFields.head.name != supVarDecl.name ||
+                                !types.isSameType(supRecordFields.head.type, supVarDecl.vartype.type)) {
+                            log.error(env.enclClass.extending.pos(),
+                                    Errors.CantExtendRecord(
+                                            Fragments.SuperFieldMismatch(
+                                                    supRecordFields.head.type, supRecordFields.head.name,
+                                                    supVarDecl.vartype.type, supVarDecl.name)));
+                            break;
+                        }
+                        supRecordFields = supRecordFields.tail;
+                    }
+
+                    List<VarSymbol> vars = types.recordVars(c.type).stream()
+                            .filter(v -> v.owner == c)
+                            .collect(List.collector());
+                    env.info.recordImplicitConstructor = new MethodSymbol(0, names.init,
+                            new MethodType(vars.map(v -> v.type), syms.voidType, List.nil(), syms.methodClass),
+                            c);
+                }
+
                 attribClassBody(env, c);
 
                 chk.checkDeprecatedAnnotation(env.tree.pos(), c);
@@ -4725,10 +4758,14 @@
                 (TreeInfo.flags(l.head) & (STATIC | INTERFACE)) != 0) {
                 Symbol sym = null;
                 if (l.head.hasTag(VARDEF)) sym = ((JCVariableDecl) l.head).sym;
-                if (sym == null ||
-                    sym.kind != VAR ||
-                    ((VarSymbol) sym).getConstValue() == null)
-                    log.error(l.head.pos(), Errors.IclsCantHaveStaticDecl(c));
+                // static records are allowed
+                if (!(l.head.hasTag(Tag.CLASSDEF) && (((JCClassDecl)l.head).sym.flags() & Flags.RECORD) != 0)) {
+                    if (sym == null ||
+                        sym.kind != VAR ||
+                        ((VarSymbol) sym).getConstValue() == null) {
+                        log.error(l.head.pos(), Errors.IclsCantHaveStaticDecl(c));
+                    }
+                }
             }
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Fri Apr 06 13:08:14 2018 -0400
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.comp;
 
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.code.*;
@@ -112,6 +113,8 @@
      */
     JCTree preferredTreeForDiagnostics;
 
+    MethodSymbol recordImplicitConstructor;
+
     /** Duplicate this context, replacing scope field and copying all others.
      */
     AttrContext dup(WriteableScope scope) {
@@ -132,6 +135,7 @@
         info.isNewClass = isNewClass;
         info.preferredTreeForDiagnostics = preferredTreeForDiagnostics;
         info.visitingServiceImplementation = visitingServiceImplementation;
+        info.recordImplicitConstructor = recordImplicitConstructor;
         return info;
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Apr 06 13:08:14 2018 -0400
@@ -1170,17 +1170,22 @@
             break;
         case TYP:
             if (sym.isLocal()) {
-                mask = LocalClassFlags;
+                mask = (flags & RECORD) != 0 ? LocalRecordFlags : LocalClassFlags;
                 if ((sym.owner.flags_field & STATIC) == 0 &&
-                    (flags & ENUM) != 0)
+                    (flags & ENUM) != 0) {
                     log.error(pos, Errors.EnumsMustBeStatic);
+                }
+                if ((flags & RECORD) != 0 && (flags & STATIC) == 0) {
+                    log.error(pos, Errors.NestedRecordsMustBeStatic);
+                }
             } else if (sym.owner.kind == TYP) {
-                mask = MemberClassFlags;
+                mask = (flags & RECORD) != 0 ? MemberRecordClassFlags : MemberClassFlags;
                 if (sym.owner.owner.kind == PCK ||
                     (sym.owner.flags_field & STATIC) != 0)
                     mask |= STATIC;
-                else if ((flags & ENUM) != 0)
+                else if ((flags & ENUM) != 0) {
                     log.error(pos, Errors.EnumsMustBeStatic);
+                }
                 // Nested interfaces and enums are always STATIC (Spec ???)
                 if ((flags & (INTERFACE | ENUM)) != 0 ) implicit = STATIC;
             } else {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java	Fri Apr 06 13:08:14 2018 -0400
@@ -399,6 +399,9 @@
             PackageSymbol packge = (PackageSymbol)owner;
             for (Symbol q = packge; q != null && q.kind == PCK; q = q.owner)
                 q.flags_field |= EXISTS;
+            if ((tree.mods.flags & Flags.RECORD) != 0) {
+                tree.mods.flags &= ~Flags.STATIC;
+            }
             c = syms.enterClass(env.toplevel.modle, tree.name, packge);
             packge.members().enterIfAbsent(c);
             if ((tree.mods.flags & PUBLIC) != 0 && !classNameMatchesFileName(c, env)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Apr 06 13:08:14 2018 -0400
@@ -28,6 +28,7 @@
 package com.sun.tools.javac.comp;
 
 import java.util.HashMap;
+import java.util.stream.Collectors;
 
 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
 import com.sun.tools.javac.code.*;
@@ -1888,17 +1889,21 @@
                     if (isInitialConstructor) {
                         boolean isSynthesized = (tree.sym.flags() &
                                                  GENERATEDCONSTR) != 0;
-                        for (int i = firstadr; i < nextadr; i++) {
-                            JCVariableDecl vardecl = vardecls[i];
-                            VarSymbol var = vardecl.sym;
-                            if (var.owner == classDef.sym) {
-                                // choose the diagnostic position based on whether
-                                // the ctor is default(synthesized) or not
-                                if (isSynthesized) {
-                                    checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
-                                        var, Errors.VarNotInitializedInDefaultConstructor(var));
-                                } else {
-                                    checkInit(TreeInfo.diagEndPos(tree.body), var);
+                        boolean isRecord = (tree.sym.owner.flags() & Flags.RECORD) != 0;
+                        // skip record as they are generated by the compiler and guaranteed to be correct
+                        if (!isRecord || !isSynthesized) {
+                            for (int i = firstadr; i < nextadr; i++) {
+                                JCVariableDecl vardecl = vardecls[i];
+                                VarSymbol var = vardecl.sym;
+                                if (var.owner == classDef.sym) {
+                                    // choose the diagnostic position based on whether
+                                    // the ctor is default(synthesized) or not
+                                    if (isSynthesized) {
+                                        checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
+                                            var, Errors.VarNotInitializedInDefaultConstructor(var));
+                                    } else {
+                                        checkInit(TreeInfo.diagEndPos(tree.body), var);
+                                    }
                                 }
                             }
                         }
@@ -2332,6 +2337,11 @@
         public void visitApply(JCMethodInvocation tree) {
             scanExpr(tree.meth);
             scanExprs(tree.args);
+            if (TreeInfo.name(tree.meth) == names._default) {
+                types.recordVars(classDef.type).stream()
+                        .filter(v -> v.owner == classDef.sym)
+                        .forEach(v -> letInit(tree.pos(), v));
+            }
         }
 
         public void visitNewClass(JCNewClass tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Apr 06 13:08:14 2018 -0400
@@ -25,7 +25,10 @@
 
 package com.sun.tools.javac.comp;
 
+import sun.invoke.util.BytecodeName;
+
 import java.util.*;
+import java.util.stream.Collectors;
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Kinds.KindSelector;
@@ -121,6 +124,23 @@
         Options options = Options.instance(context);
         debugLower = options.isSet("debuglower");
         pkginfoOpt = PkgInfo.get(options);
+        String generationSwitch = options.get("generation_switch");
+        if (generationSwitch != null) {
+            if (generationSwitch.equals("all")) {
+                generationSwitchSet = EnumSet.allOf(GenerationSwitch.class);
+            } else {
+                String[] switches = generationSwitch.split(",");
+                for (String s :switches) {
+                    if (s.equals("oldEquals")) {
+                        generationSwitchSet.add(GenerationSwitch.OLD_EQUALS);
+                    } else if (s.equals("oldToString")) {
+                        generationSwitchSet.add(GenerationSwitch.OLD_TOSTRING);
+                    } else if (s.equals("oldHashCode")) {
+                        generationSwitchSet.add(GenerationSwitch.OLD_HASCODE);
+                    }
+                }
+            }
+        }
     }
 
     /** The currently enclosing class.
@@ -2221,6 +2241,10 @@
             (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
             visitEnumDef(tree);
 
+        if ((tree.mods.flags & RECORD) != 0) {
+            visitRecordDef(tree);
+        }
+
         // If this is a nested class, define a this$n field for
         // it and add to proxies.
         JCVariableDecl otdef = null;
@@ -2290,6 +2314,37 @@
         result = make_at(tree.pos()).Block(SYNTHETIC, List.nil());
     }
 
+    List<JCTree> accessors(JCClassDecl tree) {
+        ListBuffer<JCTree> buffer = new ListBuffer<>();
+        tree.defs.stream()
+                .filter(t -> t.hasTag(VARDEF))
+                .map(t -> (JCVariableDecl)t)
+                .filter(vd -> vd.sym.accessors.nonEmpty())
+                .forEach(vd -> {
+                    for (Pair<Accessors.Kind, MethodSymbol> accessor : vd.sym.accessors) {
+                        MethodSymbol accessorSym = accessor.snd;
+                        if ((accessorSym.flags() & Flags.MANDATED) != 0) {
+                            make_at(tree.pos());
+                            switch (accessor.fst) {
+                                case GET:
+                                    buffer.add(make.MethodDef(accessorSym, make.Block(0,
+                                            List.of(make.Return(make.Ident(vd.sym))))));
+                                    break;
+                                case SET:
+                                    buffer.add(make.MethodDef(accessorSym, make.Block(0,
+                                            List.of(make.Exec(
+                                                    make.Assign(make.Ident(vd.sym), make.Ident(accessorSym.params.head))
+                                                            .setType(vd.sym.type))))));
+                                    break;
+                                default:
+                                    Assert.error("Cannot get here!");
+                            }
+                        }
+                    }
+                });
+        return buffer.toList();
+    }
+
     /** Translate an enum class. */
     private void visitEnumDef(JCClassDecl tree) {
         make_at(tree.pos());
@@ -2445,6 +2500,368 @@
             prepend(makeLit(syms.stringType, var.name.toString()));
     }
 
+    /** Translate a record. */
+
+    enum GenerationSwitch {
+        OLD_EQUALS,
+        OLD_HASCODE,
+        OLD_TOSTRING
+    }
+
+    private EnumSet<GenerationSwitch> generationSwitchSet = EnumSet.noneOf(GenerationSwitch.class);
+
+    private void visitRecordDef(JCClassDecl tree) {
+        boolean isAbstract = (tree.mods.flags & ABSTRACT) != 0;
+        make_at(tree.pos());
+        List<VarSymbol> vars = types.recordVars(tree.type);
+        Pool.MethodHandle[] getterMethHandles = new Pool.MethodHandle[vars.size()];
+        int index = 0;
+        for (VarSymbol var : vars) {
+            if (var.owner != tree.sym) {
+                var = new VarSymbol(var.flags_field, var.name, var.type, tree.sym);
+            }
+            getterMethHandles[index] = new Pool.MethodHandle(ClassFile.REF_getField, var, types);
+            index++;
+        }
+
+        tree.defs = tree.defs.appendList(accessors(tree));
+
+        if (!isAbstract) {
+            tree.defs = tree.defs.appendList(List.of(
+                    generationSwitchSet.contains(GenerationSwitch.OLD_EQUALS) ?
+                            recordOldEquals(tree, vars):
+                            recordEquals(tree, getterMethHandles),
+                    generationSwitchSet.contains(GenerationSwitch.OLD_TOSTRING) ?
+                            recordOldToString(tree, vars):
+                            recordToString(tree, vars, getterMethHandles),
+                    generationSwitchSet.contains(GenerationSwitch.OLD_HASCODE) ?
+                            recordOldHashCode(tree, vars):
+                            recordHashCode(tree, getterMethHandles),
+                    recordExtractor(tree, getterMethHandles)
+            ));
+        }
+    }
+
+    JCTree recordToString(JCClassDecl tree, List<VarSymbol> vars, Pool.MethodHandle[] getterMethHandles) {
+        make_at(tree.pos());
+
+        MethodSymbol msym = lookupMethod(tree.pos(),
+                         names.toString,
+                         tree.sym.type,
+                         List.nil());
+        if ((msym.flags() & RECORD) != 0) {
+            Name bootstrapName = names.makeToString;
+            Object[] staticArgsValues = new Object[2 + getterMethHandles.length];
+            staticArgsValues[0] = tree.sym;
+            String concatNames = vars.stream()
+                    .map(v -> v.name)
+                    .collect(Collectors.joining(";", "", ""));
+            staticArgsValues[1] = concatNames;
+            int index = 2;
+            for (Object mho : getterMethHandles) {
+                staticArgsValues[index] = mho;
+                index++;
+            }
+
+            List<Type> staticArgTypes = List.of(syms.classType,
+                    syms.stringType,
+                    new ArrayType(syms.methodHandleType, syms.arrayClass));
+
+            JCFieldAccess qualifier = makeIndyQualifier(syms.objectMethodBuildersType,
+                    tree, msym, staticArgTypes, staticArgsValues, bootstrapName, false);
+
+            VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym);
+
+            JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this)));
+            proxyCall.type = qualifier.type;
+            return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall))));
+        } else {
+            return make.Block(SYNTHETIC, List.nil());
+        }
+    }
+
+    JCTree recordHashCode(JCClassDecl tree, Pool.MethodHandle[] getterMethHandles) {
+        make_at(tree.pos());
+        MethodSymbol msym = lookupMethod(tree.pos(),
+                         names.hashCode,
+                         tree.sym.type,
+                         List.nil());
+        if ((msym.flags() & RECORD) != 0) {
+            Name bootstrapName = names.makeHashCode;
+            Object[] staticArgsValues = new Object[1 + getterMethHandles.length];
+            staticArgsValues[0] = tree.sym;
+            int index = 1;
+            for (Object mho : getterMethHandles) {
+                staticArgsValues[index] = mho;
+                index++;
+            }
+
+            List<Type> staticArgTypes = List.of(syms.classType,
+                    new ArrayType(syms.methodHandleType, syms.arrayClass));
+
+            JCFieldAccess qualifier = makeIndyQualifier(
+                    syms.objectMethodBuildersType, tree, msym,
+                    staticArgTypes, staticArgsValues, bootstrapName,
+                    false);
+
+            VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym);
+
+            JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this)));
+            proxyCall.type = qualifier.type;
+            return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall))));
+        } else {
+            return make.Block(SYNTHETIC, List.nil());
+        }
+    }
+
+    JCTree recordExtractor(JCClassDecl tree, Pool.MethodHandle[] getterMethHandles) {
+        make_at(tree.pos());
+        List<Type> fieldTypes = TreeInfo.types(TreeInfo.recordFields(tree));
+        String argsTypeSig = '(' + argsTypeSig(fieldTypes) + ')';
+        String extractorStr = BytecodeName.toBytecodeName("$pattern$" + tree.sym.name + "$" + argsTypeSig);
+        Name extractorName = names.fromString(extractorStr);
+        // public Extractor extractorName () { return ???; }
+        MethodType extractorMT = new MethodType(List.nil(), syms.extractorType, List.nil(), syms.methodClass);
+        MethodSymbol extractorSym = new MethodSymbol(
+                Flags.PUBLIC | Flags.RECORD | Flags.STATIC,
+                extractorName, extractorMT, tree.sym);
+        tree.sym.members().enter(extractorSym);
+
+        Name bootstrapName = names.makeLazyExtractor;
+        Object[] staticArgsValues = new Object[1 + getterMethHandles.length];
+        /** this method descriptor should have the same arguments as the record constructor and its
+         *  return type should be the same as the type of the record
+         */
+        MethodType mt = new MethodType(fieldTypes, tree.type, List.nil(), syms.methodClass);
+        staticArgsValues[0] = mt;
+        int index = 1;
+        for (Object mho : getterMethHandles) {
+            staticArgsValues[index] = mho;
+            index++;
+        }
+
+        List<Type> staticArgTypes = List.of(syms.methodTypeType,
+                new ArrayType(syms.methodHandleType, syms.arrayClass));
+        JCFieldAccess qualifier = makeIndyQualifier(
+                syms.extractorType, tree, extractorSym, staticArgTypes,
+                staticArgsValues, bootstrapName, true);
+
+        JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.nil());
+        proxyCall.type = qualifier.type;
+        return make.MethodDef(extractorSym, make.Block(0, List.of(make.Return(proxyCall))));
+    }
+
+    private String argsTypeSig(List<Type> typeList) {
+        LowerSignatureGenerator sg = new LowerSignatureGenerator();
+        sg.assembleSig(typeList);
+        return sg.toString();
+    }
+
+    /**
+     * Signature Generation
+     */
+    private class LowerSignatureGenerator extends Types.SignatureGenerator {
+
+        /**
+         * An output buffer for type signatures.
+         */
+        StringBuilder sb = new StringBuilder();
+
+        LowerSignatureGenerator() {
+            super(types);
+        }
+
+        @Override
+        protected void append(char ch) {
+            sb.append(ch);
+        }
+
+        @Override
+        protected void append(byte[] ba) {
+            sb.append(new String(ba));
+        }
+
+        @Override
+        protected void append(Name name) {
+            sb.append(name.toString());
+        }
+
+        @Override
+        public String toString() {
+            return sb.toString();
+        }
+    }
+
+    JCTree recordEquals(JCClassDecl tree, Pool.MethodHandle[] getterMethHandles) {
+        make_at(tree.pos());
+        MethodSymbol msym = lookupMethod(tree.pos(),
+                         names.equals,
+                         tree.sym.type,
+                         List.of(syms.objectType));
+
+        if ((msym.flags() & RECORD) != 0) {
+            Name bootstrapName = names.makeEquals;
+            Object[] staticArgsValues = new Object[1 + getterMethHandles.length];
+            staticArgsValues[0] = tree.sym;
+            int index = 1;
+            for (Object mho : getterMethHandles) {
+                staticArgsValues[index] = mho;
+                index++;
+            }
+
+            List<Type> staticArgTypes = List.of(syms.classType,
+                    new ArrayType(syms.methodHandleType, syms.arrayClass));
+
+            JCFieldAccess qualifier = makeIndyQualifier(
+                    syms.objectMethodBuildersType, tree, msym,
+                    staticArgTypes, staticArgsValues, bootstrapName, false);
+
+            VarSymbol o = msym.params.head;
+            o.adr = 0;
+            VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym);
+
+            JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this), make.Ident(o)));
+            proxyCall.type = qualifier.type;
+            return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall))));
+        } else {
+            return make.Block(SYNTHETIC, List.nil());
+        }
+    }
+
+    JCFieldAccess makeIndyQualifier(
+            Type site,
+            JCClassDecl tree,
+            MethodSymbol msym,
+            List<Type> staticArgTypes,
+            Object[] staticArgValues,
+            Name bootstrapName,
+            boolean isStatic) {
+        List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                syms.stringType,
+                syms.methodTypeType).appendList(staticArgTypes);
+
+        Symbol bsm = rs.resolveInternalMethod(tree.pos(), attrEnv, site,
+                bootstrapName, bsm_staticArgs, List.nil());
+
+        MethodType indyType = msym.type.asMethodType();
+        indyType = new MethodType(
+                isStatic ? List.nil() : indyType.argtypes.prepend(tree.sym.type),
+                indyType.restype,
+                indyType.thrown,
+                syms.methodClass
+        );
+        DynamicMethodSymbol dynSym = new DynamicMethodSymbol(bootstrapName,
+                syms.noSymbol,
+                ClassFile.REF_invokeStatic,
+                (MethodSymbol)bsm,
+                indyType,
+                staticArgValues);
+        JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bootstrapName);
+        qualifier.sym = dynSym;
+        qualifier.type = msym.type.asMethodType().restype;
+        return qualifier;
+    }
+
+    JCTree recordOldToString(JCClassDecl tree, List<VarSymbol> vars) {
+        make_at(tree.pos());
+
+        MethodSymbol toStringSym = lookupMethod(tree.pos(),
+                         names.toString,
+                         tree.sym.type,
+                         List.nil());
+        if ((toStringSym.flags() & RECORD) != 0) {
+            String format = vars.stream()
+                    .map(v -> v.name + "=%s")
+                    .collect(Collectors.joining(", ", tree.name + "[", "]"));
+            JCExpression formatLit = make.Literal(format);
+            JCFieldAccess meth = make.Select(make.Type(syms.stringType), names.fromString("format"));
+            meth.sym = lookupMethod(tree.pos(),
+                    meth.name,
+                    syms.stringType,
+                    List.of(syms.stringType, types.makeArrayType(syms.objectType)));
+            meth.type = meth.sym.type;
+            JCMethodInvocation app = make.Apply(List.nil(), meth,
+                    List.of(formatLit).appendList(vars.map(make::Ident)));
+            app.type = meth.type.getReturnType();
+            app.varargsElement = syms.objectType;
+            return make.MethodDef(toStringSym, make.Block(0, List.of(make.Return(app))));
+        } else {
+            return make.Block(SYNTHETIC, List.nil());
+        }
+    }
+
+    JCTree recordOldHashCode(JCClassDecl tree, List<VarSymbol> vars) {
+        make_at(tree.pos());
+
+        MethodSymbol hashCodeSym = lookupMethod(tree.pos(),
+                         names.hashCode,
+                         tree.sym.type,
+                         List.nil());
+        if ((hashCodeSym.flags() & RECORD) != 0) {
+            JCFieldAccess meth = make.Select(make.Type(syms.objectsType), names.fromString("hash"));
+            meth.sym = lookupMethod(tree.pos(),
+                    meth.name,
+                    syms.objectsType,
+                    List.of(types.makeArrayType(syms.objectType)));
+            meth.type = meth.sym.type;
+            JCMethodInvocation app = make.Apply(List.nil(), meth, vars.map(make::Ident));
+            app.type = meth.type.getReturnType();
+            app.varargsElement = syms.objectType;
+            return make.MethodDef(hashCodeSym, make.Block(0, List.of(make.Return(app))));
+        } else {
+            return make.Block(SYNTHETIC, List.nil());
+        }
+    }
+
+    JCTree recordOldEquals(JCClassDecl tree, List<VarSymbol> vars) {
+        make_at(tree.pos());
+
+        MethodSymbol oldEqualsSym = lookupMethod(tree.pos(),
+                         names.equals,
+                         tree.sym.type,
+                         List.of(syms.objectType));
+
+        if ((oldEqualsSym.flags() & RECORD) != 0) {
+            ListBuffer<JCStatement> trueStats = new ListBuffer<>();
+
+            VarSymbol o = oldEqualsSym.params.head;
+
+            VarSymbol that = new VarSymbol(SYNTHETIC, names.fromString("that" + target.syntheticNameChar()),
+                                                types.erasure(tree.type),
+                                                oldEqualsSym);
+
+            trueStats.add(make.VarDef(that,
+                    make.TypeCast(make.Type(types.erasure(tree.type)),
+                            make.Ident(o)).setType(types.erasure(tree.type))));
+
+            Symbol objectEqualsSym = lookupMethod(tree.pos(),
+                    names.equals,
+                    syms.objectsType,
+                    List.of(syms.objectType, syms.objectType));
+            for (VarSymbol v : vars) {
+                JCFieldAccess meth = make.Select(make.Type(syms.objectsType), names.equals);
+                meth.sym = objectEqualsSym;
+                meth.type = meth.sym.type;
+                JCExpression sel = make.Select(make.Ident(that), v);
+                JCMethodInvocation app = make.Apply(List.nil(), meth, List.of(make.Ident(v), sel));
+                app.type = meth.type.getReturnType();
+                JCUnary neg = make.Unary(Tag.NOT, app);
+                neg.operator = operators.resolveUnary(tree.pos(), Tag.NOT, syms.booleanType);
+                neg.type = neg.operator.getReturnType();
+                trueStats.add(make.If(neg, make.Return(make.Literal(false)), null));
+            }
+            trueStats.add(make.Return(make.Literal(true)));
+
+            JCStatement ifStat = make.If(make.TypeTest(make.Ident(o), make.Type(tree.type)).setType(syms.booleanType),
+                    make.Block(0, trueStats.toList()),
+                    make.Return(make.Literal(false)));
+
+            return make.MethodDef(oldEqualsSym, make.Block(0, List.of(ifStat)));
+        } else {
+            return make.Block(SYNTHETIC, List.nil());
+        }
+    }
+
     public void visitMethodDef(JCMethodDecl tree) {
         if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
@@ -3411,6 +3828,45 @@
         }
     }
 
+    @Override
+    public void visitExec(JCExpressionStatement tree) {
+        if (tree.expr.hasTag(APPLY) &&
+                TreeInfo.name(((JCMethodInvocation)tree.expr).meth) == names._default) {
+            //inline constructor assignments
+            List<VarSymbol> vars = types.recordVars(currentClass.type).stream()
+                            .filter(v -> v.owner == currentClass)
+                            .collect(List.collector());
+            ListBuffer<JCStatement> stats = new ListBuffer<>();
+
+            List<JCExpression> args = ((JCMethodInvocation)tree.expr).args;
+
+            JCRecordDecl recordDecl = (JCRecordDecl)classdefs.get(currentClass);
+            if (recordDecl.guard != null) {
+                MethodSymbol guardSym = lookupMethod(
+                        tree.pos(),
+                        names.guard,
+                        currentClass.type,
+                        vars.map(v -> v.type));
+                JCExpression meth = make.Ident(guardSym);
+                JCMethodInvocation app = make.Apply(null, meth, args);
+                app.type = guardSym.type.asMethodType().restype;
+                JCStatement guardCall = make.Exec(app);
+                stats.add(guardCall);
+            }
+            for (VarSymbol vsym : vars) {
+                stats.add(make.Exec(
+                        make.Assign(make.Select(makeThis(tree, currentClass), vsym), args.head)
+                                .setType(types.erasure(vsym.type))));
+                args = args.tail;
+            }
+            JCTree block = make.Block(0, stats.toList());
+            result = translate(block);
+            return;
+        } else {
+            super.visitExec(tree);
+        }
+    }
+
     public JCTree visitEnumSwitch(JCSwitch tree) {
         TypeSymbol enumSym = tree.selector.type.tsym;
         EnumMapping map = mapForEnum(tree.pos(), enumSym);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Apr 06 13:08:14 2018 -0400
@@ -293,7 +293,8 @@
                 v.setLazyConstValue(initEnv(tree, initEnv), attr, tree);
             }
         }
-        if (chk.checkUnique(tree.pos(), v, enclScope)) {
+        if ((v.flags_field & (HYPOTHETICAL | RECORD)) != (HYPOTHETICAL | RECORD) &&
+                chk.checkUnique(tree.pos(), v, enclScope)) {
             chk.checkTransparentVar(tree.pos(), v, enclScope);
             enclScope.enter(v);
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Apr 06 13:08:14 2018 -0400
@@ -1923,6 +1923,13 @@
                    List<Type> argtypes, List<Type> typeargtypes,
                    boolean allowBoxing, boolean useVarargs) {
         Symbol bestSoFar = methodNotFound;
+
+        if (name == names._default &&
+                env.enclMethod != null &&
+                env.enclMethod.sym.name == names.init) {
+            return env.info.recordImplicitConstructor;
+        }
+
         Env<AttrContext> env1 = env;
         boolean staticOnly = false;
         while (env1.outer != null) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Fri Apr 06 13:08:14 2018 -0400
@@ -54,7 +54,10 @@
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
 import static com.sun.tools.javac.code.TypeTag.ERROR;
+import static com.sun.tools.javac.code.TypeTag.NONE;
+
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
+
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
 import com.sun.tools.javac.util.Dependencies.CompletionCause;
@@ -683,6 +686,8 @@
                                   true, false, false)
                 : (sym.fullname == names.java_lang_Object)
                 ? Type.noType
+                : ((tree.mods.flags & Flags.RECORD) != 0)
+                ? syms.abstractRecordType
                 : syms.objectType;
             }
             ct.supertype_field = modelMissingTypes(baseEnv, supertype, extending, false);
@@ -799,7 +804,7 @@
     private final class HeaderPhase extends AbstractHeaderPhase {
 
         public HeaderPhase() {
-            super(CompletionCause.HEADER_PHASE, new MembersPhase());
+            super(CompletionCause.HEADER_PHASE, new RecordPhase());
         }
 
         @Override
@@ -849,12 +854,10 @@
         }
     }
 
-    /** Enter member fields and methods of a class
-     */
-    private final class MembersPhase extends Phase {
+    private abstract class AbstractMembersPhase extends Phase {
 
-        public MembersPhase() {
-            super(CompletionCause.MEMBERS_PHASE, null);
+        public AbstractMembersPhase(CompletionCause completionCause, Phase next) {
+            super(completionCause, next);
         }
 
         private boolean completing;
@@ -878,6 +881,58 @@
                 completing = prevCompleting;
             }
         }
+    }
+
+    private final class RecordPhase extends AbstractMembersPhase {
+
+        public RecordPhase() {
+            super(CompletionCause.RECORD_PHASE, new MembersPhase());
+        }
+
+        @Override
+        protected void runPhase(Env<AttrContext> env) {
+            JCClassDecl tree = env.enclClass;
+            ClassSymbol sym = tree.sym;
+            if ((sym.flags_field & RECORD) != 0) {
+                List<JCVariableDecl> recordFields = TreeInfo.recordFields(tree);
+                List<JCVariableDecl> superFields = TreeInfo.superRecordFields(tree);
+                memberEnter.memberEnter(recordFields, env);
+                memberEnter.memberEnter(superFields, env);
+                JCRecordDecl recordDecl = (JCRecordDecl)tree;
+                if (recordDecl.guard != null) {
+                    List<VarSymbol> recordSyms = recordFields.map(vd -> vd.sym);
+                    List<Type> argtypes = superFields.map(v -> v.vartype.type).appendList(recordSyms.map(v -> v.type));
+                    MethodType guardMT = new MethodType(argtypes, syms.voidType, List.nil(), syms.methodClass);
+                    MethodSymbol guardMS = new MethodSymbol(PRIVATE | RECORD, names.guard, guardMT, sym);
+
+                    ListBuffer<VarSymbol> params = new ListBuffer<>();
+                    for (JCVariableDecl p : superFields) {
+                        params.add(new VarSymbol(MANDATED | PARAMETER, p.name, p.vartype.type, guardMS));
+                    }
+                    for (VarSymbol p : recordSyms) {
+                        params.add(new VarSymbol(MANDATED | PARAMETER, p.name, p.type, guardMS));
+                    }
+                    guardMS.params = params.toList();
+
+                    JCUnary neg = make.Unary(Tag.NOT, recordDecl.guard);
+                    JCNewClass newException = make.NewClass(null, null,
+                            make.QualIdent(syms.illegalArgumentExceptionType.tsym),
+                            List.of(make.Literal(TypeTag.CLASS, "fields values are not accepted by the given guard")), null);
+                    JCStatement ifStm = make.If(neg, make.Throw(newException), null);
+                    JCMethodDecl guardDecl = make.MethodDef(guardMS, make.Block(0, List.of(ifStm)));
+                    tree.defs = tree.defs.prepend(guardDecl);
+                }
+            }
+        }
+    }
+
+    /** Enter member fields and methods of a class
+     */
+    private final class MembersPhase extends AbstractMembersPhase {
+
+        public MembersPhase() {
+            super(CompletionCause.MEMBERS_PHASE, null);
+        }
 
         @Override
         protected void runPhase(Env<AttrContext> env) {
@@ -888,40 +943,46 @@
             // Add default constructor if needed.
             if ((sym.flags() & INTERFACE) == 0 &&
                 !TreeInfo.hasConstructors(tree.defs)) {
-                List<Type> argtypes = List.nil();
-                List<Type> typarams = List.nil();
-                List<Type> thrown = List.nil();
-                long ctorFlags = 0;
-                boolean based = false;
-                boolean addConstructor = true;
-                JCNewClass nc = null;
+                DefaultConstructorHelper helper = new BasicConstructorHelper(sym);
                 if (sym.name.isEmpty()) {
-                    nc = (JCNewClass)env.next.tree;
+                    JCNewClass nc = (JCNewClass)env.next.tree;
                     if (nc.constructor != null) {
-                        addConstructor = nc.constructor.kind != ERR;
-                        Type superConstrType = types.memberType(sym.type,
-                                                                nc.constructor);
-                        argtypes = superConstrType.getParameterTypes();
-                        typarams = superConstrType.getTypeArguments();
-                        ctorFlags = nc.constructor.flags() & VARARGS;
-                        if (nc.encl != null) {
-                            argtypes = argtypes.prepend(nc.encl.type);
-                            based = true;
+                        if (nc.constructor.kind != ERR) {
+                            helper = new AnonClassConstructorHelper(sym, (MethodSymbol)nc.constructor, nc.encl);
+                        } else {
+                            helper = null;
                         }
-                        thrown = superConstrType.getThrownTypes();
+                    }
+                } else if ((sym.flags() & RECORD) != 0) {
+                    helper = new RecordConstructorHelper(sym, ((JCRecordDecl)tree).guard, TreeInfo.recordFields(tree).map(vd -> vd.sym), TreeInfo.superRecordFields(tree));
+                }
+                if (helper != null) {
+                    JCTree constrDef = defaultConstructor(make.at(tree.pos), helper);
+                    tree.defs = tree.defs.prepend(constrDef);
+                }
+            } else {
+                if ((sym.flags() & RECORD) != 0) {
+                    // there are constructors but they could be incomplete
+                    for (JCTree def : tree.defs) {
+                        if (TreeInfo.isConstructor(def) &&
+                            !TreeInfo.hasConstructorInvocation(((JCMethodDecl)def).body.stats, names, true)) {
+                            RecordConstructorHelper helper = new RecordConstructorHelper(sym,
+                                    ((JCRecordDecl)tree).guard, TreeInfo.recordFields(tree).map(vd -> vd.sym),
+                                    TreeInfo.superRecordFields(tree));
+                            JCMethodDecl methDecl = (JCMethodDecl)def;
+                            JCStatement supCall = make.at(methDecl.body.pos).Exec(make.Apply(List.nil(),
+                                    make.Ident(names._super), make.Idents(helper.superFields)));
+                            methDecl.body.stats = methDecl.body.stats.append(supCall);
+                            ListBuffer<JCStatement> initializations = new ListBuffer<>();
+                            for (Name initName : helper.inits()) {
+                                initializations.add(make.Exec(make.Assign(make.Select(make.Ident(names._this),
+                                        initName), make.Ident(initName))));
+                            }
+                            methDecl.body.stats = methDecl.body.stats.appendList(initializations.toList());
+                        }
                     }
                 }
-                if (addConstructor) {
-                    MethodSymbol basedConstructor = nc != null ?
-                            (MethodSymbol)nc.constructor : null;
-                    JCTree constrDef = DefaultConstructor(make.at(tree.pos), sym,
-                                                        basedConstructor,
-                                                        typarams, argtypes, thrown,
-                                                        ctorFlags, based);
-                    tree.defs = tree.defs.prepend(constrDef);
-                }
             }
-
             // enter symbols for 'this' into current scope.
             VarSymbol thisSym =
                 new VarSymbol(FINAL | HASINIT, names._this, sym.type, sym);
@@ -953,7 +1014,15 @@
                 (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) {
                 addEnumMembers(tree, env);
             }
-            memberEnter.memberEnter(tree.defs, env);
+            List<JCTree> defsToEnter = (tree.sym.flags_field & RECORD) != 0 ?
+                    tree.defs.diff(List.convert(JCTree.class, TreeInfo.recordFields(tree))) : tree.defs;
+            memberEnter.memberEnter(defsToEnter, env);
+            if ((tree.mods.flags & RECORD) != 0) {
+                if ((tree.mods.flags & (RECORD | ABSTRACT)) == RECORD) {
+                    addRecordMembersIfNeeded(tree, env);
+                }
+                addAccessorsIfNeeded(tree, env);
+            }
 
             if (tree.sym.isAnnotationType()) {
                 Assert.check(tree.sym.isCompleted());
@@ -961,6 +1030,37 @@
             }
         }
 
+        /** Add the accessors for fields to the symbol table.
+         */
+        private void addAccessorsIfNeeded(JCClassDecl tree, Env<AttrContext> env) {
+            tree.defs.stream()
+                    .filter(t -> t.hasTag(VARDEF))
+                    .map(t -> (JCVariableDecl)t)
+                    .filter(vd -> vd.accessors != null && vd.accessors.nonEmpty())
+                    .forEach(vd -> addAccessors(vd, env));
+        }
+
+        private void addAccessors(JCVariableDecl tree, Env<AttrContext> env) {
+            for (Pair<Accessors.Kind, Name> accessor : tree.accessors) {
+                Type accessorType = accessor.fst.accessorType(syms, tree.sym.type);
+                Symbol implSym = lookupMethod(env.enclClass.sym, accessor.snd, accessorType.getParameterTypes());
+                if (implSym == null || (implSym.flags_field & MANDATED) != 0) {
+                    JCMethodDecl getter = make.at(tree.pos).MethodDef(make.Modifiers(Flags.PUBLIC | Flags.MANDATED),
+                              accessor.snd,
+                              make.Type(accessorType.getReturnType()),
+                              List.nil(),
+                              accessorType.getParameterTypes().stream()
+                                      .map(ptype -> make.Param(tree.name, tree.sym.type, env.enclClass.sym))
+                                      .collect(List.collector()),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                    memberEnter.memberEnter(getter, env);
+                    tree.sym.accessors = tree.sym.accessors.prepend(new Pair<>(accessor.fst, getter.sym));
+                }
+            }
+        }
+
         /** Add the implicit members for an enum type
          *  to the symbol table.
          */
@@ -995,136 +1095,282 @@
             memberEnter.memberEnter(valueOf, env);
         }
 
+        /** Add the implicit members for a record
+         *  to the symbol table.
+         */
+        private void addRecordMembersIfNeeded(JCClassDecl tree, Env<AttrContext> env) {
+            if (lookupMethod(tree.sym, names.toString, List.nil()) == null) {
+                // public String toString() { return ???; }
+                JCMethodDecl toString = make.
+                    MethodDef(make.Modifiers(Flags.PUBLIC | Flags.RECORD),
+                              names.toString,
+                              make.Type(syms.stringType),
+                              List.nil(),
+                              List.nil(),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                memberEnter.memberEnter(toString, env);
+            }
+
+            if (lookupMethod(tree.sym, names.hashCode, List.nil()) == null) {
+                // public int hashCode() { return ???; }
+                JCMethodDecl hashCode = make.
+                    MethodDef(make.Modifiers(Flags.PUBLIC | Flags.RECORD),
+                              names.hashCode,
+                              make.Type(syms.intType),
+                              List.nil(),
+                              List.nil(),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                memberEnter.memberEnter(hashCode, env);
+            }
+
+            if (lookupMethod(tree.sym, names.equals, List.of(syms.objectType)) == null) {
+                // public boolean equals(Object o) { return ???; }
+                JCMethodDecl equals = make.
+                    MethodDef(make.Modifiers(Flags.PUBLIC | Flags.RECORD),
+                              names.equals,
+                              make.Type(syms.booleanType),
+                              List.nil(),
+                              List.of(make.VarDef(make.Modifiers(Flags.PARAMETER),
+                                                names.fromString("o"),
+                                                make.Type(syms.objectType), null)),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                memberEnter.memberEnter(equals, env);
+            }
+        }
+
+    }
+
+    private Symbol lookupMethod(TypeSymbol tsym, Name name, List<Type> argtypes) {
+        for (Symbol s : tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) {
+            if (types.isSameTypes(s.type.getParameterTypes(), argtypes)) {
+                return s;
+            }
+        }
+        return null;
     }
 
 /* ***************************************************************************
  * tree building
  ****************************************************************************/
 
-    /** Generate default constructor for given class. For classes different
-     *  from java.lang.Object, this is:
-     *
-     *    c(argtype_0 x_0, ..., argtype_n x_n) throws thrown {
-     *      super(x_0, ..., x_n)
-     *    }
-     *
-     *  or, if based == true:
-     *
-     *    c(argtype_0 x_0, ..., argtype_n x_n) throws thrown {
-     *      x_0.super(x_1, ..., x_n)
-     *    }
-     *
-     *  @param make     The tree factory.
-     *  @param c        The class owning the default constructor.
-     *  @param argtypes The parameter types of the constructor.
-     *  @param thrown   The thrown exceptions of the constructor.
-     *  @param based    Is first parameter a this$n?
-     */
-    JCTree DefaultConstructor(TreeMaker make,
-                            ClassSymbol c,
-                            MethodSymbol baseInit,
-                            List<Type> typarams,
-                            List<Type> argtypes,
-                            List<Type> thrown,
-                            long flags,
-                            boolean based) {
-        JCTree result;
-        if ((c.flags() & ENUM) != 0 &&
-            (types.supertype(c.type).tsym == syms.enumSym)) {
-            // constructors of true enums are private
-            flags = (flags & ~AccessFlags) | PRIVATE | GENERATEDCONSTR;
-        } else
-            flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR;
-        if (c.name.isEmpty()) {
-            flags |= ANONCONSTR;
-        }
-        if (based) {
-            flags |= ANONCONSTR_BASED;
-        }
-        Type mType = new MethodType(argtypes, null, thrown, c);
-        Type initType = typarams.nonEmpty() ?
-            new ForAll(typarams, mType) :
-            mType;
-        MethodSymbol init = new MethodSymbol(flags, names.init,
-                initType, c);
-        init.params = createDefaultConstructorParams(make, baseInit, init,
-                argtypes, based);
-        List<JCVariableDecl> params = make.Params(argtypes, init);
-        List<JCStatement> stats = List.nil();
-        if (c.type != syms.objectType) {
-            stats = stats.prepend(SuperCall(make, typarams, params, based));
-        }
-        result = make.MethodDef(init, make.Block(0, stats));
-        return result;
+    interface DefaultConstructorHelper {
+       Type constructorType();
+       MethodSymbol constructorSymbol();
+       Type enclosingType();
+       TypeSymbol owner();
+       List<Name> superArgs();
+       List<Name> inits();
+       default JCExpression guard() {
+           return null;
+       }
     }
 
-    private List<VarSymbol> createDefaultConstructorParams(
-            TreeMaker make,
-            MethodSymbol baseInit,
-            MethodSymbol init,
-            List<Type> argtypes,
-            boolean based) {
-        List<VarSymbol> initParams = null;
-        List<Type> argTypesList = argtypes;
-        if (based) {
-            /*  In this case argtypes will have an extra type, compared to baseInit,
-             *  corresponding to the type of the enclosing instance i.e.:
-             *
-             *  Inner i = outer.new Inner(1){}
-             *
-             *  in the above example argtypes will be (Outer, int) and baseInit
-             *  will have parameter's types (int). So in this case we have to add
-             *  first the extra type in argtypes and then get the names of the
-             *  parameters from baseInit.
-             */
-            initParams = List.nil();
-            VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init);
-            initParams = initParams.append(param);
-            argTypesList = argTypesList.tail;
+    class BasicConstructorHelper implements DefaultConstructorHelper {
+
+        TypeSymbol owner;
+        Type constructorType;
+        MethodSymbol constructorSymbol;
+
+        BasicConstructorHelper(TypeSymbol owner) {
+            this.owner = owner;
         }
-        if (baseInit != null && baseInit.params != null &&
-            baseInit.params.nonEmpty() && argTypesList.nonEmpty()) {
-            initParams = (initParams == null) ? List.nil() : initParams;
-            List<VarSymbol> baseInitParams = baseInit.params;
-            while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) {
-                VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER,
-                        baseInitParams.head.name, argTypesList.head, init);
-                initParams = initParams.append(param);
-                baseInitParams = baseInitParams.tail;
-                argTypesList = argTypesList.tail;
+
+        @Override
+        public Type constructorType() {
+            if (constructorType == null) {
+                constructorType = new MethodType(List.nil(), syms.voidType, List.nil(), syms.methodClass);
             }
+            return constructorType;
         }
-        return initParams;
+
+        @Override
+        public MethodSymbol constructorSymbol() {
+            if (constructorSymbol == null) {
+                long flags;
+                if ((owner().flags() & ENUM) != 0 &&
+                    (types.supertype(owner().type).tsym == syms.enumSym)) {
+                    // constructors of true enums are private
+                    flags = PRIVATE | GENERATEDCONSTR;
+                } else {
+                    flags = (owner().flags() & AccessFlags) | GENERATEDCONSTR;
+                }
+                constructorSymbol = new MethodSymbol(flags, names.init,
+                    constructorType(), owner());
+            }
+            return constructorSymbol;
+        }
+
+        @Override
+        public Type enclosingType() {
+            return Type.noType;
+        }
+
+        @Override
+        public TypeSymbol owner() {
+            return owner;
+        }
+
+        @Override
+        public List<Name> superArgs() {
+            return List.nil();
+        }
+
+        @Override
+        public List<Name> inits() {
+            return List.nil();
+        }
     }
 
-    /** Generate call to superclass constructor. This is:
-     *
-     *    super(id_0, ..., id_n)
-     *
-     * or, if based == true
-     *
-     *    id_0.super(id_1,...,id_n)
-     *
-     *  where id_0, ..., id_n are the names of the given parameters.
-     *
-     *  @param make    The tree factory
-     *  @param params  The parameters that need to be passed to super
-     *  @param typarams  The type parameters that need to be passed to super
-     *  @param based   Is first parameter a this$n?
-     */
-    JCExpressionStatement SuperCall(TreeMaker make,
-                   List<Type> typarams,
-                   List<JCVariableDecl> params,
-                   boolean based) {
-        JCExpression meth;
-        if (based) {
-            meth = make.Select(make.Ident(params.head), names._super);
-            params = params.tail;
-        } else {
-            meth = make.Ident(names._super);
+    class AnonClassConstructorHelper extends BasicConstructorHelper {
+
+        MethodSymbol constr;
+        Type encl;
+        boolean based = false;
+
+        AnonClassConstructorHelper(TypeSymbol owner, MethodSymbol constr, JCExpression encl) {
+            super(owner);
+            this.constr = constr;
+            this.encl = encl != null ? encl.type : Type.noType;
         }
-        List<JCExpression> typeargs = typarams.nonEmpty() ? make.Types(typarams) : null;
-        return make.Exec(make.Apply(typeargs, meth, make.Idents(params)));
+
+        @Override
+        public Type constructorType() {
+            if (constructorType == null) {
+                Type ctype = types.memberType(owner.type, constr);
+                if (!enclosingType().hasTag(NONE)) {
+                    ctype = types.createMethodTypeWithParameters(ctype, ctype.getParameterTypes().prepend(enclosingType()));
+                    based = true;
+                }
+                constructorType = ctype;
+            }
+            return constructorType;
+        }
+
+        @Override
+        public MethodSymbol constructorSymbol() {
+            MethodSymbol csym = super.constructorSymbol();
+            csym.flags_field |= ANONCONSTR | (constr.flags() & VARARGS);
+            csym.flags_field |= based ? ANONCONSTR_BASED : 0;
+            ListBuffer<VarSymbol> params = new ListBuffer<>();
+            List<Type> argtypes = constructorType().getParameterTypes();
+            if (!enclosingType().hasTag(NONE)) {
+                argtypes = argtypes.tail;
+                params = params.prepend(new VarSymbol(PARAMETER, make.paramName(0), enclosingType(), csym));
+            }
+            if (constr.params != null) {
+                for (VarSymbol p : constr.params) {
+                    params.add(new VarSymbol(PARAMETER | p.flags(), p.name, argtypes.head, csym));
+                    argtypes = argtypes.tail;
+                }
+            }
+            csym.params = params.toList();
+            return csym;
+        }
+
+        @Override
+        public Type enclosingType() {
+            return encl;
+        }
+
+        @Override
+        public List<Name> superArgs() {
+            List<JCVariableDecl> params = make.Params(constructorType().getParameterTypes(), constructorSymbol());
+            if (!enclosingType().hasTag(NONE)) {
+                params = params.tail;
+            }
+            return params.map(vd -> vd.name);
+        }
+    }
+
+    class RecordConstructorHelper extends BasicConstructorHelper {
+
+        List<VarSymbol> recordFields;
+        List<JCVariableDecl> superFields;
+        JCExpression guard;
+
+        RecordConstructorHelper(TypeSymbol owner, JCExpression guard, List<VarSymbol> recordFields, List<JCVariableDecl> superFields) {
+            super(owner);
+            this.recordFields = recordFields;
+            this.superFields = superFields;
+            this.guard = guard;
+        }
+
+        @Override
+        public Type constructorType() {
+            if (constructorType == null) {
+                List<Type> argtypes = superFields.map(v -> v.vartype.type)
+                        .appendList(recordFields.map(v -> v.type));
+                constructorType = new MethodType(argtypes, syms.voidType, List.nil(), syms.methodClass);
+            }
+            return constructorType;
+        }
+
+        @Override
+        public MethodSymbol constructorSymbol() {
+            MethodSymbol csym = super.constructorSymbol();
+            ListBuffer<VarSymbol> params = new ListBuffer<>();
+            for (JCVariableDecl p : superFields) {
+                params.add(new VarSymbol(MANDATED | PARAMETER, p.name, p.vartype.type, csym));
+            }
+            for (VarSymbol p : recordFields) {
+                params.add(new VarSymbol(MANDATED | PARAMETER, p.name, p.type, csym));
+            }
+            csym.params = params.toList();
+            csym.flags_field |= RECORD | PUBLIC;
+            return csym;
+        }
+
+        @Override
+        public List<Name> superArgs() {
+            return superFields.map(v -> v.name);
+        }
+
+        @Override
+        public List<Name> inits() {
+            return recordFields.map(v -> v.name);
+        }
+
+        @Override
+        public JCExpression guard() {
+            return guard;
+        }
+    }
+
+    JCTree defaultConstructor(TreeMaker make, DefaultConstructorHelper helper) {
+        Type initType = helper.constructorType();
+        MethodSymbol initSym = helper.constructorSymbol();
+        ListBuffer<JCStatement> stats = new ListBuffer<>();
+        if (helper.owner().type != syms.objectType) {
+            JCExpression meth;
+            if (!helper.enclosingType().hasTag(NONE)) {
+                meth = make.Select(make.Ident(initSym.params.head), names._super);
+            } else {
+                meth = make.Ident(names._super);
+            }
+            List<JCExpression> typeargs = initType.getTypeArguments().nonEmpty() ?
+                    make.Types(initType.getTypeArguments()) : null;
+            JCStatement superCall = make.Exec(make.Apply(typeargs, meth, helper.superArgs().map(make::Ident)));
+            stats.add(superCall);
+        }
+        JCExpression guard = helper.guard();
+        if (guard != null) {
+            JCExpression meth = make.Ident(names.guard);
+            List<JCExpression> args = helper.superArgs().map(make::Ident);
+            args = args.appendList(helper.inits().map(make::Ident));
+            JCStatement guardCall = make.Exec(make.Apply(null, meth, args));
+            stats.add(guardCall);
+        }
+        for (Name initName : helper.inits()) {
+            stats.add(make.Exec(make.Assign(make.Select(make.Ident(names._this), initName), make.Ident(initName))));
+        }
+        JCTree result = make.MethodDef(initSym, make.Block(0, stats.toList()));
+        return result;
     }
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Apr 06 13:08:14 2018 -0400
@@ -1638,7 +1638,9 @@
         }
         ListBuffer<CompoundAnnotationProxy> proxies = new ListBuffer<>();
         for (CompoundAnnotationProxy proxy : annotations) {
-            if (proxy.type.tsym == syms.proprietaryType.tsym)
+            if (proxy.type.tsym == syms.dataAnnotationType.tsym) {
+                    sym.flags_field |= RECORD;
+            } else if (proxy.type.tsym == syms.proprietaryType.tsym)
                 sym.flags_field |= PROPRIETARY;
             else if (proxy.type.tsym == syms.profileType.tsym) {
                 if (profile != Profile.DEFAULT) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Apr 06 13:08:14 2018 -0400
@@ -30,6 +30,7 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
 import com.sun.tools.javac.comp.*;
@@ -2170,6 +2171,13 @@
             this.endPosTable = toplevel.endPositions;
             c.pool = pool;
             pool.reset();
+            if (c.isDatum()) {
+                Attribute.Compound attribute = c.attribute(syms.dataAnnotationType.tsym);
+                if (attribute == null) {
+                    attribute = new Attribute.Compound(syms.dataAnnotationType, List.nil());
+                    c.appendAttributes(List.of(attribute));
+                }
+            }
             /* method normalizeDefs() can add references to external classes into the constant pool
              */
             cdef.defs = normalizeDefs(cdef.defs, c);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Fri Apr 06 13:08:14 2018 -0400
@@ -43,6 +43,7 @@
 import com.sun.source.util.JavacTask;
 import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Accessors.Kind;
 import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.code.Directive.ExportsDirective;
 import com.sun.tools.javac.code.Directive.ExportsFlag;
@@ -786,4 +787,23 @@
             throw new IllegalArgumentException(o.toString());
         return clazz.cast(o);
     }
+
+    @Override
+    public ExecutableElement getterFor(VariableElement variableElement) {
+        return accessorFor(Kind.GET, variableElement);
+    }
+
+    @Override
+    public ExecutableElement setterFor(VariableElement variableElement) {
+        return accessorFor(Kind.SET, variableElement);
+    }
+
+    private ExecutableElement accessorFor(Accessors.Kind kind, VariableElement variableElement) {
+        for (Pair<Accessors.Kind, MethodSymbol> accessor : ((VarSymbol)variableElement).accessors) {
+            if (accessor.fst == kind) {
+                return accessor.snd;
+            }
+        }
+        return null;
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Fri Apr 06 13:08:14 2018 -0400
@@ -30,6 +30,7 @@
 import java.util.Map;
 
 import com.sun.source.doctree.AttributeTree.ValueKind;
+import com.sun.source.doctree.DocTree;
 import com.sun.tools.javac.parser.DocCommentParser.TagParser.Kind;
 import com.sun.tools.javac.parser.Tokens.Comment;
 import com.sun.tools.javac.parser.Tokens.TokenKind;
@@ -1226,6 +1227,12 @@
                 }
             },
 
+            // {@getter text}
+            new AccessorParser(DCTree.Kind.GETTER),
+
+            // {@getter text}
+            new AccessorParser(DCTree.Kind.SETTER),
+
             // @param parameter-name description
             new TagParser(Kind.BLOCK, DCTree.Kind.PARAM) {
                 public DCTree parse(int pos) throws ParseException {
@@ -1409,4 +1416,14 @@
 
     }
 
+    class AccessorParser extends TagParser {
+        AccessorParser(DocTree.Kind kind) {
+            super(Kind.BLOCK, kind, true);
+        }
+
+        public DCTree parse(int pos) throws ParseException {
+            List<DCTree> desc = blockContent();
+            return m.at(pos).newAccessorTree(treeKind, desc);
+        }
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Apr 06 13:08:14 2018 -0400
@@ -96,7 +96,7 @@
     private Source source;
 
     /** The name table. */
-    private Names names;
+    protected Names names;
 
     /** End position mappings container */
     protected final AbstractEndPosTable endPosTable;
@@ -2281,7 +2281,7 @@
         JCClassDecl body = null;
         if (token.kind == LBRACE) {
             int pos = token.pos;
-            List<JCTree> defs = classOrInterfaceBody(names.empty, false);
+            List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
             JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
             body = toP(F.at(pos).AnonymousClassDef(mods, defs));
         }
@@ -2417,8 +2417,17 @@
         //todo: skip to anchor on error(?)
         int pos = token.pos;
         switch (token.kind) {
-        case RBRACE: case CASE: case DEFAULT: case EOF:
+        case RBRACE: case CASE: case EOF:
             return List.nil();
+        case DEFAULT:
+            if (peekToken(COLON)) {
+                return List.nil();
+            } else {
+                accept(DEFAULT);
+                JCExpression t = toP(F.at(pos).Ident(names._default));
+                t = arguments(null, t);
+                return List.of(toP(F.at(pos).Exec(t)));
+            }
         case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY:
         case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK:
         case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
@@ -2431,7 +2440,7 @@
             if (token.kind == INTERFACE ||
                 token.kind == CLASS ||
                 token.kind == ENUM) {
-                return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
+                return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
             } else {
                 JCExpression t = parseType(true);
                 return localVariableDeclarations(mods, t);
@@ -2440,34 +2449,49 @@
         case ABSTRACT: case STRICTFP: {
             Comment dc = token.comment(CommentStyle.JAVADOC);
             JCModifiers mods = modifiersOpt();
-            return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
+            return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
         }
         case INTERFACE:
         case CLASS:
             Comment dc = token.comment(CommentStyle.JAVADOC);
-            return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+            return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
         case ENUM:
             log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.LocalEnum);
             dc = token.comment(CommentStyle.JAVADOC);
-            return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+            return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
         default:
-            Token prevToken = token;
-            JCExpression t = term(EXPR | TYPE);
-            if (token.kind == COLON && t.hasTag(IDENT)) {
-                nextToken();
-                JCStatement stat = parseStatementAsBlock();
-                return List.of(F.at(pos).Labelled(prevToken.name(), stat));
-            } else if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
-                pos = token.pos;
-                JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
-                F.at(pos);
-                return localVariableDeclarations(mods, t);
+            if (token.kind == TokenKind.STATIC) {
+                // we have to check if this is a record declaration
+                Token t1 = S.token(1);
+                Token t2 = S.token(2);
+                Token t3 = S.token(3);
+                if (t1.kind == IDENTIFIER && t1.name() == names.record && t2.kind == IDENTIFIER && t3.kind == LPAREN) {
+                    nextToken();
+                }
+            }
+            if (isRecordDeclaration()) {
+                JCModifiers mods = modifiersOpt();
+                dc = token.comment(CommentStyle.JAVADOC);
+                return List.of(recordDeclaration(mods, dc));
             } else {
-                // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
-                t = checkExprStat(t);
-                accept(SEMI);
-                JCExpressionStatement expr = toP(F.at(pos).Exec(t));
-                return List.of(expr);
+                Token prevToken = token;
+                JCExpression t = term(EXPR | TYPE);
+                if (token.kind == COLON && t.hasTag(IDENT)) {
+                    nextToken();
+                    JCStatement stat = parseStatementAsBlock();
+                    return List.of(F.at(pos).Labelled(prevToken.name(), stat));
+                } else if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
+                    pos = token.pos;
+                    JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
+                    F.at(pos);
+                    return localVariableDeclarations(mods, t);
+                } else {
+                    // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
+                    t = checkExprStat(t);
+                    accept(SEMI);
+                    JCExpressionStatement expr = toP(F.at(pos).Exec(t));
+                    return List.of(expr);
+                }
             }
         }
     }
@@ -2861,6 +2885,19 @@
             case MONKEYS_AT  : flag = Flags.ANNOTATION; break;
             case DEFAULT     : checkSourceLevel(Feature.DEFAULT_METHODS); flag = Flags.DEFAULT; break;
             case ERROR       : flag = 0; nextToken(); break;
+            case IDENTIFIER  : {
+                if (token.name() == names.non && peekToken(0, TokenKind.SUB, TokenKind.FINAL)) {
+                    Token tokenSub = S.token(1);
+                    Token tokenFinal = S.token(2);
+                    if (token.endPos == tokenSub.pos && tokenSub.endPos == tokenFinal.pos) {
+                        flag = Flags.NON_FINAL;
+                        nextToken();
+                        nextToken();
+                        break;
+                    }
+                }
+                break loop;
+            }
             default: break loop;
             }
             if ((flags & flag) != 0) log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
@@ -3092,6 +3129,10 @@
         return Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source) && name == names.var;
     }
 
+    boolean isRestrictedRecordTypeName(Name name) {
+        return Feature.DATA_CLASSES.allowedInSource(source) && name == names.record;
+    }
+
     /** VariableDeclaratorId = Ident BracketsOpt
      */
     JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
@@ -3411,7 +3452,7 @@
             nextToken();
             return toP(F.at(pos).Skip());
         } else {
-            return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
+            return classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
         }
     }
 
@@ -3420,9 +3461,11 @@
      *  @param mods     Any modifiers starting the class or interface declaration
      *  @param dc       The documentation comment for the class, or null.
      */
-    protected JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
+    protected JCStatement classOrRecordOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
         if (token.kind == CLASS) {
             return classDeclaration(mods, dc);
+        } if (isRecordDeclaration()) {
+            return recordDeclaration(mods, dc);
         } else if (token.kind == INTERFACE) {
             return interfaceDeclaration(mods, dc);
         } else if (token.kind == ENUM) {
@@ -3440,7 +3483,7 @@
             if (parseModuleInfo) {
                 erroneousTree = syntaxError(pos, errs, Errors.ExpectedModuleOrOpen);
             } else {
-                erroneousTree = syntaxError(pos, errs, Errors.Expected3(CLASS, INTERFACE, ENUM));
+                erroneousTree = syntaxError(pos, errs, Errors.Expected4(CLASS, INTERFACE, ENUM, RECORD));
             }
             return toP(F.Exec(erroneousTree));
         }
@@ -3468,13 +3511,91 @@
             nextToken();
             implementing = typeList();
         }
-        List<JCTree> defs = classOrInterfaceBody(name, false);
+        List<JCTree> defs = classInterfaceOrRecordBody(name, false, false);
         JCClassDecl result = toP(F.at(pos).ClassDef(
             mods, name, typarams, extending, implementing, defs));
         attach(result, dc);
         return result;
     }
 
+    protected JCClassDecl recordDeclaration(JCModifiers mods, Comment dc) {
+        int pos = token.pos;
+        nextToken();
+        mods.flags |= Flags.RECORD | Flags.STATIC;
+        Name name = typeName();
+
+        List<JCTypeParameter> typarams = typeParametersOpt();
+
+        Map<Name, JCVariableDecl> optHeaderFields = headerFields(mods);
+
+        if (optHeaderFields.size() == 0) {
+            log.error(token.pos, Errors.RecordMustDeclareAtLeastOneField);
+        }
+
+        JCExpression extending = null;
+        Set<Name> superFieldNames = new LinkedHashSet<>();
+        if (token.kind == EXTENDS) {
+            nextToken();
+            extending = parseType();
+            if (token.kind == LPAREN) {
+                accept(LPAREN);
+                while (token.kind != RPAREN) {
+                    Name id = ident();
+                    if (!superFieldNames.contains(id)) {
+                        superFieldNames.add(id);
+                    } else {
+                        log.error(token.pos, Errors.DuplicateArgumentToSuper(id));
+                    }
+                    if (token.kind == COMMA) {
+                        nextToken();
+                    }
+                }
+                accept(RPAREN);
+            }
+        }
+        List<JCExpression> implementing = List.nil();
+        if (token.kind == IMPLEMENTS) {
+            nextToken();
+            implementing = typeList();
+        }
+        List<JCTree> defs = List.nil();
+        if (token.kind == LBRACE) {
+            defs = classInterfaceOrRecordBody(name, false, true);
+        } else {
+            accept(SEMI);
+        }
+        optHeaderFields.values().stream()
+                .filter(t -> superFieldNames.contains(t.name))
+                .forEach(t -> t.getModifiers().flags |= Flags.HYPOTHETICAL);
+        java.util.List<JCVariableDecl> fields = new ArrayList<>();
+        for (Name n : superFieldNames) {
+            JCVariableDecl field = optHeaderFields.get(n);
+            fields.add(field);
+            optHeaderFields.remove(n);
+        }
+        for (JCVariableDecl field : optHeaderFields.values()) {
+            fields.add(field);
+        }
+        for (JCTree def : defs) {
+            if (def.hasTag(METHODDEF)) {
+                JCMethodDecl methDef = (JCMethodDecl) def;
+                if (methDef.name == names.init && methDef.params.isEmpty()) {
+                    ListBuffer<JCVariableDecl> tmpParams = new ListBuffer<>();
+                    for (JCVariableDecl param : fields) {
+                        tmpParams.add(F.at(param).VarDef(F.Modifiers(Flags.PARAMETER), param.name, param.vartype, null));
+                    }
+                    methDef.params = tmpParams.toList();
+                }
+            }
+        }
+        for (int i = fields.size() - 1; i >= 0; i--) {
+            defs = defs.prepend(fields.get(i));
+        }
+        JCRecordDecl result = toP(F.at(pos).RecordDef(mods, name, typarams, extending, implementing, defs, null));
+        attach(result, dc);
+        return result;
+    }
+
     Name typeName() {
         int pos = token.pos;
         Name name = ident();
@@ -3485,9 +3606,40 @@
                 log.warning(pos, Warnings.VarNotAllowed);
             }
         }
+
+        if (isRestrictedRecordTypeName(name)) {
+            reportSyntaxError(pos, Errors.RecordNotAllowed(name));
+        }
         return name;
     }
 
+    Map<Name, JCVariableDecl> headerFields(JCModifiers recordClassMods) {
+        accept(LPAREN);
+        Map<Name, JCVariableDecl> fields = new LinkedHashMap<>();
+        while (token.kind != RPAREN) {
+            JCModifiers mods = modifiersOpt();
+            mods.flags |= Flags.RECORD;
+            mods.flags |= (recordClassMods.flags & Flags.ABSTRACT) != 0 ? Flags.PROTECTED : 0;
+            if ((mods.flags & Flags.NON_FINAL) == 0) {
+                mods.flags |= Flags.FINAL;
+            }
+            JCExpression type = parseType();
+            int pos = token.pos;
+            Name id = ident();
+            if (!fields.containsKey(id)) {
+                List<Pair<Accessors.Kind, Name>> accessors = List.of(new Pair<>(Accessors.Kind.GET, id));
+                fields.put(id, toP(F.at(pos).VarDef(mods, id, type, null, accessors)));
+            } else {
+                log.error(pos, Errors.RecordCantDeclareDuplicateFields);
+            }
+            if (token.kind == COMMA) {
+                nextToken();
+            }
+        }
+        accept(RPAREN);
+        return fields;
+    }
+
     /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
      *                         [EXTENDS TypeList] InterfaceBody
      *  @param mods    The modifiers starting the interface declaration
@@ -3506,7 +3658,7 @@
             nextToken();
             extending = typeList();
         }
-        List<JCTree> defs = classOrInterfaceBody(name, true);
+        List<JCTree> defs = classInterfaceOrRecordBody(name, true, false);
         JCClassDecl result = toP(F.at(pos).ClassDef(
             mods, name, typarams, null, extending, defs));
         attach(result, dc);
@@ -3593,7 +3745,7 @@
         JCClassDecl body = null;
         if (token.kind == LBRACE) {
             JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM);
-            List<JCTree> defs = classOrInterfaceBody(names.empty, false);
+            List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
             body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
         }
         if (args.isEmpty() && body == null)
@@ -3623,7 +3775,7 @@
     /** ClassBody     = "{" {ClassBodyDeclaration} "}"
      *  InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
      */
-    List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) {
+    List<JCTree> classInterfaceOrRecordBody(Name className, boolean isInterface, boolean isRecord) {
         accept(LBRACE);
         if (token.pos <= endPosTable.errorEndPos) {
             // error recovery
@@ -3633,7 +3785,11 @@
         }
         ListBuffer<JCTree> defs = new ListBuffer<>();
         while (token.kind != RBRACE && token.kind != EOF) {
-            defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
+            if (!isRecord) {
+                defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
+            } else {
+                defs.appendList(recordBodyDeclaration(className));
+            }
             if (token.pos <= endPosTable.errorEndPos) {
                // error recovery
                skip(false, true, true, false);
@@ -3681,9 +3837,10 @@
             int pos = token.pos;
             JCModifiers mods = modifiersOpt();
             if (token.kind == CLASS ||
+                isRecordDeclaration() ||
                 token.kind == INTERFACE ||
                 token.kind == ENUM) {
-                return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
+                return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
             } else if (token.kind == LBRACE &&
                        (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 &&
                        mods.annotations.isEmpty()) {
@@ -3692,69 +3849,91 @@
                 }
                 return List.of(block(pos, mods.flags));
             } else {
-                pos = token.pos;
-                List<JCTypeParameter> typarams = typeParametersOpt();
-                // if there are type parameters but no modifiers, save the start
-                // position of the method in the modifiers.
-                if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
-                    mods.pos = pos;
-                    storeEnd(mods, pos);
-                }
-                List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
-
-                if (annosAfterParams.nonEmpty()) {
-                    checkSourceLevel(annosAfterParams.head.pos, Feature.ANNOTATIONS_AFTER_TYPE_PARAMS);
-                    mods.annotations = mods.annotations.appendList(annosAfterParams);
-                    if (mods.pos == Position.NOPOS)
-                        mods.pos = mods.annotations.head.pos;
-                }
-
-                Token tk = token;
-                pos = token.pos;
-                JCExpression type;
-                boolean isVoid = token.kind == VOID;
-                if (isVoid) {
-                    type = to(F.at(pos).TypeIdent(TypeTag.VOID));
-                    nextToken();
-                } else {
-                    // method returns types are un-annotated types
-                    type = unannotatedType(false);
-                }
-                if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
-                    if (isInterface || tk.name() != className)
-                        log.error(DiagnosticFlag.SYNTAX, pos, Errors.InvalidMethDeclRetTypeReq);
-                    else if (annosAfterParams.nonEmpty())
-                        illegal(annosAfterParams.head.pos);
-                    return List.of(methodDeclaratorRest(
-                        pos, mods, null, names.init, typarams,
-                        isInterface, true, dc));
-                } else {
-                    pos = token.pos;
-                    Name name = ident();
-                    if (token.kind == LPAREN) {
-                        return List.of(methodDeclaratorRest(
-                            pos, mods, type, name, typarams,
-                            isInterface, isVoid, dc));
-                    } else if (!isVoid && typarams.isEmpty()) {
-                        List<JCTree> defs =
-                            variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
-                                                    new ListBuffer<JCTree>(), false).toList();
-                        accept(SEMI);
-                        storeEnd(defs.last(), S.prevToken().endPos);
-                        return defs;
-                    } else {
-                        pos = token.pos;
-                        List<JCTree> err = isVoid
-                            ? List.of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
-                                List.nil(), List.nil(), null, null)))
-                            : null;
-                        return List.of(syntaxError(token.pos, err, Errors.Expected(LPAREN)));
-                    }
-                }
+                return methodOrFieldMemberDecl(className, mods, isInterface, dc, false);
             }
         }
     }
 
+    boolean isRecordDeclaration() {
+        return token.kind == IDENTIFIER && token.name() == names.record && peekToken(TokenKind.IDENTIFIER, TokenKind.LPAREN);
+    }
+
+    private List<JCTree> methodOrFieldMemberDecl(Name className, JCModifiers mods, boolean isInterface, Comment dc, boolean isRecord) {
+        int pos = token.pos;
+        List<JCTypeParameter> typarams = typeParametersOpt();
+        // if there are type parameters but no modifiers, save the start
+        // position of the method in the modifiers.
+        if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
+            mods.pos = pos;
+            storeEnd(mods, pos);
+        }
+        List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
+
+        if (annosAfterParams.nonEmpty()) {
+            checkSourceLevel(annosAfterParams.head.pos, Feature.ANNOTATIONS_AFTER_TYPE_PARAMS);
+            mods.annotations = mods.annotations.appendList(annosAfterParams);
+            if (mods.pos == Position.NOPOS)
+                mods.pos = mods.annotations.head.pos;
+        }
+
+        Token tk = token;
+        pos = token.pos;
+        JCExpression type;
+        boolean isVoid = token.kind == VOID;
+        if (isVoid) {
+            type = to(F.at(pos).TypeIdent(TypeTag.VOID));
+            nextToken();
+        } else {
+            // method returns types are un-annotated types
+            type = unannotatedType(false);
+        }
+        if ((token.kind == LPAREN && !isInterface ||
+                isRecord && token.kind == LBRACE) && type.hasTag(IDENT)) {
+            if (isInterface || tk.name() != className)
+                log.error(pos, Errors.InvalidMethDeclRetTypeReq);
+            else if (annosAfterParams.nonEmpty())
+                illegal(annosAfterParams.head.pos);
+            return List.of(methodDeclaratorRest(
+                pos, mods, null, names.init, typarams,
+                isInterface, true, isRecord, dc));
+        } else {
+            pos = token.pos;
+            Name name = ident();
+            if (token.kind == LPAREN) {
+                return List.of(methodDeclaratorRest(
+                    pos, mods, type, name, typarams,
+                    isInterface, isVoid, isRecord, dc));
+            } else if (!isVoid && typarams.isEmpty()) {
+                if (!isRecord || isRecord && (mods.flags & Flags.STATIC) != 0) {
+                    List<JCTree> defs =
+                        variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
+                                                new ListBuffer<JCTree>(), false).toList();
+                    accept(SEMI);
+                    storeEnd(defs.last(), S.prevToken().endPos);
+                    return defs;
+                } else {
+                    log.error(pos, Errors.RecordFieldsMustBeInHeader);
+                    int tmpPos = token.pos;
+                    nextToken();
+                    return List.of(syntaxError(tmpPos, null, Errors.Expected(LPAREN)));
+                }
+            } else {
+                pos = token.pos;
+                List<JCTree> err = isVoid
+                    ? List.of(toP(F.at(pos).MethodDef(mods, name, type, typarams,
+                        List.nil(), List.nil(), null, null)))
+                    : null;
+                return List.of(syntaxError(token.pos, err, Errors.Expected(LPAREN)));
+            }
+        }
+    }
+
+    protected List<JCTree> recordBodyDeclaration(Name className) {
+        Comment dc = token.comment(CommentStyle.JAVADOC);
+        JCModifiers mods = modifiersOpt();
+        return methodOrFieldMemberDecl(className, mods, false, dc, true);
+    }
+
     /** MethodDeclaratorRest =
      *      FormalParameters BracketsOpt [THROWS TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
      *  VoidMethodDeclaratorRest =
@@ -3768,6 +3947,7 @@
                               Name name,
                               List<JCTypeParameter> typarams,
                               boolean isInterface, boolean isVoid,
+                              boolean isRecord,
                               Comment dc) {
         if (isInterface) {
             if ((mods.flags & Flags.STATIC) != 0) {
@@ -3781,12 +3961,15 @@
         try {
             this.receiverParam = null;
             // Parsing formalParameters sets the receiverParam, if present
-            List<JCVariableDecl> params = formalParameters();
-            if (!isVoid) type = bracketsOpt(type);
+            List<JCVariableDecl> params = List.nil();
             List<JCExpression> thrown = List.nil();
-            if (token.kind == THROWS) {
-                nextToken();
-                thrown = qualidentList(true);
+            if (!isRecord || name != names.init || token.kind == LPAREN) {
+                params = formalParameters();
+                if (!isVoid) type = bracketsOpt(type);
+                if (token.kind == THROWS) {
+                    nextToken();
+                    thrown = qualidentList(true);
+                }
             }
             JCBlock body = null;
             JCExpression defaultValue;
@@ -3809,7 +3992,6 @@
                     }
                 }
             }
-
             JCMethodDecl result =
                     toP(F.at(pos).MethodDef(mods, name, type, typarams,
                                             receiverParam, params, thrown,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Fri Apr 06 13:08:14 2018 -0400
@@ -84,7 +84,7 @@
         key = new TokenKind[maxKey+1];
         for (int i = 0; i <= maxKey; i++) key[i] = TokenKind.IDENTIFIER;
         for (TokenKind t : TokenKind.values()) {
-            if (t.name != null)
+            if (t.name != null && !t.reserved())
             key[tokenName[t.ordinal()].getIndex()] = t;
         }
     }
@@ -226,6 +226,8 @@
         GTGTEQ(">>="),
         GTGTGTEQ(">>>="),
         MONKEYS_AT("@"),
+        VAR("var", Tag.RESERVED),
+        RECORD("record", Tag.RESERVED),
         CUSTOM;
 
         public final String name;
@@ -276,6 +278,10 @@
             }
         }
 
+        public boolean reserved() {
+            return tag == Tag.RESERVED;
+        }
+
         public String getKind() {
             return "Token";
         }
@@ -315,7 +321,8 @@
             DEFAULT,
             NAMED,
             STRING,
-            NUMERIC
+            NUMERIC,
+            RESERVED;
         }
 
         /** The token kind */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Apr 06 13:08:14 2018 -0400
@@ -753,6 +753,11 @@
 compiler.misc.unexpected.ret.val=\
     unexpected return value
 
+# 0: name (accessor kind), 1: list of string (supported accessor kinds)
+compiler.err.unexpected.accessor.kind=\
+    unexpected accessor kind ''{0}''\n\
+    (Valid accessor kinds are: {1})
+
 # 0: set of flag
 compiler.err.mod.not.allowed.here=\
     modifier {0} not allowed here
@@ -2029,6 +2034,10 @@
 compiler.err.expected3=\
     {0}, {1}, or {2} expected
 
+# 0: token, 1: token, 2: token, 3: token
+compiler.err.expected4=\
+    {0}, {1}, {2}, or {3} expected
+
 compiler.err.premature.eof=\
     reached end of file while parsing
 
@@ -3200,3 +3209,50 @@
 # 0: string, 1: string
 compiler.err.illegal.argument.for.option=\
     illegal argument for {0}: {1}
+
+###
+# errors related to records
+
+compiler.err.record.must.declare.at.least.one.field=\
+    records must declare at least one field
+
+compiler.err.record.cant.declare.duplicate.fields=\
+    records cannot declare fields with the same name
+
+compiler.err.record.can.only.declare.methods.as.members=\
+    records can only declare methods as members
+
+# 0: fragment
+compiler.err.cant.extend.record=\
+    Illegal ''extends'' clause for record\n\
+    {0}
+
+compiler.misc.bad.record.super=\
+    A record must extend class AbstractRecord or an ''abstract'' record
+
+# 0: type, 1: name, 2: type, 3: name
+compiler.misc.super.field.mismatch=\
+    Superclass field declaration mismatch\n\
+    expected: {0} {1}\n\
+    found: {2} {3}
+
+compiler.misc.bad.super.fields=\
+    A record cannot have both an explicit constructor, and an implicit superclass header.
+
+compiler.err.record.fields.must.be.in.header=\
+    instance fields in a record must be declared in the header
+
+compiler.err.local.record=\
+    records must not be local
+
+compiler.err.nested.records.must.be.static=\
+    nested records must always be static
+
+# 0: name
+compiler.err.duplicate.argument.to.super=\
+    duplicate argument {0}, arguments passed to the super of a record must be unique
+
+# 0: name
+compiler.err.record.not.allowed=\
+    ''{0}'' not allowed here\n\
+    as of release 10, ''{0}'' is a restricted type name and cannot be used for type declarations
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java	Fri Apr 06 13:08:14 2018 -0400
@@ -575,6 +575,32 @@
         }
     }
 
+    public static class DCAccessor extends DCInlineTag implements AccessorTree {
+        public final Kind kind;
+        public final List<? extends DocTree> description;
+
+        DCAccessor(Kind kind, List<? extends DocTree> description) {
+            Assert.check(kind == Kind.GETTER || kind == Kind.SETTER);
+            this.kind = kind;
+            this.description = description;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return kind;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(DocTreeVisitor<R, D> v, D d) {
+            return v.visitAccessor(this, d);
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<? extends DocTree> getDescription() {
+            return description;
+        }
+    }
+
     public static class DCParam extends DCBlockTag implements ParamTree {
         public final boolean isTypeParameter;
         public final DCIdentifier name;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java	Fri Apr 06 13:08:14 2018 -0400
@@ -129,6 +129,19 @@
         }
     }
 
+    @Override
+    public Void visitAccessor(AccessorTree node, Void aVoid) {
+        try {
+            print("{");
+            printTagName(node);
+            print(node.getDescription());
+            print("}");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+        return null;
+    }
+
     @Override @DefinedBy(Api.COMPILER_TREE)
     public Void visitAttribute(AttributeTree node, Void p) {
         try {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Fri Apr 06 13:08:14 2018 -0400
@@ -55,6 +55,7 @@
 import com.sun.tools.javac.parser.ReferenceParser;
 import com.sun.tools.javac.parser.Tokens.Comment;
 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
+import com.sun.tools.javac.tree.DCTree.DCAccessor;
 import com.sun.tools.javac.tree.DCTree.DCAttribute;
 import com.sun.tools.javac.tree.DCTree.DCAuthor;
 import com.sun.tools.javac.tree.DCTree.DCComment;
@@ -360,6 +361,13 @@
     }
 
     @Override @DefinedBy(Api.COMPILER_TREE)
+    public DCAccessor newAccessorTree(Kind kind, List<? extends DocTree> desc) {
+        DCAccessor tree = new DCAccessor(kind, desc);
+        tree.pos = pos;
+        return tree;
+    }
+
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public DCParam newParamTree(boolean isTypeParameter, IdentifierTree name, List<? extends DocTree> description) {
         DCParam tree = new DCParam(isTypeParameter, (DCIdentifier) name, cast(description));
         tree.pos = pos;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Apr 06 13:08:14 2018 -0400
@@ -814,6 +814,21 @@
         }
     }
 
+    public static class JCRecordDecl extends JCClassDecl implements ClassTree {
+        public JCExpression guard;
+        public JCRecordDecl(JCModifiers mods,
+                           Name name,
+                           List<JCTypeParameter> typarams,
+                           JCExpression extending,
+                           List<JCExpression> implementing,
+                           List<JCTree> defs,
+                           ClassSymbol sym,
+                           JCExpression guard) {
+            super(mods, name, typarams, extending, implementing, defs, sym);
+            this.guard = guard;
+        }
+    }
+
     /**
      * A method definition.
      */
@@ -922,23 +937,27 @@
         public VarSymbol sym;
         /** explicit start pos */
         public int startPos = Position.NOPOS;
+        /** accessors */
+        public List<Pair<Accessors.Kind, Name>> accessors;
 
         protected JCVariableDecl(JCModifiers mods,
                          Name name,
                          JCExpression vartype,
                          JCExpression init,
-                         VarSymbol sym) {
+                         VarSymbol sym,
+                         List<Pair<Accessors.Kind, Name>> accessors) {
             this.mods = mods;
             this.name = name;
             this.vartype = vartype;
             this.init = init;
             this.sym = sym;
+            this.accessors = accessors;
         }
 
         protected JCVariableDecl(JCModifiers mods,
                          JCExpression nameexpr,
                          JCExpression vartype) {
-            this(mods, null, vartype, null, null);
+            this(mods, null, vartype, null, null, null);
             this.nameexpr = nameexpr;
             if (nameexpr.hasTag(Tag.IDENT)) {
                 this.name = ((JCIdent)nameexpr).name;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Apr 06 13:08:14 2018 -0400
@@ -98,6 +98,26 @@
         return false;
     }
 
+    /** Is there a constructor invocation in the given list of trees?
+     */
+    public static boolean hasConstructorInvocation(List<? extends JCTree> trees, Names names, boolean isRecord) {
+        for (JCTree tree : trees) {
+            if (tree.hasTag(EXEC)) {
+                JCExpressionStatement stat = (JCExpressionStatement)tree;
+                if (stat.expr.hasTag(APPLY)) {
+                    JCMethodInvocation apply = (JCMethodInvocation)stat.expr;
+                    Name methName = TreeInfo.name(apply.meth);
+                    if (methName == names._this ||
+                        methName == names._super ||
+                        (isRecord && methName == names._default)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     public static boolean isMultiCatch(JCCatch catchClause) {
         return catchClause.param.vartype.hasTag(TYPEUNION);
     }
@@ -160,6 +180,22 @@
         }
     }
 
+    public static List<JCVariableDecl> recordFields(JCClassDecl tree) {
+        return tree.defs.stream()
+                .filter(t -> t.hasTag(VARDEF))
+                .map(t -> (JCVariableDecl)t)
+                .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD | HYPOTHETICAL)) == RECORD)
+                .collect(List.collector());
+    }
+
+    public static List<JCVariableDecl> superRecordFields(JCClassDecl tree) {
+        return tree.defs.stream()
+                .filter(t -> t.hasTag(VARDEF))
+                .map(t -> (JCVariableDecl)t)
+                .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD | HYPOTHETICAL)) == (RECORD | HYPOTHETICAL))
+                .collect(List.collector());
+    }
+
     /** Is this a constructor whose first (non-synthetic) statement is not
      *  of the form this(...)?
      */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Apr 06 13:08:14 2018 -0400
@@ -171,6 +171,26 @@
         return tree;
     }
 
+    public JCRecordDecl RecordDef(JCModifiers mods,
+                                Name name,
+                                List<JCTypeParameter> typarams,
+                                JCExpression extending,
+                                List<JCExpression> implementing,
+                                List<JCTree> defs,
+                                JCExpression guard)
+    {
+        JCRecordDecl tree = new JCRecordDecl(mods,
+                                     name,
+                                     typarams,
+                                     extending,
+                                     implementing,
+                                     defs,
+                                     null,
+                                     guard);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCMethodDecl MethodDef(JCModifiers mods,
                                Name name,
                                JCExpression restype,
@@ -209,7 +229,11 @@
     }
 
     public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init) {
-        JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null);
+        return VarDef(mods, name, vartype, init, null);
+    }
+
+    public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, List<Pair<Accessors.Kind, Name>> accessors) {
+        JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, accessors);
         tree.pos = pos;
         return tree;
     }
@@ -808,7 +832,7 @@
                 v.name,
                 Type(v.type),
                 init,
-                v).setPos(pos).setType(v.type);
+                v, null).setPos(pos).setType(v.type);
     }
 
     /** Create annotation trees from annotations.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Fri Apr 06 13:08:14 2018 -0400
@@ -91,6 +91,7 @@
         HIERARCHY_PHASE,
         IMPORTS_PHASE,
         MEMBER_ENTER,
+        RECORD_PHASE,
         MEMBERS_PHASE,
         OTHER;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Fri Apr 06 13:08:14 2018 -0400
@@ -74,6 +74,8 @@
     public final Name uses;
     public final Name open;
     public final Name with;
+    public final Name get;
+    public final Name set;
 
     // field and method names
     public final Name _name;
@@ -87,6 +89,7 @@
     public final Name deserializeLambda;
     public final Name desiredAssertionStatus;
     public final Name equals;
+    public final Name oldEquals;
     public final Name error;
     public final Name family;
     public final Name finalize;
@@ -203,6 +206,18 @@
     public final Name makeConcat;
     public final Name makeConcatWithConstants;
 
+    // members of java.lang.invoke.ObjectMethodBuilders
+    public final Name makeEquals;
+    public final Name makeHashCode;
+    public final Name makeToString;
+
+    // record related
+    public final Name record;
+    public final Name where;
+    public final Name guard;
+    public final Name non;
+    public final Name makeLazyExtractor;
+
     public final Name.Table table;
 
     public Names(Context context) {
@@ -236,6 +251,8 @@
         uses = fromString("uses");
         open = fromString("open");
         with = fromString("with");
+        get = fromString("get");
+        set = fromString("set");
 
         // field and method names
         _name = fromString("name");
@@ -249,6 +266,7 @@
         deserializeLambda = fromString("$deserializeLambda$");
         desiredAssertionStatus = fromString("desiredAssertionStatus");
         equals = fromString("equals");
+        oldEquals = fromString("oldEquals");
         error = fromString("<error>");
         family = fromString("family");
         finalize = fromString("finalize");
@@ -364,6 +382,15 @@
         // string concat
         makeConcat = fromString("makeConcat");
         makeConcatWithConstants = fromString("makeConcatWithConstants");
+
+        makeEquals = fromString("makeEquals");
+        makeHashCode = fromString("makeHashCode");
+        makeToString = fromString("makeToString");
+        record = fromString("record");
+        where = fromString("where");
+        guard = fromString("$guard");
+        non = fromString("non");
+        makeLazyExtractor = fromString("makeLazyExtractor");
     }
 
     protected Name.Table createTable(Options options) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java	Fri Apr 06 13:08:14 2018 -0400
@@ -28,6 +28,7 @@
 import java.util.List;
 
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
@@ -36,6 +37,7 @@
 import javax.lang.model.util.SimpleElementVisitor9;
 
 import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.DocTree.Kind;
 import com.sun.source.doctree.IndexTree;
 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
@@ -314,6 +316,26 @@
 
     }
 
+    public Content accessorTagOutput(Element holder, List<? extends DocTree> tags) {
+        if (!tags.isEmpty()) {
+            //Todo: check that there's only one tag
+            DocTree.Kind kind = tags.get(0).getKind();
+            ExecutableElement accessor = utils.findAccessorFor((VariableElement)holder, kind);
+            //add reference to getter/setter
+            Content body = htmlWriter.getDocLink(LinkInfoImpl.Kind.SEE_TAG, (TypeElement)holder.getEnclosingElement(),
+                    accessor, accessor.getSimpleName() + utils.makeSignature(accessor, true), false, false);
+            ContentBuilder result = new ContentBuilder();
+            String key = kind == Kind.GETTER ?
+                    "doclet.getter" : "doclet.setter";
+            result.addContent(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.seeLabel,
+                    new StringContent(configuration.getText(key)))));
+            result.addContent(HtmlTree.DD(body));
+            return result;
+        } else {
+            return new ContentBuilder();
+        }
+    }
+
     private void appendSeparatorIfNotEmpty(ContentBuilder body) {
         if (!body.isEmpty()) {
             body.addContent(", ");
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java	Fri Apr 06 13:08:14 2018 -0400
@@ -335,6 +335,7 @@
     public final Map<TypeElement, List<Element>> propertiesCache = new HashMap<>();
     public final Map<Element, Element> classPropertiesMap = new HashMap<>();
     public final Map<Element, GetterSetter> getterSetterMap = new HashMap<>();
+    public final Map<Element,Element> classAccessedFieldMap = new HashMap<>();
 
     public DocFileFactory docFileFactory;
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Fri Apr 06 13:08:14 2018 -0400
@@ -221,6 +221,17 @@
         utils.removeCommentHelper(element);
     }
 
+    public void setAccessorCommentTree(Element element, List<DocTree> fullBody,
+                                  List<DocTree> blockTags, Utils utils) {
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags);
+        TreePath pathToEncl = utils.docTrees.getPath(element.getEnclosingElement());
+        dcTreesMap.put(element, new DocCommentDuo(pathToEncl, docTree));
+        // There maybe an entry with the original comments usually null,
+        // therefore remove that entry if it exists, and allow a new one
+        // to be reestablished.
+        utils.removeCommentHelper(element);
+    }
+
     /**
      * A simplistic container to transport a TreePath, DocCommentTree pair.
      * Here is why we need this:
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java	Fri Apr 06 13:08:14 2018 -0400
@@ -33,6 +33,7 @@
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 
+import com.sun.source.doctree.AccessorTree;
 import com.sun.source.doctree.DocTree;
 import com.sun.source.doctree.DocTree.Kind;
 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter;
@@ -338,6 +339,10 @@
                 if (property != null) {
                     processProperty(visibleMemberMap, member, property);
                 }
+                final Element accessedField = visibleMemberMap.getAccessorMemberDoc(member);
+                if (accessedField != null) {
+                    processAccessor(accessedField, member);
+                }
                 List<? extends DocTree> firstSentenceTags = utils.getFirstSentenceTrees(member);
                 if (utils.isExecutableElement(member) && firstSentenceTags.isEmpty()) {
                     //Inherit comments from overriden or implemented method if
@@ -441,6 +446,51 @@
     }
 
     /**
+     * Process the an accessor method, e.g. a field getter/setter, so that it contains the documentation
+     * from the underlying field. The method adds the leading sentence, which might be derived from
+     * the field accessor taglet (if present). Certain tags are also copied from the underlying field
+     * documentation.
+     *
+     * @param member the member which is to be augmented.
+     * @param field the original field documentation.
+     */
+    private void processAccessor(Element field, Element member) {
+        CommentUtils cmtutils = configuration.cmtUtils;
+        final boolean isGetter = ((ExecutableElement)member).getParameters().isEmpty();
+        List<? extends DocTree> accessorTags = utils.getBlockTags(field, isGetter ? Kind.GETTER : Kind.SETTER);
+        //Todo: check that there's only one tag
+        List<? extends DocTree> description = ((AccessorTree)accessorTags.get(0)).getDescription();
+
+        List<DocTree> fullBody = new ArrayList<>();
+        List<DocTree> blockTags = new ArrayList<>();
+        //add description
+        if (description.isEmpty()) {
+            if (isGetter) {
+                String text = MessageFormat.format(
+                        configuration.getText("doclet.FieldGetterWithName"),
+                        utils.propertyName((ExecutableElement) member));
+                fullBody.addAll(cmtutils.makeFirstSentenceTree(text));
+            } else {
+                String text = MessageFormat.format(
+                        configuration.getText("doclet.FieldSetterWithName"),
+                        utils.propertyName((ExecutableElement)member));
+                fullBody.addAll(cmtutils.makeFirstSentenceTree(text));
+            }
+        } else {
+            fullBody.addAll(description);
+        }
+
+        // copy certain tags
+        List<? extends DocTree> tags = utils.getBlockTags(field, Kind.SINCE);
+        blockTags.addAll(tags);
+        if (getVisibleMemberMap(VisibleMemberMap.Kind.FIELDS)
+                .getMembers((TypeElement)field.getEnclosingElement()).contains(field)) {
+            blockTags.add(cmtutils.makeSeeTree("#" + field.getSimpleName(), field));
+        }
+        cmtutils.setAccessorCommentTree(member, fullBody, blockTags, utils);
+    }
+
+    /**
      * Test whether the method is a getter.
      * @param element property method documentation. Needs to be either property
      * method, property getter, or property setter.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Fri Apr 06 13:08:14 2018 -0400
@@ -63,6 +63,8 @@
 doclet.PropertySetter=Sets the value of the property
 doclet.PropertyGetterWithName=Gets the value of the property {0}.
 doclet.PropertySetterWithName=Sets the value of the property {0}.
+doclet.FieldGetterWithName=Gets the value of the field {0}.
+doclet.FieldSetterWithName=Sets the value of the field {0}.
 doclet.Default=Default:
 doclet.Parameters=Parameters:
 doclet.TypeParameters=Type Parameters:
@@ -74,6 +76,8 @@
 doclet.Return_tag_on_void_method=@return tag cannot be used in method with void return type.
 doclet.See_Also=See Also:
 doclet.See=See:
+doclet.getter=Getter:
+doclet.setter=Setter:
 doclet.SerialData=Serial Data:
 doclet.Since=Since:
 doclet.Throws=Throws:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/AccessorTaglet.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017, 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 jdk.javadoc.internal.doclets.toolkit.taglets;
+
+import com.sun.source.doctree.DocTree;
+import jdk.javadoc.internal.doclets.toolkit.Content;
+import jdk.javadoc.internal.doclets.toolkit.util.Utils;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.VariableElement;
+import java.util.List;
+
+/**
+ * A taglet that represents the @param tag.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ * @author Jamie Ho
+ */
+public class AccessorTaglet extends BaseTaglet {
+
+    DocTree.Kind kind;
+
+    /**
+     * Construct a ParamTaglet.
+     */
+    public AccessorTaglet(DocTree.Kind kind) {
+        name = kind.tagName;
+        this.kind = kind;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean inField() {
+        return true;
+    }
+
+        /**
+     * {@inheritDoc}
+     */
+    public boolean inMethod() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean inOverview() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean inModule() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean inPackage() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean inType() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInlineTag() {
+        return false;
+    }
+
+    /**
+     * Given an array of <code>ParamTag</code>s,return its string representation.
+     * @param holder the member that holds the param tags.
+     * @param writer the TagletWriter that will write this tag.
+     * @return the TagletOutput representation of these <code>ParamTag</code>s.
+     */
+    public Content getTagletOutput(Element holder, TagletWriter writer) {
+        Utils utils = writer.configuration().utils;
+        return writer.accessorTagOutput(holder, utils.getBlockTags(holder, kind));
+    }
+}
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java	Fri Apr 06 13:08:14 2018 -0400
@@ -739,6 +739,8 @@
         addStandardTaglet(new CodeTaglet());
         addStandardTaglet(new IndexTaglet());
         addStandardTaglet(new SummaryTaglet());
+        addStandardTaglet(new AccessorTaglet(GETTER));
+        addStandardTaglet(new AccessorTaglet(SETTER));
 
         // Keep track of the names of standard tags for error
         // checking purposes. The following are not handled above.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java	Fri Apr 06 13:08:14 2018 -0400
@@ -25,6 +25,7 @@
 
 package jdk.javadoc.internal.doclets.toolkit.taglets;
 
+import java.util.EnumSet;
 import java.util.List;
 
 import javax.lang.model.element.Element;
@@ -152,6 +153,15 @@
     protected abstract Content seeTagOutput(Element holder, List<? extends DocTree> seeTags);
 
     /**
+     * Return the accessor tag output.
+     *
+     * @param holder
+     * @param tags the accessor tags
+     * @return the output of the accessor tag.
+     */
+    protected abstract Content accessorTagOutput(Element holder, List<? extends DocTree> tags);
+
+    /**
      * Return the output for a simple tag.
      *
      * @param element
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Fri Apr 06 13:08:14 2018 -0400
@@ -210,6 +210,17 @@
         return null;
     }
 
+    public ExecutableElement findAccessorFor(VariableElement field, DocTree.Kind kind) {
+        switch (kind) {
+            case GETTER:
+                return elementUtils.getterFor(field);
+            case SETTER:
+                return elementUtils.setterFor(field);
+            default:
+                throw new IllegalStateException("Cannot get here!");
+        }
+    }
+
     /**
      * Test whether a class is a subclass of another class.
      *
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberMap.java	Fri Apr 06 13:08:14 2018 -0400
@@ -136,6 +136,7 @@
     private final Map<TypeElement, List<Element>> propertiesCache;
     private final Map<Element, Element> classPropertiesMap;
     private final Map<Element, GetterSetter> getterSetterMap;
+    private final Map<Element, Element> classAccessedFieldMap;
 
     /**
      * Construct a VisibleMemberMap of the given type for the given class.
@@ -158,6 +159,7 @@
         propertiesCache = configuration.propertiesCache;
         classPropertiesMap = configuration.classPropertiesMap;
         getterSetterMap = configuration.getterSetterMap;
+        classAccessedFieldMap = configuration.classAccessedFieldMap;
         comparator  = utils.makeGeneralPurposeComparator();
         visibleClasses = new LinkedHashSet<>();
         new ClassMembers(typeElement, STARTLEVEL).build();
@@ -213,6 +215,10 @@
         return classPropertiesMap.get(element);
     }
 
+    public Element getAccessorMemberDoc(Element element) {
+        return classAccessedFieldMap.get(element);
+    }
+
     /**
      * Returns the getter documentation belonging to the given property method.
      * @param propertyMethod the method for which the getter is needed.
@@ -534,6 +540,7 @@
                                 ? utils.getAnnotationFieldsUnfiltered(te)
                                 : utils.getFieldsUnfiltered(te);
                     }
+                    processAccessors(list);
                     break;
                 case CONSTRUCTORS:
                     list = utils.getConstructors(te);
@@ -599,6 +606,19 @@
             return false;
         }
 
+        private void processAccessors(List<? extends Element> fields) {
+            for (Element e : fields) {
+                Element getter = utils.elementUtils.getterFor((VariableElement)e);
+                if (getter != null) {
+                    classAccessedFieldMap.put(getter, e);
+                }
+                Element setter = utils.elementUtils.setterFor((VariableElement)e);
+                if (setter != null) {
+                    classAccessedFieldMap.put(setter, e);
+                }
+            }
+        }
+
         private List<Element> properties(final TypeElement typeElement, final boolean filter) {
             final List<ExecutableElement> allMethods = filter
                     ? utils.getMethods(typeElement)
--- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Fri Apr 06 13:08:14 2018 -0400
@@ -51,6 +51,8 @@
 import java.util.function.Function;
 import java.util.function.Supplier;
 
+import com.sun.tools.javac.util.Names;
+
 /**
  * Low level scanner to determine completeness of input.
  * @author Robert Field
@@ -59,6 +61,7 @@
 
     private final ScannerFactory scannerFactory;
     private final JShell proc;
+    private final Names names;
 
     private static Completeness error() {
         return Completeness.UNKNOWN;  // For breakpointing
@@ -80,6 +83,7 @@
         Log log = CaLog.createLog(context);
         context.put(Log.class, log);
         context.put(Source.class, Source.JDK9);
+        names = Names.instance(context);
         scannerFactory = ScannerFactory.instance(context);
     }
 
@@ -87,6 +91,7 @@
         try {
             Parser parser = new Parser(
                     () -> new Matched(scannerFactory.newScanner(s, false)),
+                    names,
                     worker -> proc.taskFactory.parse(s, worker));
             Completeness stat = parser.parseUnit();
             int endPos = stat == Completeness.UNKNOWN
@@ -159,6 +164,7 @@
     private static final int XSTART        = 0b1000000000;              // Boundary, must be XTERM before
     private static final int XERRO         = 0b10000000000;             // Is an error
     private static final int XBRACESNEEDED = 0b100000000000;            // Expect {ANY} LBRACE
+    private static final int XMODIFIER     = 0b1000000000000;           // Modifier
 
     /**
      * An extension of the compiler's TokenKind which adds our combined/processed
@@ -184,6 +190,7 @@
         IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM),  //
         UNDERSCORE(TokenKind.UNDERSCORE, XERRO),  //  _
         CLASS(TokenKind.CLASS, XEXPR|XDECL1|XBRACESNEEDED),  //  class decl (MAPPED: DOTCLASS)
+        RECORD(TokenKind.RECORD, XEXPR|XDECL1),  //  record decl (MAPPED: DOTCLASS)
         MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1),  //  @
         IMPORT(TokenKind.IMPORT, XDECL1|XSTART),  //  import -- consider declaration
         SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART),  //  ;
@@ -210,18 +217,19 @@
         LONG(TokenKind.LONG, XEXPR1|XDECL1),  //  long
         SHORT(TokenKind.SHORT, XEXPR1|XDECL1),  //  short
         VOID(TokenKind.VOID, XEXPR1|XDECL1),  //  void
+        VAR(TokenKind.VAR, XEXPR1|XDECL1|XTERM),  //  var
 
         // Modifiers keywords
-        ABSTRACT(TokenKind.ABSTRACT, XDECL1),  //  abstract
-        FINAL(TokenKind.FINAL, XDECL1),  //  final
-        NATIVE(TokenKind.NATIVE, XDECL1),  //  native
-        STATIC(TokenKind.STATIC, XDECL1),  //  static
-        STRICTFP(TokenKind.STRICTFP, XDECL1),  //  strictfp
-        PRIVATE(TokenKind.PRIVATE, XDECL1),  //  private
-        PROTECTED(TokenKind.PROTECTED, XDECL1),  //  protected
-        PUBLIC(TokenKind.PUBLIC, XDECL1),  //  public
-        TRANSIENT(TokenKind.TRANSIENT, XDECL1),  //  transient
-        VOLATILE(TokenKind.VOLATILE, XDECL1),  //  volatile
+        ABSTRACT(TokenKind.ABSTRACT, XDECL1 | XMODIFIER),  //  abstract
+        FINAL(TokenKind.FINAL, XDECL1 | XMODIFIER),  //  final
+        NATIVE(TokenKind.NATIVE, XDECL1 | XMODIFIER),  //  native
+        STATIC(TokenKind.STATIC, XDECL1 | XMODIFIER),  //  static
+        STRICTFP(TokenKind.STRICTFP, XDECL1 | XMODIFIER),  //  strictfp
+        PRIVATE(TokenKind.PRIVATE, XDECL1 | XMODIFIER),  //  private
+        PROTECTED(TokenKind.PROTECTED, XDECL1 | XMODIFIER),  //  protected
+        PUBLIC(TokenKind.PUBLIC, XDECL1 | XMODIFIER),  //  public
+        TRANSIENT(TokenKind.TRANSIENT, XDECL1 | XMODIFIER),  //  transient
+        VOLATILE(TokenKind.VOLATILE, XDECL1 | XMODIFIER),  //  volatile
 
         // Declarations and type parameters (thus expressions)
         EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL),  //  extends
@@ -378,6 +386,10 @@
             return (belongs & XBRACESNEEDED) != 0;
         }
 
+        boolean isModifier() {
+            return (belongs & XMODIFIER) != 0;
+        }
+
         /**
          * After construction, check that all compiler TokenKind values have
          * corresponding TK values.
@@ -412,10 +424,13 @@
         /** The error message **/
         public final String message;
 
+        public final Token tok;
+
         private CT(TK tk, Token tok, String msg) {
             this.kind = tk;
             this.endPos = tok.endPos;
             this.message = msg;
+            this.tok = tok;
             //throw new InternalError(msg); /* for debugging */
         }
 
@@ -423,12 +438,14 @@
             this.kind = tk;
             this.endPos = tok.endPos;
             this.message = null;
+            this.tok = tok;
         }
 
         private CT(TK tk, int endPos) {
             this.kind = tk;
             this.endPos = endPos;
             this.message = null;
+            this.tok = null;
         }
     }
 
@@ -557,11 +574,14 @@
         private Matched in;
         private CT token;
         private Completeness checkResult;
+        private final Names names;
 
         Parser(Supplier<Matched> matchedFactory,
+               Names names,
                Function<Worker<ParseTask, Completeness>, Completeness> parseFactory) {
             this.matchedFactory = matchedFactory;
             this.parseFactory = parseFactory;
+            this.names = names;
             resetInput();
         }
 
@@ -642,9 +662,13 @@
 
         public Completeness parseDeclaration() {
             boolean isImport = token.kind == IMPORT;
+            boolean isDatum = false;
+            boolean afterModifiers = false;
             boolean isBracesNeeded = false;
             while (token.kind.isDeclaration()) {
                 isBracesNeeded |= token.kind.isBracesNeeded();
+                isDatum |= !afterModifiers && token.kind == TK.IDENTIFIER && token.tok.name() == names.record;
+                afterModifiers |= !token.kind.isModifier();
                 nextToken();
             }
             switch (token.kind) {
@@ -663,12 +687,19 @@
                         case BRACES:
                         case SEMI:
                             return Completeness.COMPLETE;
+                        case VAR:
                         case IDENTIFIER:
                             return isBracesNeeded
                                     ? Completeness.DEFINITELY_INCOMPLETE
                                     : Completeness.COMPLETE_WITH_SEMI;
                         case BRACKETS:
                             return Completeness.COMPLETE_WITH_SEMI;
+                        case PARENS:
+                            if (isDatum) {
+                                return Completeness.COMPLETE_WITH_SEMI;
+                            } else {
+                                return Completeness.DEFINITELY_INCOMPLETE;
+                            }
                         case DOTSTAR:
                             if (isImport) {
                                 return Completeness.COMPLETE_WITH_SEMI;
--- a/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Fri Apr 06 13:08:14 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, 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
@@ -59,6 +59,7 @@
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Position;
 
+import static com.sun.tools.javac.parser.Tokens.TokenKind.IDENTIFIER;
 /**
  * This is a subclass of JavacParser which overrides one method with a modified
  * verson of that method designed to allow parsing of one "snippet" of Java
@@ -179,9 +180,10 @@
             default:
                 JCModifiers mods = modifiersOpt(pmods);
                 if (token.kind == CLASS
+                        || token.kind == IDENTIFIER && token.name() == names.record
                         || token.kind == INTERFACE
                         || token.kind == ENUM) {
-                    return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc));
+                    return List.<JCTree>of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
                 } else {
                     int pos = token.pos;
                     List<JCTypeParameter> typarams = typeParametersOpt();
@@ -229,7 +231,7 @@
                             //mods.flags |= Flags.STATIC;
                             return List.of(methodDeclaratorRest(
                                     pos, mods, t, name, typarams,
-                                    false, isVoid, dc));
+                                    false, isVoid, false, dc));
                         } else if (!isVoid && typarams.isEmpty()) {
                         // variable declaration
                             //mods.flags |= Flags.STATIC;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/compiler/ExtractorTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+import java.lang.compiler.Extractor;
+import java.lang.compiler.PatternCarriers;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * @test
+ * @run testng ExtractorTest
+ * @summary unit tests for java.lang.compiler.Extractor
+ */
+@Test
+public class ExtractorTest {
+
+    private Object[] extract(Extractor extractor, Object target) throws Throwable {
+        int count = extractor.descriptor().parameterCount();
+        Object[] result = new Object[count + 1];
+        Object carrier = extractor.tryMatch().invoke(target);
+        if (carrier == null)
+            return null;
+        for (int i=0; i<count; i++)
+            result[i] = extractor.component(i).invoke(carrier);
+        result[count] = carrier;
+        return result;
+    }
+
+    private void assertExtracted(Object[] result, Object... args) {
+        assertNotNull(result);
+        assertEquals(result.length - 1, args.length);
+        for (int i = 0; i < args.length; i++) {
+            assertEquals(result[i], args[i]);
+        }
+    }
+
+    private void testExtractLazy(Extractor e, Object target, Object... args) throws Throwable {
+        Object[] result = extract(e, target);
+        assertExtracted(result, args);
+        assertSame(carrier(result), target);
+    }
+
+    private void testExtractEager(Extractor e, Object target, Object... args) throws Throwable {
+        Object[] result = extract(e, target);
+        assertExtracted(result, args);
+        assertNotSame(carrier(result), target);
+    }
+
+    private void assertExtractFail(Extractor e, Object target) throws Throwable {
+        Object[] result = extract(e, target);
+        assertNull(result);
+    }
+
+    private Object carrier(Object[] result) {
+        return result[result.length-1];
+    }
+
+    private static class TestClass {
+        static MethodHandle MH_S, MH_I, MH_L, MH_B;
+        static MethodHandle CONSTRUCTOR;
+        static MethodHandle COPIER;
+        static MethodHandle DIGESTER;
+        static MethodHandle NON_NULL;
+        static MethodHandle NON_NULL_EXPLODED;
+        static MethodType TYPE = MethodType.methodType(TestClass.class, String.class, int.class, long.class, byte.class);
+        static {
+            try {
+                MH_B = MethodHandles.lookup().findGetter(TestClass.class, "b", byte.class);
+                MH_S = MethodHandles.lookup().findGetter(TestClass.class, "s", String.class);
+                MH_I = MethodHandles.lookup().findGetter(TestClass.class, "i", int.class);
+                MH_L = MethodHandles.lookup().findGetter(TestClass.class, "l", long.class);
+                CONSTRUCTOR = MethodHandles.lookup().findConstructor(TestClass.class, TYPE.changeReturnType(void.class));
+                COPIER = MethodHandles.lookup().findVirtual(TestClass.class, "copy", MethodType.methodType(TestClass.class));
+                NON_NULL = MethodHandles.lookup().findVirtual(TestClass.class, "test", MethodType.methodType(boolean.class));
+                NON_NULL_EXPLODED = MethodHandles.lookup().findStatic(TestClass.class, "testExploded", MethodType.methodType(boolean.class, String.class, int.class, long.class, byte.class));
+                DIGESTER = MethodHandles.lookup().findVirtual(TestClass.class, "digest", MethodType.methodType(Object.class, MethodHandle.class));
+            }
+            catch (ReflectiveOperationException e) {
+                throw new ExceptionInInitializerError(e);
+            }
+        }
+
+        String s;
+        int i;
+        long l;
+        byte b;
+
+        public TestClass(String s, int i, long l, byte b) {
+            this.s = s;
+            this.i = i;
+            this.l = l;
+            this.b = b;
+        }
+
+        TestClass copy() {
+            return new TestClass(s, i, l, b);
+        }
+
+        boolean test() {
+            return s != null;
+        }
+
+        static boolean testExploded(String s, int i, long l, byte b) {
+            return s != null;
+        }
+
+        Object digest(MethodHandle target) throws Throwable {
+            return target.invoke(s, i, l, b);
+        }
+    }
+
+    static final MethodHandle[] COMPONENTS = { TestClass.MH_S, TestClass.MH_I, TestClass.MH_L, TestClass.MH_B };
+    static final MethodHandle CARRIER_FACTORY = PatternCarriers.carrierFactory(TestClass.TYPE);
+    static final MethodHandle[] CARRIER_COMPONENTS = { PatternCarriers.carrierComponent(TestClass.TYPE, 0),
+                                                       PatternCarriers.carrierComponent(TestClass.TYPE, 1),
+                                                       PatternCarriers.carrierComponent(TestClass.TYPE, 2),
+                                                       PatternCarriers.carrierComponent(TestClass.TYPE, 3) };
+
+    public void testLazySelfTotal() throws Throwable {
+        Extractor e = Extractor.ofLazy(TestClass.TYPE, COMPONENTS);
+        testExtractLazy(e, new TestClass("foo", 3, 4L, (byte) 5),
+                        "foo", 3, 4L, (byte) 5);
+        testExtractLazy(e, new TestClass(null, 0, 0L, (byte) 0),
+                        null, 0, 0L, (byte) 0);
+    }
+
+    public void testEagerSelfTotal() throws Throwable {
+        Extractor e = Extractor.of(TestClass.TYPE, TestClass.COPIER, COMPONENTS);
+        testExtractEager(e, new TestClass("foo", 3, 4L, (byte) 5),
+                        "foo", 3, 4L, (byte) 5);
+        testExtractEager(e, new TestClass(null, 0, 0L, (byte) 0),
+                        null, 0, 0L, (byte) 0);
+    }
+
+    public void testLazySelfPartial() throws Throwable {
+        Extractor e = Extractor.ofLazyPartial(TestClass.TYPE, TestClass.NON_NULL, COMPONENTS);
+        testExtractLazy(e, new TestClass("foo", 3, 4L, (byte) 5),
+                        "foo", 3, 4L, (byte) 5);
+        assertExtractFail(e, new TestClass(null, 0, 0L, (byte) 0));
+    }
+
+    public void testEagerSelfPartial() throws Throwable {
+        Extractor e = Extractor.ofPartial(TestClass.TYPE, TestClass.COPIER, TestClass.NON_NULL, COMPONENTS);
+        testExtractEager(e, new TestClass("foo", 3, 4L, (byte) 5),
+                        "foo", 3, 4L, (byte) 5);
+        assertExtractFail(e, new TestClass(null, 0, 0L, (byte) 0));
+    }
+
+    public void testCarrierTotal() throws Throwable {
+        Extractor e = Extractor.ofCarrier(TestClass.TYPE, CARRIER_FACTORY, TestClass.DIGESTER, CARRIER_COMPONENTS);
+        testExtractEager(e, new TestClass("foo", 3, 4L, (byte) 5),
+                        "foo", 3, 4L, (byte) 5);
+        testExtractEager(e, new TestClass(null, 0, 0L, (byte) 0),
+                        null, 0, 0L, (byte) 0);
+    }
+
+    public void testCarrierPartial() throws Throwable {
+        Extractor e = Extractor.ofCarrierPartial(TestClass.TYPE, CARRIER_FACTORY, TestClass.DIGESTER, TestClass.NON_NULL_EXPLODED, CARRIER_COMPONENTS);
+        testExtractEager(e, new TestClass("foo", 3, 4L, (byte) 5),
+                        "foo", 3, 4L, (byte) 5);
+        assertExtractFail(e, new TestClass(null, 0, 0L, (byte) 0));
+    }
+
+    public void testClamshell() throws Throwable {
+        Extractor e = Extractor.ofCarrier(TestClass.TYPE, CARRIER_FACTORY, TestClass.DIGESTER, CARRIER_COMPONENTS);
+        MethodHandle mh = e.compose(TestClass.CONSTRUCTOR);
+        TestClass target = new TestClass("foo", 3, 4L, (byte) 5);
+        Object o = mh.invoke(target);
+        assertTrue(o instanceof TestClass);
+        TestClass copy = (TestClass) o;
+        assertEquals(target.s, copy.s);
+        assertEquals(target.i, copy.i);
+        assertEquals(target.l, copy.l);
+        assertEquals(target.b, copy.b);
+    }
+}
--- a/test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -78,7 +78,7 @@
                 }
                 List<String> expect = Arrays.asList(
                         "javadoc.note.msg",         // Loading source file
-                        "compiler.err.expected3",   // class, interface, or enum expected
+                        "compiler.err.expected4",   // class, interface, enum, or __datum expected
                         "javadoc.note.msg");        // 1 error
                 if (!diagCodes.equals(expect))
                     throw new Exception("unexpected diagnostics occurred");
--- a/test/langtools/jdk/jshell/CompletenessTest.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/jdk/jshell/CompletenessTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -122,6 +122,8 @@
         "int[] m = {1, 2}, n = null",
         "int[] m = {1, 2}, n",
         "int[] m = {1, 2}, n = {3, 4}",
+        "record D(int i)",
+        "static record D(int i)"
     };
 
     static final String[] considered_incomplete = new String[] {
--- a/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java	Fri Apr 06 13:08:14 2018 -0400
@@ -26,7 +26,7 @@
  * @bug 8161013
  * @summary Verify that anonymous class binaries have the correct flags set
  * @modules jdk.jdeps/com.sun.tools.classfile
- * @run main AnonymousClassFlags
+ * @compile AnonymousClassFlags.java
  */
 
 import java.util.*;
--- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out	Fri Apr 06 13:08:14 2018 -0400
@@ -1,7 +1,7 @@
 AnnotatedImport.java:10:13: compiler.err.expected: token.identifier
-AnnotatedImport.java:10:16: compiler.err.expected3: class, interface, enum
+AnnotatedImport.java:10:16: compiler.err.expected4: class, interface, enum, record
 AnnotatedImport.java:11:7: compiler.err.expected: token.identifier
-AnnotatedImport.java:11:11: compiler.err.expected3: class, interface, enum
+AnnotatedImport.java:11:11: compiler.err.expected4: class, interface, enum, record
 AnnotatedImport.java:12:18: compiler.err.expected: token.identifier
-AnnotatedImport.java:12:21: compiler.err.expected3: class, interface, enum
+AnnotatedImport.java:12:21: compiler.err.expected4: class, interface, enum, record
 6 errors
--- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out	Fri Apr 06 13:08:14 2018 -0400
@@ -1,3 +1,3 @@
 AnnotatedPackage1.java:9:14: compiler.err.expected: token.identifier
-AnnotatedPackage1.java:9:17: compiler.err.expected3: class, interface, enum
+AnnotatedPackage1.java:9:17: compiler.err.expected4: class, interface, enum, record
 2 errors
--- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out	Fri Apr 06 13:08:14 2018 -0400
@@ -1,3 +1,3 @@
 AnnotatedPackage2.java:9:8: compiler.err.expected: token.identifier
-AnnotatedPackage2.java:9:12: compiler.err.expected3: class, interface, enum
+AnnotatedPackage2.java:9:12: compiler.err.expected4: class, interface, enum, record
 2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/AllowStaticFieldsInRecordsTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, 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 smoke test to check that static fields are allowed in records
+ * @compile AllowStaticFieldsInRecordsTest.java
+ */
+
+public record AllowStaticFieldsInRecordsTest(int x) {
+    static int S = 3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/BadUseOfRecordTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary check that record is not used as a type name
+ * @compile/fail/ref=BadUseOfRecordTest.out -XDrawDiagnostics BadUseOfRecordTest.java
+ */
+
+class BadUseOfRecordTest {
+
+    interface record {
+        void m();
+    }
+
+    class record {}
+
+    enum record {A, B}
+
+    record record(int x);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/BadUseOfRecordTest.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,5 @@
+BadUseOfRecordTest.java:9:15: compiler.err.record.not.allowed: record
+BadUseOfRecordTest.java:13:11: compiler.err.record.not.allowed: record
+BadUseOfRecordTest.java:15:10: compiler.err.record.not.allowed: record
+BadUseOfRecordTest.java:17:12: compiler.err.record.not.allowed: record
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/CheckDatumMembersAccess.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017, 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 members of abtract datum has protected access
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @compile CheckDatumMembersAccess.java
+ * @run main CheckDatumMembersAccess
+ */
+
+import com.sun.tools.classfile.ClassFile;
+
+import java.io.File;
+
+import com.sun.tools.classfile.AccessFlags;
+import com.sun.tools.classfile.Field;
+import com.sun.tools.classfile.Method;
+import com.sun.tools.javac.util.Assert;
+
+public class CheckDatumMembersAccess {
+
+    abstract record abtractDatum(int AbstractFieldToSearchFor) {}
+
+    record Datum(int AbstractFieldToSearchFor, int newField, non-final int nonFinalField) {}
+
+    public static void main(String args[]) throws Throwable {
+        new CheckDatumMembersAccess().run();
+    }
+
+    void run() throws Throwable {
+        checkAbstractDatum();
+        checkNonAbstractDatum();
+    }
+
+    void checkAbstractDatum() throws Throwable {
+        File testClasses = new File(System.getProperty("test.classes"));
+        File file = new File(testClasses,
+                CheckDatumMembersAccess.class.getName() + "$abtractDatum.class");
+        ClassFile classFile = ClassFile.read(file);
+        for (Field f : classFile.fields) {
+            if (f.getName(classFile.constant_pool).equals("AbstractFieldToSearchFor")) {
+                Assert.check((f.access_flags.flags & AccessFlags.ACC_PROTECTED) != 0, "fields of abstract datum should be protected");
+            }
+        }
+
+        for (Method m : classFile.methods) {
+            Assert.check((m.access_flags.flags & AccessFlags.ACC_PUBLIC) != 0, "methods of abstract datum should be public");
+        }
+    }
+
+    void checkNonAbstractDatum() throws Throwable {
+        File testClasses = new File(System.getProperty("test.classes"));
+        File file = new File(testClasses,
+                CheckDatumMembersAccess.class.getName() + "$Datum.class");
+        ClassFile classFile = ClassFile.read(file);
+        for (Field f : classFile.fields) {
+            if (f.getName(classFile.constant_pool).equals("AbstractFieldToSearchFor") ||
+                f.getName(classFile.constant_pool).equals("newField")) {
+                Assert.check((f.access_flags.flags & AccessFlags.ACC_FINAL) != 0, "fields of datum should be final");
+            }
+            if (f.getName(classFile.constant_pool).equals("nonFinalField")) {
+                Assert.check((f.access_flags.flags & AccessFlags.ACC_FINAL) == 0, "non-final fields of datum should be mutable");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/DataClassAsSuper.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary check that a datum can inherit from DataClass or an abstract datum class
+ * @compile/fail/ref=DataClassAsSuper.out -XDrawDiagnostics DataClassAsSuper.java
+ */
+
+class DataClassAsSuper {
+
+    // should extend DataClass or an abstract datum
+    record D1(int x) extends Object { }
+
+    record D2(int y) {}
+
+    // D2 is datum but not abstract
+    record D3(int y, int x) extends D2(y) {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/DataClassAsSuper.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,3 @@
+DataClassAsSuper.java:10:30: compiler.err.cant.extend.record: (compiler.misc.bad.record.super)
+DataClassAsSuper.java:15:37: compiler.err.cant.extend.record: (compiler.misc.bad.record.super)
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/DataClassTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+/**
+ * DataClassTest
+ *
+ * @test
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.tools.javac.file
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build combo.ComboTestHelper
+
+ * @run main DataClassTest
+ */
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.file.PathFileObject;
+import combo.ComboTask;
+
+public class DataClassTest extends combo.ComboInstance<DataClassTest> {
+
+    enum FieldTypeKind implements combo.ComboParameter {
+        BYTE("byte", byte.class),
+        SHORT("short", short.class),
+        CHAR("char", char.class),
+        INT("int", int.class),
+        LONG("long", long.class),
+        FLOAT("float", float.class),
+        DOUBLE("double", double.class),
+        BOOLEAN("boolean", boolean.class),
+        OBJECT("Object", Object.class),
+        STRING("String", String.class);
+
+        String retTypeStr;
+        Class<?> clazz;
+
+        FieldTypeKind(String retTypeStr, Class<?> clazz) {
+            this.retTypeStr = retTypeStr;
+            this.clazz = clazz;
+        }
+
+        public String expand(String optParameter) {
+            return retTypeStr;
+        }
+    }
+
+    static final Map<FieldTypeKind, List<Object>> dataValues
+            = Map.ofEntries(
+            Map.entry(FieldTypeKind.BYTE, List.of(Byte.MIN_VALUE, (byte) -4, (byte) -1, (byte) 0, (byte) 1, (byte) 4, Byte.MAX_VALUE)),
+            Map.entry(FieldTypeKind.SHORT, List.of(Short.MIN_VALUE, (short) -4, (short) -1, (short) 0, (short) 1, (short) 4, Short.MAX_VALUE)),
+            Map.entry(FieldTypeKind.CHAR, List.of(Character.MIN_VALUE, 'a', 'A', 'z', (char) 0, Character.MAX_VALUE)),
+            Map.entry(FieldTypeKind.INT, List.of(Integer.MIN_VALUE, (int) -4, (int) -1, (int) 0, (int) 1, (int) 4, Integer.MAX_VALUE)),
+            Map.entry(FieldTypeKind.LONG, List.of(Long.MIN_VALUE, (long) -4, (long) -1, (long) 0, (long) 1, (long) 4, Long.MAX_VALUE)),
+            Map.entry(FieldTypeKind.FLOAT, List.of(Float.MIN_VALUE, Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, 0.0f, -0.0f, 1.0f, -1.0f, 2.0f, -2.0f, Float.MAX_VALUE)),
+            Map.entry(FieldTypeKind.DOUBLE, List.of(Double.MIN_VALUE, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0.0d, -0.0d, 1.0d, -1.0d, 2.0d, -2.0d, Double.MAX_VALUE)),
+            Map.entry(FieldTypeKind.BOOLEAN, List.of(true, false)),
+            Map.entry(FieldTypeKind.OBJECT, Arrays.asList(null, 3, "foo", new String[] {"a"})),
+            Map.entry(FieldTypeKind.STRING, Arrays.asList(null, "", "foo", "bar"))
+    );
+
+    static final String sourceTemplate =
+            "record Data(#{FT[0]} f0, #{FT[1]} f1) { }";
+
+    public static void main(String... args) throws Exception {
+        new combo.ComboTestHelper<DataClassTest>()
+                .withArrayDimension("FT", (x, t, index) -> {
+                    x.fieldType[index] = t;
+                }, 2, FieldTypeKind.values())
+                .run(DataClassTest::new);
+    }
+
+    FieldTypeKind[] fieldType = new FieldTypeKind[2];
+
+    @Override
+    public void doWork() throws Throwable {
+        newCompilationTask()
+                .withSourceFromTemplate(sourceTemplate)
+                .generate(this::check);
+    }
+
+    void check(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
+        List<Object> f0s = dataValues.get(fieldType[0]);
+        List<Object> f1s = dataValues.get(fieldType[1]);
+
+        if (result.hasErrors() || result.hasWarnings())
+            fail("Compilation errors not expected: " + result.compilationInfo());
+
+        Iterable<? extends PathFileObject> pfoIt = (Iterable<? extends PathFileObject>) result.get();
+        PathFileObject pfo = pfoIt.iterator().next();
+        Class<?> clazz;
+        Constructor<?> ctor;
+        Method getterF0, getterF1, hashCodeMethod, equalsMethod, toStringMethod;
+        Field fieldF0, fieldF1;
+
+        try {
+            URL[] urls = new URL[] {pfo.getPath().getParent().toUri().toURL()};
+            ClassLoader cl = new URLClassLoader(urls);
+            clazz = cl.loadClass("Data");
+
+            ctor = clazz.getConstructor(fieldType[0].clazz, fieldType[1].clazz);
+            getterF0 = clazz.getMethod("f0");
+            getterF1 = clazz.getMethod("f1");
+            fieldF0 = clazz.getDeclaredField("f0");
+            fieldF1 = clazz.getDeclaredField("f1");
+            equalsMethod = clazz.getMethod("equals", Object.class);
+            hashCodeMethod = clazz.getMethod("hashCode");
+            toStringMethod = clazz.getMethod("toString");
+
+            if (getterF0.getReturnType() != fieldType[0].clazz
+                || getterF1.getReturnType() != fieldType[1].clazz
+                || fieldF0.getType() != fieldType[0].clazz
+                || fieldF1.getType() != fieldType[1].clazz)
+                fail("Unexpected field or getter type: " + result.compilationInfo());
+
+            for (AccessibleObject o : List.of(ctor, getterF0, getterF1, equalsMethod, hashCodeMethod, toStringMethod)) {
+                // @@@ Why do we need this?
+                o.setAccessible(true);
+            }
+
+            for (Object f0 : f0s) {
+                for (Object f1 : f1s) {
+                    // Create object
+                    Object datum = ctor.newInstance(f0, f1);
+
+                    // Test getters
+                    Object actualF0 = getterF0.invoke(datum);
+                    Object actualF1 = getterF1.invoke(datum);
+                    if (!Objects.equals(f0, actualF0) || !Objects.equals(f1, actualF1))
+                        fail(String.format("Getters don't report back right values for %s %s/%s, %s %s/%s",
+                                           fieldType[0].clazz, f0, actualF0,
+                                           fieldType[1].clazz, f1, actualF1));
+
+                    int hashCode = (int) hashCodeMethod.invoke(datum);
+                    int expectedHash = Objects.hash(f0, f1);
+                    // @@@ fail
+                    if (hashCode != expectedHash) {
+                        System.err.println(String.format("Hashcode not as expected: expected=%d, actual=%d",
+                                           expectedHash, hashCode));
+                    }
+
+                    String toString = (String) toStringMethod.invoke(datum);
+                    String expectedToString = String.format("Data[f0=%s, f1=%s]", f0, f1);
+                    if (!toString.equals(expectedToString)) {
+                        fail(String.format("ToString not as expected: expected=%s, actual=%s",
+                                           expectedToString, toString));
+                    }
+
+                    // Test equals
+                    for (Object f2 : f0s) {
+                        for (Object f3 : f1s) {
+                            Object other = ctor.newInstance(f2, f3);
+                            boolean isEqual = (boolean) equalsMethod.invoke(datum, other);
+                            boolean isEqualReverse = (boolean) equalsMethod.invoke(other, datum);
+                            boolean f0f2Equal = Objects.equals(f0, f2);
+                            boolean f1f3Equal = Objects.equals(f1, f3);
+                            if (fieldType[0] == FieldTypeKind.FLOAT) {
+                                f0f2Equal = Float.compare((float)f0, (float)f2) == 0;
+                            } else if (fieldType[0] == FieldTypeKind.DOUBLE) {
+                                f0f2Equal = Double.compare((double)f0, (double)f2) == 0;
+                            }
+                            if (fieldType[1] == FieldTypeKind.FLOAT) {
+                                f1f3Equal = Float.compare((float)f1, (float)f3) == 0;
+                            } else if (fieldType[1] == FieldTypeKind.DOUBLE) {
+                                f1f3Equal = Double.compare((double)f1, (double)f3) == 0;
+                            }
+                            boolean shouldEqual = f0f2Equal && f1f3Equal;
+                            // @@@ fail
+                            if (shouldEqual != isEqual)
+                                System.err.println(String.format("Equals not as expected: %s %s/%s, %s %s/%s",
+                                                   fieldType[0].clazz, f0, f2,
+                                                   fieldType[1].clazz, f1, f3));
+                            if (isEqualReverse != isEqual)
+                                fail(String.format("Equals not symmetric: %s %s/%s, %s %s/%s",
+                                                   fieldType[0].clazz, f0, f2,
+                                                   fieldType[1].clazz, f1, f3));
+
+                        }
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            throw new AssertionError(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/DatumCanNotDeclaredFieldsWithSameName.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,9 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=DatumCanNotDeclaredFieldsWithSameName.out -XDrawDiagnostics DatumCanNotDeclaredFieldsWithSameName.java
+ */
+
+public class DatumCanNotDeclaredFieldsWithSameName {
+    record D1(int x, int x) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/DatumCanNotDeclaredFieldsWithSameName.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,2 @@
+DatumCanNotDeclaredFieldsWithSameName.java:8:26: compiler.err.record.cant.declare.duplicate.fields
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/DatumShouldDeclareAtLeastOneFieldTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,11 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=DatumShouldDeclareAtLeastOneFieldTest.out -XDrawDiagnostics DatumShouldDeclareAtLeastOneFieldTest.java
+ */
+
+public class DatumShouldDeclareAtLeastOneFieldTest {
+    static abstract record D1() { }
+
+    static record D2() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/DatumShouldDeclareAtLeastOneFieldTest.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,3 @@
+DatumShouldDeclareAtLeastOneFieldTest.java:8:33: compiler.err.record.must.declare.at.least.one.field
+DatumShouldDeclareAtLeastOneFieldTest.java:10:24: compiler.err.record.must.declare.at.least.one.field
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/GuardsInRecordsTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, 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 test for guards in records
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @ignore guards will continue to be developed independently
+ * @run main GuardsInRecordsTest
+ */
+
+public class GuardsInRecordsTest {
+    static record Range1(int lo, int hi) where lo <= hi;
+    static record Range2(int lo, int hi) where lo <= hi {}
+    static record Range3(int lo, int hi) where lo <= hi {
+        Range3(int lo, int hi) {
+            default(lo, hi);
+        }
+    }
+
+    static abstract record A (int a) where a >= 0;
+    static record B (int a, int b) extends A(a) where b >= 0;
+
+    public static void main(String... args) {
+        try {
+            Range1 r = new Range1(2, 1);
+            throw new AssertionError("an exception was expected for Range1");
+        } catch (IllegalArgumentException iae) {}
+
+        try {
+            Range2 r = new Range2(2, 1);
+            throw new AssertionError("an exception was expected for Range2");
+        } catch (IllegalArgumentException iae) {}
+
+        try {
+            Range3 r = new Range3(2, 1);
+            throw new AssertionError("an exception was expected for Range3");
+        } catch (IllegalArgumentException iae) {}
+
+        try {
+            B b1 = new B(-1, 1);
+            throw new AssertionError("an exception was expected for B");
+        } catch (IllegalArgumentException iae) {}
+
+        try {
+            B b2 = new B(-1, -1);
+            throw new AssertionError("an exception was expected for B");
+        } catch (IllegalArgumentException iae) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Neg01.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,43 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=Neg01.out -XDrawDiagnostics Neg01.java
+ */
+
+public class Neg01 {
+    static abstract record Sup1(int x, int y) { }
+
+    record Bad1(int x, int y, int z) extends Sup1(x, y, z) { } //too many super args
+
+    record Bad2(int x, int z) extends Sup1(x) { } //too few super args
+
+    record Bad3(int x, int z) extends Sup1(x, z) { } //name mismatch
+
+    record Bad4(int x, double y) extends Sup1(x, y) { } //type mismatch
+
+    record Bad5(int x, int y) extends Sup1(x, y) {
+        Bad5(int x, int y) { super(x, y); } //error: explicit constructor and super header
+    }
+
+    static class Sup2 { }
+
+    record Bad6(int x, int y) extends Object(x) { } //bad super header
+
+    record Bad7(int x, int y) extends Sup2 { } //non-datum superclass
+
+    static record Sup3(int x, int y) { }
+
+    record Bad7(int x, int y) extends Sup2 { } //non-abstract datum superclass
+
+    record Test(int x) {
+        Test(int x, int y) {
+            default(); //too few
+            default(x); //ok
+            default(x, y); //too many
+        }
+
+        void test() {
+           default(); //error - not in a constructor
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Neg01.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,14 @@
+Neg01.java:30:5: compiler.err.already.defined: kindname.class, Neg01.Bad7, kindname.class, Neg01
+Neg01.java:10:5: compiler.err.cant.apply.symbol: kindname.constructor, Sup1, int,int, int,int,int, kindname.class, Neg01.Sup1, (compiler.misc.arg.length.mismatch)
+Neg01.java:12:5: compiler.err.cant.apply.symbol: kindname.constructor, Sup1, int,int, int, kindname.class, Neg01.Sup1, (compiler.misc.arg.length.mismatch)
+Neg01.java:14:39: compiler.err.cant.extend.record: (compiler.misc.super.field.mismatch: int, y, int, z)
+Neg01.java:16:42: compiler.err.cant.extend.record: (compiler.misc.super.field.mismatch: int, y, double, y)
+Neg01.java:16:5: compiler.err.cant.apply.symbol: kindname.constructor, Sup1, int,int, int,double, kindname.class, Neg01.Sup1, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.possible.loss.of.precision: double, int))
+Neg01.java:18:39: compiler.err.cant.extend.record: (compiler.misc.bad.super.fields)
+Neg01.java:24:39: compiler.err.cant.extend.record: (compiler.misc.bad.record.super)
+Neg01.java:24:5: compiler.err.cant.apply.symbol: kindname.constructor, Object, compiler.misc.no.args, int, kindname.class, java.lang.Object, (compiler.misc.arg.length.mismatch)
+Neg01.java:26:39: compiler.err.cant.extend.record: (compiler.misc.bad.record.super)
+Neg01.java:34:20: compiler.err.cant.apply.symbol: kindname.constructor, Test, int, compiler.misc.no.args, kindname.class, Neg01.Test, (compiler.misc.arg.length.mismatch)
+Neg01.java:36:20: compiler.err.cant.apply.symbol: kindname.constructor, Test, int, int,int, kindname.class, Neg01.Test, (compiler.misc.arg.length.mismatch)
+Neg01.java:40:12: compiler.err.cant.resolve.location.args: kindname.method, default, , , (compiler.misc.location: kindname.class, Neg01.Test, null)
+13 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Neg02.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,9 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=Neg02.out -XDrawDiagnostics Neg02.java
+ */
+
+public class Neg02 {
+    record R(non_final int x);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Neg02.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,2 @@
+Neg02.java:8:23: compiler.err.expected: token.identifier
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Neg03.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,11 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=Neg03.out -XDrawDiagnostics Neg03.java
+ */
+
+public class Neg03 {
+    record R(int i) {
+        int j;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Neg03.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,3 @@
+Neg03.java:9:13: compiler.err.record.fields.must.be.in.header
+Neg03.java:9:14: compiler.err.expected: '('
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/NoAddFieldsCanBeDeclaredInDatumTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=NoAddFieldsCanBeDeclaredInDatumTest.out -XDrawDiagnostics NoAddFieldsCanBeDeclaredInDatumTest.java
+ */
+
+public class NoAddFieldsCanBeDeclaredInDatumTest {
+    record Bad1(int i) {
+        int y;
+    }
+
+    record Bad2(int i) {
+        interface I {}
+    }
+
+    record Bad3(int i) {
+        static {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/NoAddFieldsCanBeDeclaredInDatumTest.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,7 @@
+NoAddFieldsCanBeDeclaredInDatumTest.java:9:13: compiler.err.record.fields.must.be.in.header
+NoAddFieldsCanBeDeclaredInDatumTest.java:9:14: compiler.err.expected: '('
+NoAddFieldsCanBeDeclaredInDatumTest.java:13:9: compiler.err.illegal.start.of.type
+NoAddFieldsCanBeDeclaredInDatumTest.java:13:19: compiler.err.invalid.meth.decl.ret.type.req
+NoAddFieldsCanBeDeclaredInDatumTest.java:17:16: compiler.err.illegal.start.of.type
+NoAddFieldsCanBeDeclaredInDatumTest.java:19:1: compiler.err.expected4: class, interface, enum, record
+6 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/ParameterLessConstructorsTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,39 @@
+/*
+ * 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
+ * @summary smoke test for parameterless constructors
+ * @compile ParameterLessConstructorsTest.java
+ */
+
+import java.util.*;
+
+public record ParameterLessConstructorsTest(String s, String k) {
+    ParameterLessConstructorsTest {
+        Objects.requireNonNull(s);
+        Objects.requireNonNull(k);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Pos01.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, 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 datum classes
+ * @run main Pos01
+ */
+public class Pos01 {
+
+    static void assertTrue(boolean cond) {
+        if (!cond) {
+            throw new AssertionError();
+        }
+    }
+
+    static abstract record Sup(int x, int y) { }
+
+    static record Foo(int x, int y, public int z) extends Sup(x, y);
+
+    public static void main(String[] args) {
+        Foo foo = new Foo(1, 2, 3);
+        Foo foo2 = new Foo(1, 2, 3);
+        Foo foo3 = new Foo(1, 2, 4);
+        assertTrue(foo.toString().equals("Foo[x=1, y=2, z=3]"));
+//        assertTrue(foo.hashCode() == java.util.Objects.hash(1, 2, 3));
+        assertTrue(foo.equals(foo2));
+        assertTrue(!foo.equals(foo3));
+        assertTrue(foo.x() == 1);
+        assertTrue(foo.y() == 2);
+        assertTrue(foo.z() == 3);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/Pos02.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, 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 DA/DU with explicit default calls
+ * @compile Pos02.java
+ */
+
+class Pos02 {
+    static record Foo(final int x) {
+        Foo(int x) {
+            default(x);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/RecordsMustBeStaticTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2017, 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 records are always static
+ * @library /tools/javac/lib
+ * @modules jdk.compiler/com.sun.source.util
+ *          jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.file
+ *          jdk.compiler/com.sun.tools.javac.tree
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build DPrinter
+ * @run main RecordsMustBeStaticTest
+ */
+
+import java.io.*;
+import java.net.URI;
+import java.util.Arrays;
+
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.api.JavacTrees;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+
+public class RecordsMustBeStaticTest {
+    public static void main(String... args) throws Exception {
+        new RecordsMustBeStaticTest().run();
+    }
+
+    void run() throws Exception {
+        Context context = new Context();
+        JavacFileManager.preRegister(context);
+        Trees trees = JavacTrees.instance(context);
+        strOut = new StringWriter();
+        PrintWriter pw = new PrintWriter(strOut);
+        dprinter = new DPrinter(pw, trees);
+        tool = ToolProvider.getSystemJavaCompiler();
+        test("Foo.java", source1);
+        test("Foo2.java", source11);
+        test("Foo3.java", source111);
+        test("Bar.java", source2);
+        test("Bar2.java", source3);
+        test("Baz.java", source4);
+    }
+
+    StringWriter strOut;
+    DPrinter dprinter;
+    JavaCompiler tool;
+
+    void test(String fileName, String source) throws Exception {
+        JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, Arrays.asList(new JavaSource(fileName, source)));
+        Iterable<? extends CompilationUnitTree> elements = ct.parse();
+        Assert.check(elements.iterator().hasNext());
+        dprinter.treeTypes(true).printTree("", (JCTree)elements.iterator().next());
+        String output = strOut.toString();
+        Assert.check(output.contains("flags: [static, record]"), "nested records should be static");
+    }
+
+    static final String source1 =
+            "class Foo {\n" +
+            "    record R (int x);\n" +
+            "}";
+
+    static final String source11 =
+            "class Foo2 {\n" +
+            "    class Inner {\n" +
+            "        record R (int x);\n" +
+            "    }\n" +
+            "}";
+    static final String source111 =
+            "class Foo3 {\n" +
+            "    Runnable r = new Runnable() {\n" +
+            "        record R(int i);\n" +
+            "        public void run() {}\n" +
+            "    };" +
+            "}";
+    static final String source2 =
+            "class Bar {\n" +
+            "    void m() {\n" +
+            "        record R (int x);\n" +
+            "    }\n" +
+            "}";
+
+    static final String source3 =
+            "class Bar2 {\n" +
+            "    void m() {\n" +
+            "        static record R (int x);\n" +
+            "    }\n" +
+            "}";
+
+    static final String source4 =
+            "class Baz {\n" +
+            "    void m() {\n" +
+            "        Runnable r = () -> {" +
+            "            record R (int x);\n" +
+            "        };\n" +
+            "    }\n" +
+            "}";
+
+    static class JavaSource extends SimpleJavaFileObject {
+
+        String source;
+
+        public JavaSource(String fileName, String source) {
+            super(URI.create("myfo:/" + fileName), JavaFileObject.Kind.SOURCE);
+            this.source = source;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/SubDatumCannotPassDuplicateArgsToSuperTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,10 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=SubDatumCannotPassDuplicateArgsToSuperTest.out -XDrawDiagnostics SubDatumCannotPassDuplicateArgsToSuperTest.java
+ */
+
+public class SubDatumCannotPassDuplicateArgsToSuperTest {
+    abstract record D1(int x, int y) { }
+    record D2(int x, int y, int z) extends D1(x, x) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/SubDatumCannotPassDuplicateArgsToSuperTest.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,2 @@
+SubDatumCannotPassDuplicateArgsToSuperTest.java:9:51: compiler.err.duplicate.argument.to.super: x
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/SubDatumFieldsMustBeAPrefixOfParentTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,10 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary smoke negative test for datum classes
+ * @compile/fail/ref=SubDatumFieldsMustBeAPrefixOfParentTest.out -XDrawDiagnostics SubDatumFieldsMustBeAPrefixOfParentTest.java
+ */
+
+public class SubDatumFieldsMustBeAPrefixOfParentTest {
+    abstract record D1(int x, int y) { }
+    record D2(int x, int y, int z) extends D1(y, x) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/SubDatumFieldsMustBeAPrefixOfParentTest.out	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,2 @@
+SubDatumFieldsMustBeAPrefixOfParentTest.java:9:44: compiler.err.cant.extend.record: (compiler.misc.super.field.mismatch: int, x, int, y)
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/datum/UserDefinedMethodsTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, 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 datum classes
+ * @modules jdk.compiler/com.sun.tools.javac.util
+ * @run main UserDefinedMethodsTest
+ */
+
+import com.sun.tools.javac.util.Assert;
+
+public class UserDefinedMethodsTest {
+
+    static abstract record Sup(int x) {
+        String foo() {
+            return "Sup.foo";
+        }
+    }
+
+    static record Foo(int x, int y, public int z) extends Sup(x) {
+        @Override
+        public String toString() {
+            return "Foo(x=#x, y=#y, z=#z)".replaceAll("#x", "" + x).replaceAll("#y", "" + y).replaceAll("#z", "" + z);
+        }
+
+        @Override
+        public int hashCode() {
+            return x + y + z;
+        }
+
+        String bar() {
+            return "bar";
+        }
+
+        @Override
+        String foo() {
+            return "Foo.foo";
+        }
+    }
+
+    public static void main(String[] args) {
+        Foo foo = new Foo(1, 2, 3);
+        Assert.check(foo.toString().equals("Foo(x=1, y=2, z=3)"));
+        Assert.check(foo.bar().equals("bar"));
+        Assert.check(foo.foo().equals("Foo.foo"));
+        Assert.check(foo.hashCode() == 6);
+    }
+}
--- a/test/langtools/tools/javac/diags/examples.not-yet.txt	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/diags/examples.not-yet.txt	Fri Apr 06 13:08:14 2018 -0400
@@ -154,3 +154,16 @@
 compiler.err.locn.module-info.not.allowed.on.patch.path
 compiler.misc.cant.resolve.modules
 compiler.misc.file.does.not.contain.module
+
+# datum related messages
+compiler.err.accessors.not.supported.in.source
+compiler.err.cant.extend.datum
+compiler.err.datum.can.only.declare.methods.as.members
+compiler.err.datum.cant.declare.duplicate.fields
+compiler.err.datum.must.declare.at.least.one.field
+compiler.err.duplicate.argument.to.super
+compiler.err.expected3
+compiler.err.unexpected.accessor.kind
+compiler.misc.bad.datum.super
+compiler.misc.bad.super.fields
+compiler.misc.super.field.mismatch
--- a/test/langtools/tools/javac/diags/examples/Expected3.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/diags/examples/Expected3.java	Fri Apr 06 13:08:14 2018 -0400
@@ -21,6 +21,6 @@
  * questions.
  */
 
-// key: compiler.err.expected3
+// key: compiler.err.expected4
 
 int Expected3;
--- a/test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java	Fri Apr 06 13:08:14 2018 -0400
@@ -22,7 +22,7 @@
  */
 
 // key: compiler.err.illegal.start.of.stmt
-// key: compiler.err.expected3
+// key: compiler.err.expected4
 
 class IllegalStartOfStmt {
     void m() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/doctree/AccessorsTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+public class AccessorsTest {
+    /**
+     * @getter This is a getter.
+     * @setter This is a setter.
+     */
+    int x;
+}
--- a/test/langtools/tools/javac/doctree/DocCommentTester.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/doctree/DocCommentTester.java	Fri Apr 06 13:08:14 2018 -0400
@@ -772,6 +772,17 @@
                 else
                     return s;
             }
+
+            @Override
+            public Void visitAccessor(AccessorTree node, Void p) {
+                header(node);
+                indent(+1);
+                print("description", node.getDescription());
+                indent(-1);
+                indent();
+                out.println("]");
+                return null;
+            }
         }
     }
 
--- a/test/langtools/tools/javac/enum/EnumMembersOrder.out	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/enum/EnumMembersOrder.out	Fri Apr 06 13:08:14 2018 -0400
@@ -1,7 +1,7 @@
 EnumMembersOrder.java:11:16: compiler.err.expected: ')'
 EnumMembersOrder.java:11:17: compiler.err.expected3: ',', '}', ';'
 EnumMembersOrder.java:11:18: compiler.err.expected: '}'
-EnumMembersOrder.java:11:31: compiler.err.expected3: class, interface, enum
-EnumMembersOrder.java:17:13: compiler.err.expected3: class, interface, enum
-EnumMembersOrder.java:19:1: compiler.err.expected3: class, interface, enum
+EnumMembersOrder.java:11:31: compiler.err.expected4: class, interface, enum, record
+EnumMembersOrder.java:17:13: compiler.err.expected4: class, interface, enum, record
+EnumMembersOrder.java:19:1: compiler.err.expected4: class, interface, enum, record
 6 errors
--- a/test/langtools/tools/javac/lib/DPrinter.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/lib/DPrinter.java	Fri Apr 06 13:08:14 2018 -0400
@@ -1203,6 +1203,12 @@
         public Void visitTree(DocTree node, Void p) {
             return null;
         }
+
+        @Override
+        public Void visitAccessor(AccessorTree node, Void p) {
+            printList("desc", node.getDescription());
+            return visitTree(node, null);
+        }
     }
 
     // </editor-fold>
--- a/test/langtools/tools/javac/parser/JavacParserTest.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/parser/JavacParserTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -993,7 +993,7 @@
     @Test //JDK-8065753
     void testWrongFirstToken() throws IOException {
         String code = "<";
-        String expectedErrors = "Test.java:1:1: compiler.err.expected3: class, interface, enum\n" +
+        String expectedErrors = "Test.java:1:1: compiler.err.expected4: class, interface, enum, record\n" +
                                 "1 error\n";
         StringWriter out = new StringWriter();
         JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null,
--- a/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out	Fri Apr 06 13:08:14 2018 -0400
@@ -1,3 +1,3 @@
 SingleCommaAnnotationValueFail.java:34:12: compiler.err.expected: '}'
-SingleCommaAnnotationValueFail.java:34:14: compiler.err.expected3: class, interface, enum
+SingleCommaAnnotationValueFail.java:34:14: compiler.err.expected4: class, interface, enum, record
 2 errors
--- a/test/langtools/tools/javac/parser/extend/TrialParser.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/parser/extend/TrialParser.java	Fri Apr 06 13:08:14 2018 -0400
@@ -175,7 +175,7 @@
                 if (token.kind == CLASS
                         || token.kind == INTERFACE
                         || token.kind == ENUM) {
-                    return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc));
+                    return List.<JCTree>of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
                 } else {
                     int pos = token.pos;
                     List<JCTypeParameter> typarams = typeParametersOpt();
--- a/test/langtools/tools/javac/tree/JavacTreeScannerTest.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/tree/JavacTreeScannerTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -47,12 +47,14 @@
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
+
 import javax.tools.*;
 
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.tree.TreeScanner;
 import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Pair;
 
 public class JavacTreeScannerTest extends AbstractTreeScannerTest {
     /**
@@ -148,6 +150,8 @@
                 List<?> list = (List<?>) o;
                 for (Object item: list)
                     reflectiveScan(item);
+            } else if (o instanceof Pair) {
+                return;
             } else
                 error("unexpected item: " + o);
         }
--- a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -47,6 +47,7 @@
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
+
 import javax.tools.*;
 
 import com.sun.source.tree.Tree;
@@ -56,6 +57,7 @@
 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
 import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
 import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Pair;
 
 public class SourceTreeScannerTest extends AbstractTreeScannerTest {
     /**
@@ -161,6 +163,8 @@
                 List<?> list = (List<?>) o;
                 for (Object item: list)
                     reflectiveScan(item);
+            } else if (o instanceof Pair) {
+                return;
             } else
                 error("unexpected item: " + o);
         }
--- a/test/langtools/tools/javadoc/api/basic/GetTask_DiagListenerTest.java	Fri Apr 06 13:05:03 2018 -0400
+++ b/test/langtools/tools/javadoc/api/basic/GetTask_DiagListenerTest.java	Fri Apr 06 13:08:14 2018 -0400
@@ -78,7 +78,7 @@
                 }
                 List<String> expect = Arrays.asList(
                         "javadoc.note.msg",         // Loading source file
-                        "compiler.err.expected3",   // class, interface, or enum expected
+                        "compiler.err.expected4",   // class, interface, enum, or __datum expected
                         "javadoc.note.msg");        // 1 error
                 if (!diagCodes.equals(expect))
                     throw new Exception("unexpected diagnostics occurred");