changeset 52306:de411d537aae

8206986: Compiler support for Switch Expressions (Preview) 8207405: Compiler Tree API support for Switch Expressions (Preview) Summary: Support for switch expression, switch with rules and multiple constants for cases. Reviewed-by: jjg, mcimadamore, vromero
author jlahoda
date Wed, 29 Aug 2018 09:36:17 +0200
parents 1b1bca603244
children 0f8e680269d4 04adf962576e
files make/langtools/tools/propertiesparser/parser/MessageType.java src/jdk.compiler/share/classes/com/sun/source/tree/BreakTree.java src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.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/DeferredAttr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java test/langtools/jdk/jshell/CompletenessTest.java test/langtools/lib/combo/tools/javac/combo/Diagnostics.java test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java test/langtools/tools/javac/ConditionalWithVoid.java test/langtools/tools/javac/ConditionalWithVoid.out test/langtools/tools/javac/desugar/BoxingAndSuper.java test/langtools/tools/javac/diags/CheckResourceKeys.java test/langtools/tools/javac/diags/examples/BreakAmbiguousTarget.java test/langtools/tools/javac/diags/examples/BreakComplexValueNoSwitchExpression.java test/langtools/tools/javac/diags/examples/BreakExprNotImmediate.java test/langtools/tools/javac/diags/examples/BreakMissingValue.java test/langtools/tools/javac/diags/examples/BreakOutsideSwitchExpression.java test/langtools/tools/javac/diags/examples/ContinueOutsideSwitchExpression.java test/langtools/tools/javac/diags/examples/IncompatibleTypesInSwitchExpression.java test/langtools/tools/javac/diags/examples/MultipleCaseLabels.java test/langtools/tools/javac/diags/examples/NeitherConditionalSubtype.java test/langtools/tools/javac/diags/examples/NotExhaustive.java test/langtools/tools/javac/diags/examples/ReturnOutsideSwitchExpression.java test/langtools/tools/javac/diags/examples/SwitchCaseUnexpectedStatement.java test/langtools/tools/javac/diags/examples/SwitchExpressionEmpty.java test/langtools/tools/javac/diags/examples/SwitchExpressionTargetCantBeVoid.java test/langtools/tools/javac/diags/examples/SwitchExpressions.java test/langtools/tools/javac/diags/examples/SwitchMixingCaseTypes.java test/langtools/tools/javac/diags/examples/SwitchNullNotAllowed.java test/langtools/tools/javac/diags/examples/SwitchRules.java test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java test/langtools/tools/javac/expswitch/TEST.properties test/langtools/tools/javac/failover/CheckAttributedTree.java test/langtools/tools/javac/lambda/BadSwitchExpressionLambda.java test/langtools/tools/javac/lambda/BadSwitchExpressionLambda.out test/langtools/tools/javac/lib/DPrinter.java test/langtools/tools/javac/parser/JavacParserTest.java test/langtools/tools/javac/switchexpr/BlockExpression.java test/langtools/tools/javac/switchexpr/BooleanNumericNonNumeric.java test/langtools/tools/javac/switchexpr/BooleanNumericNonNumeric.out test/langtools/tools/javac/switchexpr/BreakTest.java test/langtools/tools/javac/switchexpr/EmptySwitch.java test/langtools/tools/javac/switchexpr/EmptySwitch.out test/langtools/tools/javac/switchexpr/ExhaustiveEnumSwitch.java test/langtools/tools/javac/switchexpr/ExhaustiveEnumSwitchExtra.java test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out test/langtools/tools/javac/switchexpr/ExpressionSwitch.java test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks1.java test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.java test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.out test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java test/langtools/tools/javac/switchexpr/ExpressionSwitchCodeFromJLS.java test/langtools/tools/javac/switchexpr/ExpressionSwitchDA.java test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough.java test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough1.java test/langtools/tools/javac/switchexpr/ExpressionSwitchInExpressionSwitch.java test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.java test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.out test/langtools/tools/javac/switchexpr/ExpressionSwitchIntersectionTypes.java test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.java test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.out test/langtools/tools/javac/switchexpr/ExpressionSwitchUnreachable.java test/langtools/tools/javac/switchexpr/ExpressionSwitchUnreachable.out test/langtools/tools/javac/switchexpr/ParseIncomplete.java test/langtools/tools/javac/switchexpr/ParserRecovery.java test/langtools/tools/javac/switchexpr/ParserRecovery.out test/langtools/tools/javac/switchexpr/SwitchExpressionScopesIsolated.java test/langtools/tools/javac/switchexpr/SwitchExpressionScopesIsolated.out test/langtools/tools/javac/switchexpr/SwitchExpressionSimpleVisitorTest.java test/langtools/tools/javac/switchextra/CaseTest.java test/langtools/tools/javac/switchextra/MultipleLabelsExpression-old.out test/langtools/tools/javac/switchextra/MultipleLabelsExpression.java test/langtools/tools/javac/switchextra/MultipleLabelsStatement-old.out test/langtools/tools/javac/switchextra/MultipleLabelsStatement.java test/langtools/tools/javac/switchextra/RuleParsingTest.java test/langtools/tools/javac/switchextra/SwitchArrowBrokenConstant.java test/langtools/tools/javac/switchextra/SwitchArrowBrokenConstant.out test/langtools/tools/javac/switchextra/SwitchNoExtraTypes.java test/langtools/tools/javac/switchextra/SwitchNoExtraTypes.out test/langtools/tools/javac/switchextra/SwitchObject.java test/langtools/tools/javac/switchextra/SwitchObject.out test/langtools/tools/javac/switchextra/SwitchStatementArrow-old.out test/langtools/tools/javac/switchextra/SwitchStatementArrow.java test/langtools/tools/javac/switchextra/SwitchStatementBroken.java test/langtools/tools/javac/switchextra/SwitchStatementBroken.out test/langtools/tools/javac/switchextra/SwitchStatementBroken2.java test/langtools/tools/javac/switchextra/SwitchStatementBroken2.out test/langtools/tools/javac/switchextra/SwitchStatementScopesIsolated.java test/langtools/tools/javac/switchextra/SwitchStatementScopesIsolated.out test/langtools/tools/javac/switchnull/SwitchNullDisabled.java test/langtools/tools/javac/switchnull/SwitchNullDisabled.out test/langtools/tools/javac/tree/SourceTreeScannerTest.java test/langtools/tools/javac/tree/TreePosTest.java
diffstat 122 files changed, 4782 insertions(+), 297 deletions(-) [+]
line wrap: on
line diff
--- a/make/langtools/tools/propertiesparser/parser/MessageType.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/make/langtools/tools/propertiesparser/parser/MessageType.java	Wed Aug 29 09:36:17 2018 +0200
@@ -95,6 +95,7 @@
         KIND_NAME("kind name", "KindName", "com.sun.tools.javac.code.Kinds"),
         TARGET("target", "Target", "com.sun.tools.javac.jvm"),
         TOKEN("token", "TokenKind", "com.sun.tools.javac.parser.Tokens"),
+        TREE_TAG("tree tag", "Tag", "com.sun.tools.javac.tree.JCTree"),
         TYPE("type", "Type", "com.sun.tools.javac.code"),
         URL("url", "URL", "java.net"),
         SET("set", "Set", "java.util"),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/BreakTree.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BreakTree.java	Wed Aug 29 09:36:17 2018 +0200
@@ -35,6 +35,8 @@
  *   break;
  *
  *   break <em>label</em> ;
+ *
+ *   break <em>expression</em> ;
  * </pre>
  *
  * @jls section 14.15
@@ -49,4 +51,18 @@
      * @return the label
      */
     Name getLabel();
+
+    /**
+     * Returns the expression for this {@code break} statement.
+     *
+     * @return the expression
+     * @since 12
+     *
+     * @deprecated This method is modeling value breaks, which are part of
+     * a preview feature and may be removed if the preview feature
+     * is removed.
+     *
+     */
+    @Deprecated(forRemoval=true, since="12")
+    ExpressionTree getValue();
 }
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Wed Aug 29 09:36:17 2018 +0200
@@ -28,7 +28,7 @@
 import java.util.List;
 
 /**
- * A tree node for a {@code case} in a {@code switch} statement.
+ * A tree node for a {@code case} in a {@code switch} statement or expression.
  *
  * For example:
  * <pre>
@@ -49,13 +49,89 @@
     /**
      * Returns the expression for the case, or
      * {@code null} if this is the default case.
+     * If this case has multiple lables, returns the first label.
      * @return the expression for the case, or null
      */
     ExpressionTree getExpression();
 
     /**
-     * Returns the statements labeled by the case.
-     * @return the statements labeled by the case
+     * Returns the labels for this case.
+     * For default case, returns an empty list.
+     *
+     * @return labels for this case
+     * @since 12
+     *
+     * @deprecated This method is modeling a case with multiple labels,
+     * which is part of a preview feature and may be removed
+     * if the preview feature is removed.
+     */
+    @Deprecated(forRemoval=true, since="12")
+    List<? extends ExpressionTree> getExpressions();
+
+    /**
+     * For case with kind {@linkplain CaseKind#STATEMENT},
+     * returns the statements labeled by the case.
+     * Returns {@code null} for case with kind
+     * {@linkplain CaseKind#RULE}.
+     * @return the statements labeled by the case or null
      */
     List<? extends StatementTree> getStatements();
+
+    /**
+     * For case with kind {@linkplain CaseKind#RULE},
+     * returns the statement or expression after the arrow.
+     * Returns {@code null} for case with kind
+     * {@linkplain CaseKind#STATEMENT}.
+     *
+     * @return case value or null
+     * @since 12
+     *
+     * @deprecated This method is modeling a rule case,
+     * which is part of a preview feature and may be removed
+     * if the preview feature is removed.
+     */
+    @Deprecated(forRemoval=true, since="12")
+    public default Tree getBody() {
+        return null;
+    }
+
+    /**
+     * Returns the kind of this case.
+     *
+     * @return the kind of this case
+     * @since 12
+     *
+     * @deprecated This method is used to model a rule case,
+     * which is part of a preview feature and may be removed
+     * if the preview feature is removed.
+     */
+    @Deprecated(forRemoval=true, since="12")
+    public default CaseKind getCaseKind() {
+        return CaseKind.STATEMENT;
+    }
+
+    /**
+     * The syntatic form of this case:
+     * <ul>
+     *     <li>STATEMENT: {@code case <expression>: <statements>}</li>
+     *     <li>RULE: {@code case <expression> -> <expression>/<statement>}</li>
+     * </ul>
+     *
+     * @since 12
+     *
+     * @deprecated This enum is used to model a rule case,
+     * which is part of a preview feature and may be removed
+     * if the preview feature is removed.
+     */
+    @Deprecated(forRemoval=true, since="12")
+    public enum CaseKind {
+        /**
+         * Case is in the form: {@code case <expression>: <statements>}.
+         */
+        STATEMENT,
+        /**
+         * Case is in the form: {@code case <expression> -> <expression>}.
+         */
+        RULE;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for a {@code switch} expression.
+ *
+ * For example:
+ * <pre>
+ *   switch ( <em>expression</em> ) {
+ *     <em>cases</em>
+ *   }
+ * </pre>
+ *
+ * @jls section 15.29
+ *
+ * @since 12
+ *
+ * @deprecated This method is modeling switch expressions,
+ * which are part of a preview feature and may be removed
+ * if the preview feature is removed.
+ */
+@Deprecated(forRemoval=true, since="12")
+public interface SwitchExpressionTree extends ExpressionTree {
+    /**
+     * Returns the expression for the {@code switch} expression.
+     * @return the expression
+     */
+    ExpressionTree getExpression();
+
+    /**
+     * Returns the cases for the {@code switch} expression.
+     * @return the cases
+     */
+    List<? extends CaseTree> getCases();
+}
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Wed Aug 29 09:36:17 2018 +0200
@@ -240,6 +240,20 @@
         SWITCH(SwitchTree.class),
 
         /**
+         * Used for instances of {@link SwitchExpressionTree}.
+         *
+         * @since 12
+         *
+         * @deprecated
+         * This enum constant is modeling switch expressions,
+         * which are part of a preview feature and may be removed
+         * if the preview feature is removed.
+         */
+        @Deprecated(forRemoval=true, since="12")
+        @SuppressWarnings("removal")
+        SWITCH_EXPRESSION(SwitchExpressionTree.class),
+
+        /**
          * Used for instances of {@link SynchronizedTree}.
          */
         SYNCHRONIZED(SynchronizedTree.class),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Wed Aug 29 09:36:17 2018 +0200
@@ -354,6 +354,23 @@
     R visitSwitch(SwitchTree node, P p);
 
     /**
+     * Visits a SwitchExpressionTree node.
+     *
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     * @since 12
+     *
+     * @deprecated
+     * This method is modeling switch expressions,
+     * which are part of a preview feature and may be removed
+     * if the preview feature is removed.
+     */
+    @Deprecated(forRemoval=true, since="12")
+    @SuppressWarnings("removal")
+    R visitSwitchExpression(SwitchExpressionTree node, P p);
+
+    /**
      * Visits a SynchronizedTree node.
      * @param node the node being visited
      * @param p a parameter value
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Wed Aug 29 09:36:17 2018 +0200
@@ -269,6 +269,25 @@
      * @param node {@inheritDoc}
      * @param p {@inheritDoc}
      * @return  the result of {@code defaultAction}
+     *
+     * @deprecated
+     * This method is modeling switch expressions,
+     * which are part of a preview feature and may be removed
+     * if the preview feature is removed.
+     */
+    @Override
+    @Deprecated(forRemoval=true, since="12")
+    @SuppressWarnings("removal")
+    public R visitSwitchExpression(SwitchExpressionTree 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 visitCase(CaseTree node, P p) {
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Wed Aug 29 09:36:17 2018 +0200
@@ -26,6 +26,7 @@
 package com.sun.source.util;
 
 import com.sun.source.tree.*;
+import com.sun.source.tree.CaseTree.CaseKind;
 
 /**
  * A TreeVisitor that visits all the child tree nodes.
@@ -339,11 +340,36 @@
      * @param node  {@inheritDoc}
      * @param p  {@inheritDoc}
      * @return the result of scanning
+     *
+     * @deprecated
+     * This method is modeling switch expressions,
+     * which are part of a preview feature and may be removed
+     * if the preview feature is removed.
      */
     @Override
+    @Deprecated(forRemoval=true, since="12")
+    @SuppressWarnings("removal")
+    public R visitSwitchExpression(SwitchExpressionTree node, P p) {
+        R r = scan(node.getExpression(), p);
+        r = scanAndReduce(node.getCases(), p, r);
+        return r;
+    }
+
+    /**
+     * {@inheritDoc} This implementation scans the children in left to right order.
+     *
+     * @param node  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return the result of scanning
+     */
+    @Override
+    @SuppressWarnings("removal")
     public R visitCase(CaseTree node, P p) {
-        R r = scan(node.getExpression(), p);
-        r = scanAndReduce(node.getStatements(), p, r);
+        R r = scan(node.getExpressions(), p);
+        if (node.getCaseKind() == CaseKind.RULE)
+            r = scanAndReduce(node.getBody(), p, r);
+        else
+            r = scanAndReduce(node.getStatements(), p, r);
         return r;
     }
 
@@ -441,8 +467,9 @@
      * @return the result of scanning
      */
     @Override
+    @SuppressWarnings("removal")
     public R visitBreak(BreakTree node, P p) {
-        return null;
+        return scan(node.getValue(), p);
     }
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java	Wed Aug 29 09:36:17 2018 +0200
@@ -165,6 +165,10 @@
      * @return true, if given feature is a preview feature.
      */
     public boolean isPreview(Feature feature) {
+        if (feature == Feature.SWITCH_EXPRESSION ||
+            feature == Feature.SWITCH_MULTIPLE_CASE_LABELS ||
+            feature == Feature.SWITCH_RULE)
+            return true;
         //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
         //When real preview features will be added, this method can be implemented to return 'true'
         //for those selected features, and 'false' for all the others.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Aug 29 09:36:17 2018 +0200
@@ -180,7 +180,10 @@
         UNDERSCORE_IDENTIFIER(MIN, JDK8),
         PRIVATE_INTERFACE_METHODS(JDK9, Fragments.FeaturePrivateIntfMethods, DiagKind.PLURAL),
         LOCAL_VARIABLE_TYPE_INFERENCE(JDK10),
-        IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES(JDK1_2, JDK8);
+        IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES(JDK1_2, JDK8),
+        SWITCH_MULTIPLE_CASE_LABELS(JDK12, Fragments.FeatureMultipleCaseLabels, DiagKind.PLURAL),
+        SWITCH_RULE(JDK12, Fragments.FeatureSwitchRules, DiagKind.PLURAL),
+        SWITCH_EXPRESSION(JDK12, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL);
 
         enum DiagKind {
             NORMAL,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Aug 29 09:36:17 2018 +0200
@@ -184,6 +184,7 @@
     public final Type noClassDefFoundErrorType;
     public final Type noSuchFieldErrorType;
     public final Type assertionErrorType;
+    public final Type incompatibleClassChangeErrorType;
     public final Type cloneNotSupportedExceptionType;
     public final Type annotationType;
     public final TypeSymbol enumSym;
@@ -526,6 +527,7 @@
         noClassDefFoundErrorType = enterClass("java.lang.NoClassDefFoundError");
         noSuchFieldErrorType = enterClass("java.lang.NoSuchFieldError");
         assertionErrorType = enterClass("java.lang.AssertionError");
+        incompatibleClassChangeErrorType = enterClass("java.lang.IncompatibleClassChangeError");
         cloneNotSupportedExceptionType = enterClass("java.lang.CloneNotSupportedException");
         annotationType = enterClass("java.lang.annotation.Annotation");
         classLoaderType = enterClass("java.lang.ClassLoader");
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Wed Aug 29 09:36:17 2018 +0200
@@ -25,7 +25,6 @@
 
 package com.sun.tools.javac.comp;
 
-import com.sun.source.tree.LambdaExpressionTree.BodyKind;
 import com.sun.tools.javac.code.Flags;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symtab;
@@ -39,10 +38,12 @@
 import com.sun.tools.javac.comp.DeferredAttr.DeferredType;
 import com.sun.tools.javac.comp.DeferredAttr.DeferredTypeCompleter;
 import com.sun.tools.javac.comp.DeferredAttr.LambdaReturnScanner;
+import com.sun.tools.javac.comp.DeferredAttr.SwitchExpressionScanner;
 import com.sun.tools.javac.comp.Infer.PartiallyInferredMethodType;
 import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
 import com.sun.tools.javac.tree.JCTree.JCConditional;
 import com.sun.tools.javac.tree.JCTree.JCExpression;
 import com.sun.tools.javac.tree.JCTree.JCLambda;
@@ -52,6 +53,7 @@
 import com.sun.tools.javac.tree.JCTree.JCNewClass;
 import com.sun.tools.javac.tree.JCTree.JCParens;
 import com.sun.tools.javac.tree.JCTree.JCReturn;
+import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
 import com.sun.tools.javac.tree.TreeCopier;
 import com.sun.tools.javac.tree.TreeInfo;
 import com.sun.tools.javac.util.Assert;
@@ -145,7 +147,7 @@
      * Checks a type in the speculative tree against a given result; the type can be either a plain
      * type or an argument type,in which case a more complex check is required.
      */
-    Type checkSpeculative(JCExpression expr, ResultInfo resultInfo) {
+    Type checkSpeculative(JCTree expr, ResultInfo resultInfo) {
         return checkSpeculative(expr, expr.type, resultInfo);
     }
 
@@ -256,6 +258,11 @@
     }
 
     @Override
+    public void visitSwitchExpression(JCSwitchExpression that) {
+        processArg(that, speculativeTree -> new SwitchExpressionType(that, env, speculativeTree));
+    }
+
+    @Override
     public void visitReference(JCMemberReference tree) {
         //perform arity-based check
         Env<AttrContext> localEnv = env.dup(tree);
@@ -456,6 +463,61 @@
     }
 
     /**
+     * Argument type for switch expressions.
+     */
+    class SwitchExpressionType extends ArgumentType<JCSwitchExpression> {
+        /** List of break expressions (lazily populated). */
+        Optional<List<JCBreak>> breakExpressions = Optional.empty();
+
+        SwitchExpressionType(JCExpression tree, Env<AttrContext> env, JCSwitchExpression speculativeCond) {
+            this(tree, env, speculativeCond, new HashMap<>());
+        }
+
+        SwitchExpressionType(JCExpression tree, Env<AttrContext> env, JCSwitchExpression speculativeCond, Map<ResultInfo, Type> speculativeTypes) {
+           super(tree, env, speculativeCond, speculativeTypes);
+        }
+
+        @Override
+        Type overloadCheck(ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
+            ResultInfo localInfo = resultInfo.dup(attr.conditionalContext(resultInfo.checkContext));
+            if (resultInfo.pt.hasTag(VOID)) {
+                //this means we are returning a poly switch expression from void-compatible lambda expression
+                resultInfo.checkContext.report(tree, attr.diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid));
+                return attr.types.createErrorType(resultInfo.pt);
+            } else {
+                //poly
+                for (JCBreak brk : breakExpressions()) {
+                    checkSpeculative(brk.value, brk.value.type, resultInfo);
+                }
+                return localInfo.pt;
+            }
+        }
+
+        /** Compute return expressions (if needed). */
+        List<JCBreak> breakExpressions() {
+            return breakExpressions.orElseGet(() -> {
+                final List<JCBreak> res;
+                ListBuffer<JCBreak> buf = new ListBuffer<>();
+                new SwitchExpressionScanner() {
+                    @Override
+                    public void visitBreak(JCBreak tree) {
+                        if (tree.target == speculativeTree)
+                            buf.add(tree);
+                    }
+                }.scan(speculativeTree.cases);
+                res = buf.toList();
+                breakExpressions = Optional.of(res);
+                return res;
+            });
+        }
+
+        @Override
+        ArgumentType<JCSwitchExpression> dup(JCSwitchExpression tree, Env<AttrContext> env) {
+            return new SwitchExpressionType(tree, env, speculativeTree, speculativeTypes);
+        }
+    }
+
+    /**
      * Argument type for explicit lambdas.
      */
     class ExplicitLambdaType extends ArgumentType<JCLambda> {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Aug 29 09:36:17 2018 +0200
@@ -26,10 +26,13 @@
 package com.sun.tools.javac.comp;
 
 import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
 
 import javax.lang.model.element.ElementKind;
 import javax.tools.JavaFileObject;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.MemberSelectTree;
@@ -1395,41 +1398,123 @@
     }
 
     public void visitSwitch(JCSwitch tree) {
-        Type seltype = attribExpr(tree.selector, env);
+        handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
+            attribStats(c.stats, caseEnv);
+        });
+        result = null;
+    }
+
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        tree.polyKind = (pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly) ?
+                PolyKind.STANDALONE : PolyKind.POLY;
+
+        if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) {
+            //this means we are returning a poly conditional from void-compatible lambda expression
+            resultInfo.checkContext.report(tree, diags.fragment(Fragments.SwitchExpressionTargetCantBeVoid));
+            result = tree.type = types.createErrorType(resultInfo.pt);
+            return;
+        }
+
+        ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ?
+                unknownExprInfo :
+                resultInfo.dup(switchExpressionContext(resultInfo.checkContext));
+
+        ListBuffer<DiagnosticPosition> caseTypePositions = new ListBuffer<>();
+        ListBuffer<Type> caseTypes = new ListBuffer<>();
+
+        handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
+            caseEnv.info.breakResult = condInfo;
+            attribStats(c.stats, caseEnv);
+            new TreeScanner() {
+                @Override
+                public void visitBreak(JCBreak brk) {
+                    if (brk.target == tree) {
+                        caseTypePositions.append(brk.value != null ? brk.value.pos() : brk.pos());
+                        caseTypes.append(brk.value != null ? brk.value.type : syms.errType);
+                    }
+                    super.visitBreak(brk);
+                }
+
+                @Override public void visitClassDef(JCClassDecl tree) {}
+                @Override public void visitLambda(JCLambda tree) {}
+            }.scan(c.stats);
+        });
+
+        if (tree.cases.isEmpty()) {
+            log.error(tree.pos(),
+                      Errors.SwitchExpressionEmpty);
+        }
+
+        Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(caseTypePositions.toList(), caseTypes.toList()) : pt();
+
+        result = tree.type = check(tree, owntype, KindSelector.VAL, resultInfo);
+    }
+    //where:
+        CheckContext switchExpressionContext(CheckContext checkContext) {
+            return new Check.NestedCheckContext(checkContext) {
+                //this will use enclosing check context to check compatibility of
+                //subexpression against target type; if we are in a method check context,
+                //depending on whether boxing is allowed, we could have incompatibilities
+                @Override
+                public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                    enclosingContext.report(pos, diags.fragment(Fragments.IncompatibleTypeInSwitchExpression(details)));
+                }
+            };
+        }
+
+    private void handleSwitch(JCTree switchTree,
+                              JCExpression selector,
+                              List<JCCase> cases,
+                              BiConsumer<JCCase, Env<AttrContext>> attribCase) {
+        Type seltype = attribExpr(selector, env);
 
         Env<AttrContext> switchEnv =
-            env.dup(tree, env.info.dup(env.info.scope.dup()));
+            env.dup(switchTree, env.info.dup(env.info.scope.dup()));
 
         try {
-
             boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
             boolean stringSwitch = types.isSameType(seltype, syms.stringType);
             if (!enumSwitch && !stringSwitch)
-                seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
+                seltype = chk.checkType(selector.pos(), seltype, syms.intType);
 
             // Attribute all cases and
             // check that there are no duplicate case labels or default clauses.
             Set<Object> labels = new HashSet<>(); // The set of case labels.
             boolean hasDefault = false;      // Is there a default label?
-            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+            @SuppressWarnings("removal")
+            CaseKind caseKind = null;
+            boolean wasError = false;
+            for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 JCCase c = l.head;
-                if (c.pat != null) {
-                    if (enumSwitch) {
-                        Symbol sym = enumConstant(c.pat, seltype);
-                        if (sym == null) {
-                            log.error(c.pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
-                        } else if (!labels.add(sym)) {
-                            log.error(c.pos(), Errors.DuplicateCaseLabel);
-                        }
-                    } else {
-                        Type pattype = attribExpr(c.pat, switchEnv, seltype);
-                        if (!pattype.hasTag(ERROR)) {
-                            if (pattype.constValue() == null) {
-                                log.error(c.pat.pos(),
-                                          (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
-                            } else if (!labels.add(pattype.constValue())) {
+                if (caseKind == null) {
+                    caseKind = c.caseKind;
+                } else if (caseKind != c.caseKind && !wasError) {
+                    log.error(c.pos(),
+                              Errors.SwitchMixingCaseTypes);
+                    wasError = true;
+                }
+                if (c.getExpressions().nonEmpty()) {
+                    for (JCExpression pat : c.getExpressions()) {
+                        if (TreeInfo.isNull(pat)) {
+                            log.error(pat.pos(),
+                                      Errors.SwitchNullNotAllowed);
+                        } else if (enumSwitch) {
+                            Symbol sym = enumConstant(pat, seltype);
+                            if (sym == null) {
+                                log.error(pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
+                            } else if (!labels.add(sym)) {
                                 log.error(c.pos(), Errors.DuplicateCaseLabel);
                             }
+                        } else {
+                            Type pattype = attribExpr(pat, switchEnv, seltype);
+                            if (!pattype.hasTag(ERROR)) {
+                                if (pattype.constValue() == null) {
+                                    log.error(pat.pos(),
+                                              (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
+                                } else if (!labels.add(pattype.constValue())) {
+                                    log.error(c.pos(), Errors.DuplicateCaseLabel);
+                                }
+                            }
                         }
                     }
                 } else if (hasDefault) {
@@ -1440,16 +1525,13 @@
                 Env<AttrContext> caseEnv =
                     switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
                 try {
-                    attribStats(c.stats, caseEnv);
+                    attribCase.accept(c, caseEnv);
                 } finally {
                     caseEnv.info.scope.leave();
                     addVars(c.stats, switchEnv.info.scope);
                 }
             }
-
-            result = null;
-        }
-        finally {
+        } finally {
             switchEnv.info.scope.leave();
         }
     }
@@ -1609,7 +1691,9 @@
         Type truetype = attribTree(tree.truepart, env, condInfo);
         Type falsetype = attribTree(tree.falsepart, env, condInfo);
 
-        Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(tree, truetype, falsetype) : pt();
+        Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
+                condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
+                         List.of(truetype, falsetype)) : pt();
         if (condtype.constValue() != null &&
                 truetype.constValue() != null &&
                 falsetype.constValue() != null &&
@@ -1690,67 +1774,66 @@
          *  @param thentype The type of the expression's then-part.
          *  @param elsetype The type of the expression's else-part.
          */
-        Type condType(DiagnosticPosition pos,
-                               Type thentype, Type elsetype) {
+        Type condType(List<DiagnosticPosition> positions, List<Type> condTypes) {
+            if (condTypes.isEmpty()) {
+                return syms.objectType; //TODO: how to handle?
+            }
+            if (condTypes.size() == 1) {
+                return condTypes.head;
+            }
+            Type first = condTypes.head;
             // If same type, that is the result
-            if (types.isSameType(thentype, elsetype))
-                return thentype.baseType();
-
-            Type thenUnboxed = (thentype.isPrimitive())
-                ? thentype : types.unboxedType(thentype);
-            Type elseUnboxed = (elsetype.isPrimitive())
-                ? elsetype : types.unboxedType(elsetype);
+            if (condTypes.tail.stream().allMatch(t -> types.isSameType(first, t)))
+                return first.baseType();
+
+            List<Type> unboxedTypes = condTypes.stream()
+                                               .map(t -> t.isPrimitive() ? t : types.unboxedType(t))
+                                               .collect(List.collector());
 
             // Otherwise, if both arms can be converted to a numeric
             // type, return the least numeric type that fits both arms
             // (i.e. return larger of the two, or return int if one
             // arm is short, the other is char).
-            if (thenUnboxed.isPrimitive() && elseUnboxed.isPrimitive()) {
+            if (unboxedTypes.stream().allMatch(t -> t.isPrimitive())) {
                 // If one arm has an integer subrange type (i.e., byte,
                 // short, or char), and the other is an integer constant
                 // that fits into the subrange, return the subrange type.
-                if (thenUnboxed.getTag().isStrictSubRangeOf(INT) &&
-                    elseUnboxed.hasTag(INT) &&
-                    types.isAssignable(elseUnboxed, thenUnboxed)) {
-                    return thenUnboxed.baseType();
-                }
-                if (elseUnboxed.getTag().isStrictSubRangeOf(INT) &&
-                    thenUnboxed.hasTag(INT) &&
-                    types.isAssignable(thenUnboxed, elseUnboxed)) {
-                    return elseUnboxed.baseType();
+                for (Type type : unboxedTypes) {
+                    if (!type.getTag().isStrictSubRangeOf(INT)) {
+                        continue;
+                    }
+                    if (unboxedTypes.stream().filter(t -> t != type).allMatch(t -> t.hasTag(INT) && types.isAssignable(t, type)))
+                        return type.baseType();
                 }
 
                 for (TypeTag tag : primitiveTags) {
                     Type candidate = syms.typeOfTag[tag.ordinal()];
-                    if (types.isSubtype(thenUnboxed, candidate) &&
-                        types.isSubtype(elseUnboxed, candidate)) {
+                    if (unboxedTypes.stream().allMatch(t -> types.isSubtype(t, candidate))) {
                         return candidate;
                     }
                 }
             }
 
             // Those were all the cases that could result in a primitive
-            if (thentype.isPrimitive())
-                thentype = types.boxedClass(thentype).type;
-            if (elsetype.isPrimitive())
-                elsetype = types.boxedClass(elsetype).type;
-
-            if (types.isSubtype(thentype, elsetype))
-                return elsetype.baseType();
-            if (types.isSubtype(elsetype, thentype))
-                return thentype.baseType();
-
-            if (thentype.hasTag(VOID) || elsetype.hasTag(VOID)) {
-                log.error(pos,
-                          Errors.NeitherConditionalSubtype(thentype,
-                                                           elsetype));
-                return thentype.baseType();
-            }
+            condTypes = condTypes.stream()
+                                 .map(t -> t.isPrimitive() ? types.boxedClass(t).type : t)
+                                 .collect(List.collector());
+
+            for (Type type : condTypes) {
+                if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
+                    return type.baseType();
+            }
+
+            Iterator<DiagnosticPosition> posIt = positions.iterator();
+
+            condTypes = condTypes.stream()
+                                 .map(t -> chk.checkNonVoid(posIt.next(), t))
+                                 .collect(List.collector());
 
             // both are known to be reference types.  The result is
             // lub(thentype,elsetype). This cannot fail, as it will
             // always be possible to infer "Object" if nothing better.
-            return types.lub(thentype.baseType(), elsetype.baseType());
+            return types.lub(condTypes.stream().map(t -> t.baseType()).collect(List.collector()));
         }
 
     final static TypeTag[] primitiveTags = new TypeTag[]{
@@ -1782,7 +1865,68 @@
     }
 
     public void visitBreak(JCBreak tree) {
-        tree.target = findJumpTarget(tree.pos(), tree.getTag(), tree.label, env);
+        if (env.info.breakResult != null) {
+            if (tree.value == null) {
+                tree.target = findJumpTarget(tree.pos(), tree.getTag(), null, env);
+                if (tree.target.hasTag(SWITCH_EXPRESSION)) {
+                    log.error(tree.pos(), Errors.BreakMissingValue);
+                }
+            } else {
+                if (env.info.breakResult.pt.hasTag(VOID)) {
+                    //can happen?
+                    env.info.breakResult.checkContext.report(tree.value.pos(),
+                              diags.fragment(Fragments.UnexpectedRetVal));
+                }
+                boolean attribute = true;
+                if (tree.value.hasTag(IDENT)) {
+                    //disambiguate break <LABEL> and break <ident-as-an-expression>:
+                    Name label = ((JCIdent) tree.value).name;
+                    Pair<JCTree, Error> jumpTarget = findJumpTargetNoError(tree.getTag(), label, env);
+
+                    if (jumpTarget.fst != null) {
+                        JCTree speculative = deferredAttr.attribSpeculative(tree.value, env, unknownExprInfo);
+                        if (!speculative.type.hasTag(ERROR)) {
+                            log.error(tree.pos(), Errors.BreakAmbiguousTarget(label));
+                            if (jumpTarget.snd == null) {
+                                tree.target = jumpTarget.fst;
+                                attribute = false;
+                            } else {
+                                //nothing
+                            }
+                        } else {
+                            if (jumpTarget.snd != null) {
+                                log.error(tree.pos(), jumpTarget.snd);
+                            }
+                            tree.target = jumpTarget.fst;
+                            attribute = false;
+                        }
+                    }
+                }
+                if (attribute) {
+                    attribTree(tree.value, env, env.info.breakResult);
+                    JCTree immediateTarget = findJumpTarget(tree.pos(), tree.getTag(), null, env);
+                    if (immediateTarget.getTag() != SWITCH_EXPRESSION) {
+                        log.error(tree.pos(), Errors.BreakExprNotImmediate(immediateTarget.getTag()));
+                        Env<AttrContext> env1 = env;
+                        while (env1 != null && env1.tree.getTag() != SWITCH_EXPRESSION) {
+                            env1 = env1.next;
+                        }
+                        Assert.checkNonNull(env1);
+                        tree.target = env1.tree;
+                    } else {
+                        tree.target = immediateTarget;
+                    }
+                }
+            }
+        } else {
+            if (tree.value == null || tree.value.hasTag(IDENT)) {
+                Name label = tree.value != null ? ((JCIdent) tree.value).name : null;
+                tree.target = findJumpTarget(tree.pos(), tree.getTag(), label, env);
+            } else {
+                log.error(tree.pos(), Errors.BreakComplexValueNoSwitchExpression);
+                attribTree(tree.value, env, unknownExprInfo);
+            }
+        }
         result = null;
     }
 
@@ -1805,11 +1949,35 @@
          *  @param env     The environment current at the jump statement.
          */
         private JCTree findJumpTarget(DiagnosticPosition pos,
-                                    JCTree.Tag tag,
-                                    Name label,
-                                    Env<AttrContext> env) {
+                                                   JCTree.Tag tag,
+                                                   Name label,
+                                                   Env<AttrContext> env) {
+            Pair<JCTree, Error> jumpTarget = findJumpTargetNoError(tag, label, env);
+
+            if (jumpTarget.snd != null) {
+                log.error(pos, jumpTarget.snd);
+            }
+
+            return jumpTarget.fst;
+        }
+        /** Return the target of a break or continue statement, if it exists,
+         *  report an error if not.
+         *  Note: The target of a labelled break or continue is the
+         *  (non-labelled) statement tree referred to by the label,
+         *  not the tree representing the labelled statement itself.
+         *
+         *  @param tag     The tag of the jump statement. This is either
+         *                 Tree.BREAK or Tree.CONTINUE.
+         *  @param label   The label of the jump statement, or null if no
+         *                 label is given.
+         *  @param env     The environment current at the jump statement.
+         */
+        private Pair<JCTree, JCDiagnostic.Error> findJumpTargetNoError(JCTree.Tag tag,
+                                                                       Name label,
+                                                                       Env<AttrContext> env) {
             // Search environments outwards from the point of jump.
             Env<AttrContext> env1 = env;
+            JCDiagnostic.Error pendingError = null;
             LOOP:
             while (env1 != null) {
                 switch (env1.tree.getTag()) {
@@ -1821,13 +1989,14 @@
                                 if (!labelled.body.hasTag(DOLOOP) &&
                                         !labelled.body.hasTag(WHILELOOP) &&
                                         !labelled.body.hasTag(FORLOOP) &&
-                                        !labelled.body.hasTag(FOREACHLOOP))
-                                    log.error(pos, Errors.NotLoopLabel(label));
+                                        !labelled.body.hasTag(FOREACHLOOP)) {
+                                    pendingError = Errors.NotLoopLabel(label);
+                                }
                                 // Found labelled statement target, now go inwards
                                 // to next non-labelled tree.
-                                return TreeInfo.referencedStatement(labelled);
+                                return Pair.of(TreeInfo.referencedStatement(labelled), pendingError);
                             } else {
-                                return labelled;
+                                return Pair.of(labelled, pendingError);
                             }
                         }
                         break;
@@ -1835,10 +2004,21 @@
                     case WHILELOOP:
                     case FORLOOP:
                     case FOREACHLOOP:
-                        if (label == null) return env1.tree;
+                        if (label == null) return Pair.of(env1.tree, pendingError);
                         break;
                     case SWITCH:
-                        if (label == null && tag == BREAK) return env1.tree;
+                        if (label == null && tag == BREAK) return Pair.of(env1.tree, null);
+                        break;
+                    case SWITCH_EXPRESSION:
+                        if (tag == BREAK) {
+                            if (label == null) {
+                                return Pair.of(env1.tree, null);
+                            } else {
+                                pendingError = Errors.BreakOutsideSwitchExpression;
+                            }
+                        } else {
+                            pendingError = Errors.ContinueOutsideSwitchExpression;
+                        }
                         break;
                     case LAMBDA:
                     case METHODDEF:
@@ -1849,12 +2029,11 @@
                 env1 = env1.next;
             }
             if (label != null)
-                log.error(pos, Errors.UndefLabel(label));
+                return Pair.of(null, Errors.UndefLabel(label));
             else if (tag == CONTINUE)
-                log.error(pos, Errors.ContOutsideLoop);
+                return Pair.of(null, Errors.ContOutsideLoop);
             else
-                log.error(pos, Errors.BreakOutsideSwitchLoop);
-            return null;
+                return Pair.of(null, Errors.BreakOutsideSwitchLoop);
         }
 
     public void visitReturn(JCReturn tree) {
@@ -1862,6 +2041,8 @@
         // nested within than the enclosing class.
         if (env.info.returnResult == null) {
             log.error(tree.pos(), Errors.RetOutsideMeth);
+        } else if (env.info.breakResult != null) {
+            log.error(tree.pos(), Errors.ReturnOutsideSwitchExpression);
         } else {
             // Attribute return expression, if it exists, and check that
             // it conforms to result type of enclosing method.
@@ -2944,6 +3125,7 @@
             } else {
                 lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
             }
+            lambdaEnv.info.breakResult = null;
             return lambdaEnv;
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Wed Aug 29 09:36:17 2018 +0200
@@ -101,6 +101,11 @@
      */
     Attr.ResultInfo returnResult = null;
 
+    /** ResultInfo to be used for attributing 'break' statement expressions
+     * (set by Attr.visitSwitchExpression)
+     */
+    Attr.ResultInfo breakResult = null;
+
     /** Symbol corresponding to the site of a qualified default super call
      */
     Type defaultSuperCallSite = null;
@@ -124,6 +129,7 @@
         info.lint = lint;
         info.enclVar = enclVar;
         info.returnResult = returnResult;
+        info.breakResult = breakResult;
         info.defaultSuperCallSite = defaultSuperCallSite;
         info.isSerializable = isSerializable;
         info.isLambda = isLambda;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Wed Aug 29 09:36:17 2018 +0200
@@ -1154,6 +1154,18 @@
     }
 
     /**
+     * A tree scanner suitable for visiting the target-type dependent nodes nested
+     * within a switch expression body.
+     */
+    static class SwitchExpressionScanner extends FilterScanner {
+
+        SwitchExpressionScanner() {
+            super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP,
+                    FORLOOP, IF, BREAK, SYNCHRONIZED, SWITCH, TRY, WHILELOOP));
+        }
+    }
+
+    /**
      * This visitor is used to check that structural expressions conform
      * to their target - this step is required as inference could end up
      * inferring types that make some of the nested expressions incompatible
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Aug 29 09:36:17 2018 +0200
@@ -28,6 +28,8 @@
 package com.sun.tools.javac.comp;
 
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
 
 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
 import com.sun.tools.javac.code.*;
@@ -211,7 +213,7 @@
 
     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
         new AliveAnalyzer().analyzeTree(env, make);
-        new AssignAnalyzer().analyzeTree(env);
+        new AssignAnalyzer().analyzeTree(env, make);
         new FlowAnalyzer().analyzeTree(env, make);
         new CaptureAnalyzer().analyzeTree(env, make);
     }
@@ -244,7 +246,7 @@
         //related errors, which will allow for more errors to be detected
         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
         try {
-            new LambdaAssignAnalyzer(env).analyzeTree(env, that);
+            new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
             flowAnalyzer.analyzeTree(env, that, make);
             return flowAnalyzer.inferredThrownTypes;
@@ -396,6 +398,12 @@
         public void visitPackageDef(JCPackageDecl tree) {
             // Do nothing for PackageDecl
         }
+
+        protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
+            JCBreak brk = make.at(Position.NOPOS).Break(null);
+            brk.target = swtch;
+            scan(brk);
+        }
     }
 
     /**
@@ -596,11 +604,19 @@
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
                 alive = true;
                 JCCase c = l.head;
-                if (c.pat == null)
+                if (c.pats.isEmpty())
                     hasDefault = true;
-                else
-                    scan(c.pat);
+                else {
+                    for (JCExpression pat : c.pats) {
+                        scan(pat);
+                    }
+                }
                 scanStats(c.stats);
+                c.completesNormally = alive;
+                if (alive && c.caseKind == JCCase.RULE) {
+                    scanSyntheticBreak(make, tree);
+                    alive = false;
+                }
                 // Warn about fall-through if lint switch fallthrough enabled.
                 if (alive &&
                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
@@ -615,6 +631,46 @@
             alive |= resolveBreaks(tree, prevPendingExits);
         }
 
+        @Override
+        public void visitSwitchExpression(JCSwitchExpression tree) {
+            ListBuffer<PendingExit> prevPendingExits = pendingExits;
+            pendingExits = new ListBuffer<>();
+            scan(tree.selector);
+            Set<Object> constants = null;
+            if ((tree.selector.type.tsym.flags() & ENUM) != 0) {
+                constants = new HashSet<>();
+                for (Symbol s : tree.selector.type.tsym.members().getSymbols(s -> (s.flags() & ENUM) != 0)) {
+                    constants.add(s.name);
+                }
+            }
+            boolean hasDefault = false;
+            boolean prevAlive = alive;
+            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+                alive = true;
+                JCCase c = l.head;
+                if (c.pats.isEmpty())
+                    hasDefault = true;
+                else {
+                    for (JCExpression pat : c.pats) {
+                        scan(pat);
+                        if (constants != null) {
+                            if (pat.hasTag(IDENT))
+                                constants.remove(((JCIdent) pat).name);
+                            if (pat.type != null)
+                                constants.remove(pat.type.constValue());
+                        }
+                    }
+                }
+                scanStats(c.stats);
+                c.completesNormally = alive;
+            }
+            if ((constants == null || !constants.isEmpty()) && !hasDefault) {
+                log.error(tree, Errors.NotExhaustive);
+            }
+            alive = prevAlive;
+            alive |= resolveBreaks(tree, prevPendingExits);
+        }
+
         public void visitTry(JCTry tree) {
             ListBuffer<PendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<>();
@@ -680,6 +736,8 @@
         }
 
         public void visitBreak(JCBreak tree) {
+            if (tree.isValueBreak())
+                scan(tree.value);
             recordExit(new PendingExit(tree));
         }
 
@@ -1040,14 +1098,21 @@
         }
 
         public void visitSwitch(JCSwitch tree) {
+            handleSwitch(tree, tree.selector, tree.cases);
+        }
+
+        @Override
+        public void visitSwitchExpression(JCSwitchExpression tree) {
+            handleSwitch(tree, tree.selector, tree.cases);
+        }
+
+        private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<>();
-            scan(tree.selector);
-            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+            scan(selector);
+            for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 JCCase c = l.head;
-                if (c.pat != null) {
-                    scan(c.pat);
-                }
+                scan(c.pats);
                 scan(c.stats);
             }
             resolveBreaks(tree, prevPendingExits);
@@ -1191,6 +1256,8 @@
             }
 
         public void visitBreak(JCBreak tree) {
+            if (tree.isValueBreak())
+                scan(tree.value);
             recordExit(new FlowPendingExit(tree, null));
         }
 
@@ -2105,27 +2172,40 @@
         }
 
         public void visitSwitch(JCSwitch tree) {
+            handleSwitch(tree, tree.selector, tree.cases);
+        }
+
+        public void visitSwitchExpression(JCSwitchExpression tree) {
+            handleSwitch(tree, tree.selector, tree.cases);
+        }
+
+        private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<>();
             int nextadrPrev = nextadr;
-            scanExpr(tree.selector);
+            scanExpr(selector);
             final Bits initsSwitch = new Bits(inits);
             final Bits uninitsSwitch = new Bits(uninits);
             boolean hasDefault = false;
-            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+            for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 inits.assign(initsSwitch);
                 uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
-                if (c.pat == null) {
+                if (c.pats.isEmpty()) {
                     hasDefault = true;
                 } else {
-                    scanExpr(c.pat);
+                    for (JCExpression pat : c.pats) {
+                        scanExpr(pat);
+                    }
                 }
                 if (hasDefault) {
                     inits.assign(initsSwitch);
                     uninits.assign(uninits.andSet(uninitsSwitch));
                 }
                 scan(c.stats);
+                if (c.completesNormally && c.caseKind == JCCase.RULE) {
+                    scanSyntheticBreak(make, tree);
+                }
                 addVars(c.stats, initsSwitch, uninitsSwitch);
                 if (!hasDefault) {
                     inits.assign(initsSwitch);
@@ -2301,6 +2381,8 @@
 
         @Override
         public void visitBreak(JCBreak tree) {
+            if (tree.isValueBreak())
+                scan(tree.value);
             recordExit(new AssignPendingExit(tree, inits, uninits));
         }
 
@@ -2479,11 +2561,11 @@
 
         /** Perform definite assignment/unassignment analysis on a tree.
          */
-        public void analyzeTree(Env<?> env) {
-            analyzeTree(env, env.tree);
+        public void analyzeTree(Env<?> env, TreeMaker make) {
+            analyzeTree(env, env.tree, make);
          }
 
-        public void analyzeTree(Env<?> env, JCTree tree) {
+        public void analyzeTree(Env<?> env, JCTree tree, TreeMaker make) {
             try {
                 startPos = tree.pos().getStartPosition();
 
@@ -2494,6 +2576,7 @@
                         vardecls[i] = null;
                 firstadr = 0;
                 nextadr = 0;
+                Flow.this.make = make;
                 pendingExits = new ListBuffer<>();
                 this.classDef = null;
                 unrefdResources = WriteableScope.create(env.enclClass.sym);
@@ -2509,6 +2592,7 @@
                 }
                 firstadr = 0;
                 nextadr = 0;
+                Flow.this.make = null;
                 pendingExits = null;
                 this.classDef = null;
                 unrefdResources = null;
@@ -2661,6 +2745,12 @@
             super.visitTry(tree);
         }
 
+        @Override
+        public void visitBreak(JCBreak tree) {
+            if (tree.isValueBreak())
+                scan(tree.value);
+        }
+
         public void visitModuleDef(JCModuleDecl tree) {
             // Do nothing for modules
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Aug 29 09:36:17 2018 +0200
@@ -715,7 +715,7 @@
             JCBreak br = make.Break(null);
             breaks.add(br);
             List<JCStatement> stmts = entry.getValue().append(br).toList();
-            cases.add(make.Case(make.Literal(entry.getKey()), stmts));
+            cases.add(make.Case(JCCase.STATEMENT, List.of(make.Literal(entry.getKey())), stmts, null));
         }
         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
         for (JCBreak br : breaks) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Aug 29 09:36:17 2018 +0200
@@ -26,7 +26,11 @@
 package com.sun.tools.javac.comp;
 
 import java.util.*;
-
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Scope.WriteableScope;
@@ -54,6 +58,10 @@
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
 import static com.sun.tools.javac.jvm.ByteCodes.*;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
+import com.sun.tools.javac.tree.JCTree.JCCase;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
@@ -263,6 +271,13 @@
             }
             super.visitApply(tree);
         }
+
+        @Override
+        public void visitBreak(JCBreak tree) {
+            if (tree.isValueBreak())
+                scan(tree.value);
+        }
+
     }
 
     /**
@@ -364,6 +379,7 @@
             }
             super.visitApply(tree);
         }
+
     }
 
     ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
@@ -3340,6 +3356,45 @@
     }
 
     public void visitSwitch(JCSwitch tree) {
+        //expand multiple label cases:
+        ListBuffer<JCCase> cases = new ListBuffer<>();
+
+        for (JCCase c : tree.cases) {
+            switch (c.pats.size()) {
+                case 0: //default
+                case 1: //single label
+                    cases.append(c);
+                    break;
+                default: //multiple labels, expand:
+                    //case C1, C2, C3: ...
+                    //=>
+                    //case C1:
+                    //case C2:
+                    //case C3: ...
+                    List<JCExpression> patterns = c.pats;
+                    while (patterns.tail.nonEmpty()) {
+                        cases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
+                                                           List.of(patterns.head),
+                                                           List.nil(),
+                                                           null));
+                        patterns = patterns.tail;
+                    }
+                    c.pats = patterns;
+                    cases.append(c);
+                    break;
+            }
+        }
+
+        for (JCCase c : cases) {
+            if (c.caseKind == JCCase.RULE && c.completesNormally) {
+                JCBreak b = make_at(c.pos()).Break(null);
+                b.target = tree;
+                c.stats = c.stats.append(b);
+            }
+        }
+
+        tree.cases = cases.toList();
+
         Type selsuper = types.supertype(tree.selector.type);
         boolean enumSwitch = selsuper != null &&
             (tree.selector.type.tsym.flags() & ENUM) != 0;
@@ -3371,10 +3426,10 @@
                                                              ordinalMethod)));
         ListBuffer<JCCase> cases = new ListBuffer<>();
         for (JCCase c : tree.cases) {
-            if (c.pat != null) {
-                VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
+            if (c.pats.nonEmpty()) {
+                VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
                 JCLiteral pat = map.forConstant(label);
-                cases.append(make.Case(pat, c.stats));
+                cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
             } else {
                 cases.append(c);
             }
@@ -3442,10 +3497,10 @@
             Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
 
             int casePosition = 0;
+
             for(JCCase oneCase : caseList) {
-                JCExpression expression = oneCase.getExpression();
-
-                if (expression != null) { // expression for a "default" case is null
+                if (oneCase.pats.nonEmpty()) { // pats is empty for a "default" case
+                    JCExpression expression = oneCase.pats.head;
                     String labelExpr = (String) expression.type.constValue();
                     Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
                     Assert.checkNull(mapping);
@@ -3529,7 +3584,7 @@
                 breakStmt.target = switch1;
                 lb.append(elsepart).append(breakStmt);
 
-                caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
+                caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
             }
 
             switch1.cases = caseBuffer.toList();
@@ -3546,18 +3601,17 @@
                 // replacement switch being created.
                 patchTargets(oneCase, tree, switch2);
 
-                boolean isDefault = (oneCase.getExpression() == null);
+                boolean isDefault = (oneCase.pats.isEmpty());
                 JCExpression caseExpr;
                 if (isDefault)
                     caseExpr = null;
                 else {
-                    caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
-                                                                                                getExpression()).
+                    caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
                                                                     type.constValue()));
                 }
 
-                lb.append(make.Case(caseExpr,
-                                    oneCase.getStatements()));
+                lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
+                                    oneCase.getStatements(), null));
             }
 
             switch2.cases = lb.toList();
@@ -3567,6 +3621,76 @@
         }
     }
 
+    @Override
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        //translates switch expression to statement switch:
+        //switch (selector) {
+        //    case C: break value;
+        //    ...
+        //}
+        //=>
+        //(letexpr T exprswitch$;
+        //         switch (selector) {
+        //             case C: { exprswitch$ = value; break; }
+        //         }
+        //         exprswitch$
+        //)
+        VarSymbol dollar_switchexpr = new VarSymbol(Flags.FINAL|Flags.SYNTHETIC,
+                           names.fromString("exprswitch" + tree.pos + target.syntheticNameChar()),
+                           tree.type,
+                           currentMethodSym);
+
+        ListBuffer<JCStatement> stmtList = new ListBuffer<>();
+
+        stmtList.append(make.at(tree.pos()).VarDef(dollar_switchexpr, null).setType(dollar_switchexpr.type));
+        JCSwitch switchStatement = make.Switch(tree.selector, null);
+        switchStatement.cases =
+                tree.cases.stream()
+                          .map(c -> convertCase(dollar_switchexpr, switchStatement, tree, c))
+                          .collect(List.collector());
+        if (tree.cases.stream().noneMatch(c -> c.pats.isEmpty())) {
+            JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
+                                                  List.nil()));
+            JCCase c = make.Case(JCCase.STATEMENT, List.nil(), List.of(thr), null);
+            switchStatement.cases = switchStatement.cases.append(c);
+        }
+
+        stmtList.append(translate(switchStatement));
+
+        result = make.LetExpr(stmtList.toList(), make.Ident(dollar_switchexpr))
+                     .setType(dollar_switchexpr.type);
+    }
+        //where:
+        private JCCase convertCase(VarSymbol dollar_switchexpr, JCSwitch switchStatement,
+                                   JCSwitchExpression switchExpr, JCCase c) {
+            make.at(c.pos());
+            ListBuffer<JCStatement> statements = new ListBuffer<>();
+            statements.addAll(new TreeTranslator() {
+                @Override
+                public void visitLambda(JCLambda tree) {}
+                @Override
+                public void visitClassDef(JCClassDecl tree) {}
+                @Override
+                public void visitMethodDef(JCMethodDecl tree) {}
+                @Override
+                public void visitBreak(JCBreak tree) {
+                    if (tree.target == switchExpr) {
+                        tree.target = switchStatement;
+                        JCExpressionStatement assignment =
+                                make.Exec(make.Assign(make.Ident(dollar_switchexpr),
+                                                      translate(tree.value))
+                                              .setType(dollar_switchexpr.type));
+                        result = make.Block(0, List.of(assignment,
+                                                       tree));
+                        tree.value = null;
+                    } else {
+                        result = tree;
+                    }
+                }
+            }.translate(c.stats));
+            return make.Case(JCCase.STATEMENT, c.pats, statements.toList(), null);
+        }
+
     public void visitNewArray(JCNewArray tree) {
         tree.elemtype = translate(tree.elemtype);
         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
@@ -3602,7 +3726,7 @@
     }
 
     public void visitLetExpr(LetExpr tree) {
-        tree.defs = translateVarDefs(tree.defs);
+        tree.defs = translate(tree.defs);
         tree.expr = translate(tree.expr, tree.type);
         result = tree;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Wed Aug 29 09:36:17 2018 +0200
@@ -48,6 +48,7 @@
 import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
 import static com.sun.tools.javac.code.TypeTag.VOID;
 import static com.sun.tools.javac.comp.CompileStates.CompileState;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
 
 /** This pass translates Generic Java to conventional Java.
  *
@@ -561,11 +562,22 @@
     }
 
     public void visitCase(JCCase tree) {
-        tree.pat = translate(tree.pat, null);
+        tree.pats = translate(tree.pats, null);
         tree.stats = translate(tree.stats);
         result = tree;
     }
 
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        Type selsuper = types.supertype(tree.selector.type);
+        boolean enumSwitch = selsuper != null &&
+            selsuper.tsym == syms.enumSym;
+        Type target = enumSwitch ? erasure(tree.selector.type) : syms.intType;
+        tree.selector = translate(tree.selector, target);
+        tree.cases = translate(tree.cases);
+        tree.type = erasure(tree.type);
+        result = retype(tree, tree.type, pt);
+    }
+
     public void visitSynchronized(JCSynchronized tree) {
         tree.lock = translate(tree.lock, erasure(tree.lock.type));
         tree.body = translate(tree.body);
@@ -606,6 +618,16 @@
         result = tree;
     }
 
+    @Override
+    public void visitBreak(JCBreak tree) {
+        if (tree.isValueBreak()) {
+            tree.value = translate(tree.value, erasure(tree.value.type));
+            tree.value.type = erasure(tree.value.type);
+            tree.value = retype(tree.value, tree.value.type, pt);
+        }
+        result = tree;
+    }
+
     public void visitThrow(JCThrow tree) {
         tree.expr = translate(tree.expr, erasure(tree.expr.type));
         result = tree;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Wed Aug 29 09:36:17 2018 +0200
@@ -259,13 +259,13 @@
     @Override
     public void visitBreak(JCBreak tree) {
         JCBreak that = (JCBreak) parameter;
-        result = tree.label == that.label;
+        result = scan(tree.value, that.value);
     }
 
     @Override
     public void visitCase(JCCase tree) {
         JCCase that = (JCCase) parameter;
-        result = scan(tree.pat, that.pat) && scan(tree.stats, that.stats);
+        result = scan(tree.pats, that.pats) && scan(tree.stats, that.stats);
     }
 
     @Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Wed Aug 29 09:36:17 2018 +0200
@@ -313,7 +313,7 @@
 
         public void visitCase(JCCase tree) {
             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
-            sr.mergeWith(csp(tree.pat));
+            sr.mergeWith(csp(tree.pats));
             sr.mergeWith(csp(tree.stats));
             result = sr;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Aug 29 09:36:17 2018 +0200
@@ -183,6 +183,8 @@
 
     final MethodSymbol meth;
 
+    private int letExprStackPos = 0;
+
     /** Construct a code object, given the settings of the fatcode,
      *  debugging info switches and the CharacterRangeTable.
      */
@@ -382,7 +384,7 @@
     }
 
     void postop() {
-        Assert.check(alive || state.stacksize == 0);
+        Assert.check(alive || isStatementStart());
     }
 
     /** Emit a ldc (or ldc_w) instruction, taking into account operand size
@@ -1211,6 +1213,15 @@
         return pc;
     }
 
+    public int setLetExprStackPos(int pos) {
+        int res = letExprStackPos;
+        letExprStackPos = pos;
+        return res;
+    }
+
+    public boolean isStatementStart() {
+        return state.stacksize == letExprStackPos;
+    }
 
 /**************************************************************************
  * Stack map generation
@@ -1474,7 +1485,7 @@
         State newState = state;
         for (; chain != null; chain = chain.next) {
             Assert.check(state != chain.state
-                    && (target > chain.pc || state.stacksize == 0));
+                    && (target > chain.pc || isStatementStart()));
             if (target >= cp) {
                 target = cp;
             } else if (get1(target) == goto_) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Aug 29 09:36:17 2018 +0200
@@ -81,11 +81,6 @@
      */
     private final Type methodType;
 
-    /**
-     * Are we presently traversing a let expression ? Yes if depth != 0
-     */
-    private int letExprDepth;
-
     public static Gen instance(Context context) {
         Gen instance = context.get(genKey);
         if (instance == null)
@@ -1011,10 +1006,10 @@
         if (tree.init != null) {
             checkStringConstant(tree.init.pos(), v.getConstValue());
             if (v.getConstValue() == null || varDebugInfo) {
-                Assert.check(letExprDepth != 0 || code.state.stacksize == 0);
+                Assert.check(code.isStatementStart());
                 genExpr(tree.init, v.erasure(types)).load();
                 items.makeLocalItem(v).store();
-                Assert.check(letExprDepth != 0 || code.state.stacksize == 0);
+                Assert.check(code.isStatementStart());
             }
         }
         checkDimension(tree.pos(), v.type);
@@ -1069,14 +1064,14 @@
                 CondItem c;
                 if (cond != null) {
                     code.statBegin(cond.pos);
-                    Assert.check(code.state.stacksize == 0);
+                    Assert.check(code.isStatementStart());
                     c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
                 } else {
                     c = items.makeCondItem(goto_);
                 }
                 Chain loopDone = c.jumpFalse();
                 code.resolve(c.trueJumps);
-                Assert.check(code.state.stacksize == 0);
+                Assert.check(code.isStatementStart());
                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
                 code.resolve(loopEnv.info.cont);
                 genStats(step, loopEnv);
@@ -1090,13 +1085,13 @@
                     CondItem c;
                     if (cond != null) {
                         code.statBegin(cond.pos);
-                        Assert.check(code.state.stacksize == 0);
+                        Assert.check(code.isStatementStart());
                         c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
                     } else {
                         c = items.makeCondItem(goto_);
                     }
                     code.resolve(c.jumpTrue(), startpc);
-                    Assert.check(code.state.stacksize == 0);
+                    Assert.check(code.isStatementStart());
                     code.resolve(c.falseJumps);
                 }
             }
@@ -1125,7 +1120,7 @@
         int limit = code.nextreg;
         Assert.check(!tree.selector.type.hasTag(CLASS));
         int startpcCrt = genCrt ? code.curCP() : 0;
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         Item sel = genExpr(tree.selector, syms.intType);
         List<JCCase> cases = tree.cases;
         if (cases.isEmpty()) {
@@ -1154,8 +1149,9 @@
 
             List<JCCase> l = cases;
             for (int i = 0; i < labels.length; i++) {
-                if (l.head.pat != null) {
-                    int val = ((Number)l.head.pat.type.constValue()).intValue();
+                if (l.head.pats.nonEmpty()) {
+                    Assert.check(l.head.pats.size() == 1);
+                    int val = ((Number)l.head.pats.head.type.constValue()).intValue();
                     labels[i] = val;
                     if (val < lo) lo = val;
                     if (hi < val) hi = val;
@@ -1294,7 +1290,7 @@
         int limit = code.nextreg;
         // Generate code to evaluate lock and save in temporary variable.
         final LocalItem lockVar = makeTemp(syms.objectType);
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         genExpr(tree.lock, tree.lock.type).load().duplicate();
         lockVar.store();
 
@@ -1556,11 +1552,11 @@
     public void visitIf(JCIf tree) {
         int limit = code.nextreg;
         Chain thenExit = null;
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         CondItem c = genCond(TreeInfo.skipParens(tree.cond),
                              CRT_FLOW_CONTROLLER);
         Chain elseChain = c.jumpFalse();
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         if (!c.isFalse()) {
             code.resolve(c.trueJumps);
             genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
@@ -1574,7 +1570,7 @@
         }
         code.resolve(thenExit);
         code.endScopes(limit);
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
     }
 
     public void visitExec(JCExpressionStatement tree) {
@@ -1588,16 +1584,16 @@
                 ((JCUnary) e).setTag(PREDEC);
                 break;
         }
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         genExpr(tree.expr, tree.expr.type).drop();
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
     }
 
     public void visitBreak(JCBreak tree) {
         int tmpPos = code.pendingStatPos;
         Env<GenContext> targetEnv = unwind(tree.target, env);
         code.pendingStatPos = tmpPos;
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         targetEnv.info.addExit(code.branch(goto_));
         endFinalizerGaps(env, targetEnv);
     }
@@ -1606,7 +1602,7 @@
         int tmpPos = code.pendingStatPos;
         Env<GenContext> targetEnv = unwind(tree.target, env);
         code.pendingStatPos = tmpPos;
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         targetEnv.info.addCont(code.branch(goto_));
         endFinalizerGaps(env, targetEnv);
     }
@@ -1620,7 +1616,7 @@
          */
         int tmpPos = code.pendingStatPos;
         if (tree.expr != null) {
-            Assert.check(code.state.stacksize == 0);
+            Assert.check(code.isStatementStart());
             Item r = genExpr(tree.expr, pt).load();
             if (hasFinally(env.enclMethod, env)) {
                 r = makeTemp(pt);
@@ -1640,10 +1636,10 @@
     }
 
     public void visitThrow(JCThrow tree) {
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
         genExpr(tree.expr, tree.expr.type).load();
         code.emitop0(athrow);
-        Assert.check(code.state.stacksize == 0);
+        Assert.check(code.isStatementStart());
     }
 
 /* ************************************************************************
@@ -2147,12 +2143,15 @@
     }
 
     public void visitLetExpr(LetExpr tree) {
-        letExprDepth++;
         int limit = code.nextreg;
-        genStats(tree.defs, env);
+        int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
+        try {
+            genStats(tree.defs, env);
+        } finally {
+            code.setLetExprStackPos(prevLetExprStart);
+        }
         result = genExpr(tree.expr, tree.expr.type).load();
         code.endScopes(limit);
-        letExprDepth--;
     }
 
     private void generateReferencesToPrunedTree(ClassSymbol classSymbol, Pool pool) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Aug 29 09:36:17 2018 +0200
@@ -26,8 +26,10 @@
 package com.sun.tools.javac.parser;
 
 import java.util.*;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.ModuleTree.ModuleKind;
 
@@ -218,12 +220,22 @@
      *     mode = TYPE        : a type
      *     mode = NOPARAMS    : no parameters allowed for type
      *     mode = TYPEARG     : type argument
+     *     mode |= NOLAMBDA   : lambdas are not allowed
      */
     protected static final int EXPR = 0x1;
     protected static final int TYPE = 0x2;
     protected static final int NOPARAMS = 0x4;
     protected static final int TYPEARG = 0x8;
     protected static final int DIAMOND = 0x10;
+    protected static final int NOLAMBDA = 0x20;
+
+    protected void selectExprMode() {
+        mode = (mode & NOLAMBDA) | EXPR;
+    }
+
+    protected void selectTypeMode() {
+        mode = (mode & NOLAMBDA) | TYPE;
+    }
 
     /** The current mode.
      */
@@ -427,11 +439,18 @@
      *  an error.
      */
     public void accept(TokenKind tk) {
+        accept(tk, Errors::Expected);
+    }
+
+    /** If next input token matches given token, skip it, otherwise report
+     *  an error.
+     */
+    public void accept(TokenKind tk, Function<TokenKind, Error> errorProvider) {
         if (token.kind == tk) {
             nextToken();
         } else {
             setErrorEndPos(token.pos);
-            reportSyntaxError(S.prevToken().endPos, Errors.Expected(tk));
+            reportSyntaxError(S.prevToken().endPos, errorProvider.apply(tk));
         }
     }
 
@@ -796,7 +815,7 @@
         case EQ: {
             int pos = token.pos;
             nextToken();
-            mode = EXPR;
+            selectExprMode();
             JCExpression t1 = term();
             return toP(F.at(pos).Assign(t, t1));
         }
@@ -814,7 +833,7 @@
             int pos = token.pos;
             TokenKind tk = token.kind;
             nextToken();
-            mode = EXPR;
+            selectExprMode();
             JCExpression t1 = term();
             return F.at(pos).Assignop(optag(tk), t, t1);
         default:
@@ -829,7 +848,7 @@
     JCExpression term1() {
         JCExpression t = term2();
         if ((mode & EXPR) != 0 && token.kind == QUES) {
-            mode = EXPR;
+            selectExprMode();
             return term1Rest(t);
         } else {
             return t;
@@ -858,7 +877,7 @@
     JCExpression term2() {
         JCExpression t = term3();
         if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) {
-            mode = EXPR;
+            selectExprMode();
             return term2Rest(t, TreeInfo.orPrec);
         } else {
             return t;
@@ -1058,7 +1077,7 @@
         switch (token.kind) {
         case QUES:
             if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) {
-                mode = TYPE;
+                selectTypeMode();
                 return typeArgument();
             } else
                 return illegal();
@@ -1066,11 +1085,11 @@
             if (typeArgs == null && (mode & EXPR) != 0) {
                 TokenKind tk = token.kind;
                 nextToken();
-                mode = EXPR;
+                selectExprMode();
                 if (tk == SUB &&
                     (token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
                     token.radix() == 10) {
-                    mode = EXPR;
+                    selectExprMode();
                     t = literal(names.hyphen, pos);
                 } else {
                     t = term3();
@@ -1084,7 +1103,7 @@
                 switch (pres) {
                     case CAST:
                        accept(LPAREN);
-                       mode = TYPE;
+                       selectTypeMode();
                        int pos1 = pos;
                        List<JCExpression> targets = List.of(t = parseType());
                        while (token.kind == AMP) {
@@ -1096,7 +1115,7 @@
                            t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
                        }
                        accept(RPAREN);
-                       mode = EXPR;
+                       selectExprMode();
                        JCExpression t1 = term3();
                        return F.at(pos).TypeCast(t, t1);
                     case IMPLICIT_LAMBDA:
@@ -1105,7 +1124,7 @@
                         break;
                     default: //PARENS
                         accept(LPAREN);
-                        mode = EXPR;
+                        selectExprMode();
                         t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
                         accept(RPAREN);
                         t = toP(F.at(pos).Parens(t));
@@ -1117,7 +1136,7 @@
             break;
         case THIS:
             if ((mode & EXPR) != 0) {
-                mode = EXPR;
+                selectExprMode();
                 t = to(F.at(pos).Ident(names._this));
                 nextToken();
                 if (typeArgs == null)
@@ -1129,7 +1148,7 @@
             break;
         case SUPER:
             if ((mode & EXPR) != 0) {
-                mode = EXPR;
+                selectExprMode();
                 t = to(F.at(pos).Ident(names._super));
                 t = superSuffix(typeArgs, t);
                 typeArgs = null;
@@ -1139,14 +1158,14 @@
         case CHARLITERAL: case STRINGLITERAL:
         case TRUE: case FALSE: case NULL:
             if (typeArgs == null && (mode & EXPR) != 0) {
-                mode = EXPR;
+                selectExprMode();
                 t = literal(names.empty);
             } else return illegal();
             break;
         case NEW:
             if (typeArgs != null) return illegal();
             if ((mode & EXPR) != 0) {
-                mode = EXPR;
+                selectExprMode();
                 nextToken();
                 if (token.kind == LT) typeArgs = typeArguments(false);
                 t = creator(pos, typeArgs);
@@ -1193,7 +1212,7 @@
             break;
         case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
             if (typeArgs != null) return illegal();
-            if ((mode & EXPR) != 0 && peekToken(ARROW)) {
+            if ((mode & EXPR) != 0 && (mode & NOLAMBDA) == 0 && peekToken(ARROW)) {
                 t = lambdaExpressionOrStatement(false, false, pos);
             } else {
                 t = toP(F.at(token.pos).Ident(ident()));
@@ -1219,7 +1238,7 @@
                             t = bracketsSuffix(t);
                         } else {
                             if ((mode & EXPR) != 0) {
-                                mode = EXPR;
+                                selectExprMode();
                                 JCExpression t1 = term();
                                 if (!annos.isEmpty()) t = illegal(annos.head.pos);
                                 t = to(F.at(pos).Indexed(t, t1));
@@ -1229,7 +1248,7 @@
                         break loop;
                     case LPAREN:
                         if ((mode & EXPR) != 0) {
-                            mode = EXPR;
+                            selectExprMode();
                             t = arguments(typeArgs, t);
                             if (!annos.isEmpty()) t = illegal(annos.head.pos);
                             typeArgs = null;
@@ -1248,25 +1267,25 @@
                             switch (token.kind) {
                             case CLASS:
                                 if (typeArgs != null) return illegal();
-                                mode = EXPR;
+                                selectExprMode();
                                 t = to(F.at(pos).Select(t, names._class));
                                 nextToken();
                                 break loop;
                             case THIS:
                                 if (typeArgs != null) return illegal();
-                                mode = EXPR;
+                                selectExprMode();
                                 t = to(F.at(pos).Select(t, names._this));
                                 nextToken();
                                 break loop;
                             case SUPER:
-                                mode = EXPR;
+                                selectExprMode();
                                 t = to(F.at(pos).Select(t, names._super));
                                 t = superSuffix(typeArgs, t);
                                 typeArgs = null;
                                 break loop;
                             case NEW:
                                 if (typeArgs != null) return illegal();
-                                mode = EXPR;
+                                selectExprMode();
                                 int pos1 = token.pos;
                                 nextToken();
                                 if (token.kind == LT) typeArgs = typeArguments(false);
@@ -1310,7 +1329,7 @@
                             t = toP(F.at(pos1).TypeApply(t, args.toList()));
                             while (token.kind == DOT) {
                                 nextToken();
-                                mode = TYPE;
+                                selectTypeMode();
                                 t = toP(F.at(token.pos).Select(t, ident()));
                                 t = typeArgumentsOpt(t);
                             }
@@ -1319,7 +1338,7 @@
                                 //method reference expected here
                                 t = illegal();
                             }
-                            mode = EXPR;
+                            selectExprMode();
                             return term3Rest(t, typeArgs);
                         }
                         break loop;
@@ -1356,12 +1375,82 @@
                 //return illegal();
             }
             break;
+        case SWITCH:
+            checkSourceLevel(Feature.SWITCH_EXPRESSION);
+            int switchPos = token.pos;
+            nextToken();
+            JCExpression selector = parExpression();
+            accept(LBRACE);
+            ListBuffer<JCCase> cases = new ListBuffer<>();
+            while (true) {
+                pos = token.pos;
+                switch (token.kind) {
+                case CASE:
+                case DEFAULT:
+                    cases.appendList(switchExpressionStatementGroup());
+                    break;
+                case RBRACE: case EOF:
+                    JCSwitchExpression e = to(F.at(switchPos).SwitchExpression(selector,
+                                                                               cases.toList()));
+                    accept(RBRACE);
+                    return e;
+                default:
+                    nextToken(); // to ensure progress
+                    syntaxError(pos, Errors.Expected3(CASE, DEFAULT, RBRACE));
+                }
+            }
         default:
             return illegal();
         }
         return term3Rest(t, typeArgs);
     }
 
+    private List<JCCase> switchExpressionStatementGroup() {
+        ListBuffer<JCCase> caseExprs = new ListBuffer<>();
+        int casePos = token.pos;
+        ListBuffer<JCExpression> pats = new ListBuffer<>();
+
+        if (token.kind == DEFAULT) {
+            nextToken();
+        } else {
+            accept(CASE);
+            while (true) {
+                pats.append(term(EXPR | NOLAMBDA));
+                if (token.kind != COMMA) break;
+                checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
+                nextToken();
+            };
+        }
+        List<JCStatement> stats = null;
+        JCTree body = null;
+        @SuppressWarnings("removal")
+        CaseKind kind;
+        switch (token.kind) {
+            case ARROW:
+                checkSourceLevel(Feature.SWITCH_RULE);
+                nextToken();
+                if (token.kind == TokenKind.THROW || token.kind == TokenKind.LBRACE) {
+                    stats = List.of(parseStatement());
+                    body = stats.head;
+                    kind = JCCase.RULE;
+                } else {
+                    JCExpression value = parseExpression();
+                    stats = List.of(to(F.at(value).Break(value)));
+                    body = value;
+                    kind = JCCase.RULE;
+                    accept(SEMI);
+                }
+                break;
+            default:
+                accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
+                stats = blockStatements();
+                kind = JCCase.STATEMENT;
+                break;
+        }
+        caseExprs.append(toP(F.at(casePos).Case(kind, pats.toList(), stats, body)));
+        return caseExprs.toList();
+    }
+
     JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
         if (typeArgs != null) illegal();
         while (true) {
@@ -1372,13 +1461,13 @@
                 nextToken();
                 if ((mode & TYPE) != 0) {
                     int oldmode = mode;
-                    mode = TYPE;
+                    selectTypeMode();
                     if (token.kind == RBRACKET) {
                         nextToken();
                         t = bracketsOpt(t);
                         t = toP(F.at(pos1).TypeArray(t));
                         if (token.kind == COLCOL) {
-                            mode = EXPR;
+                            selectExprMode();
                             continue;
                         }
                         if (annos.nonEmpty()) {
@@ -1389,7 +1478,7 @@
                     mode = oldmode;
                 }
                 if ((mode & EXPR) != 0) {
-                    mode = EXPR;
+                    selectExprMode();
                     JCExpression t1 = term();
                     t = to(F.at(pos1).Indexed(t, t1));
                 }
@@ -1398,14 +1487,14 @@
                 nextToken();
                 typeArgs = typeArgumentsOpt(EXPR);
                 if (token.kind == SUPER && (mode & EXPR) != 0) {
-                    mode = EXPR;
+                    selectExprMode();
                     t = to(F.at(pos1).Select(t, names._super));
                     nextToken();
                     t = arguments(typeArgs, t);
                     typeArgs = null;
                 } else if (token.kind == NEW && (mode & EXPR) != 0) {
                     if (typeArgs != null) return illegal();
-                    mode = EXPR;
+                    selectExprMode();
                     int pos2 = token.pos;
                     nextToken();
                     if (token.kind == LT) typeArgs = typeArguments(false);
@@ -1425,7 +1514,7 @@
                     typeArgs = null;
                 }
             } else if ((mode & EXPR) != 0 && token.kind == COLCOL) {
-                mode = EXPR;
+                selectExprMode();
                 if (typeArgs != null) return illegal();
                 accept(COLCOL);
                 t = memberReferenceSuffix(pos1, t);
@@ -1440,7 +1529,7 @@
             }
         }
         while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) {
-            mode = EXPR;
+            selectExprMode();
             t = to(F.at(token.pos).Unary(
                   token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
             nextToken();
@@ -1580,7 +1669,8 @@
                         return ParensResult.EXPLICIT_LAMBDA;
                     } else if (peekToken(lookahead, RPAREN, ARROW)) {
                         // Identifier, ')' '->' -> implicit lambda
-                        return ParensResult.IMPLICIT_LAMBDA;
+                        return (mode & NOLAMBDA) == 0 ? ParensResult.IMPLICIT_LAMBDA
+                                                      : ParensResult.PARENS;
                     } else if (depth == 0 && peekToken(lookahead, COMMA)) {
                         defaultResult = ParensResult.IMPLICIT_LAMBDA;
                     }
@@ -1818,7 +1908,7 @@
      */
     JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
         if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) {
-            mode = EXPR;
+            selectExprMode();
             return arguments(typeArgs, t);
         } else {
             return t;
@@ -1857,7 +1947,7 @@
         if (token.kind == LT &&
             (mode & TYPE) != 0 &&
             (mode & NOPARAMS) == 0) {
-            mode = TYPE;
+            selectTypeMode();
             return typeArguments(t, false);
         } else {
             return t;
@@ -2019,7 +2109,7 @@
      */
     JCExpression bracketsSuffix(JCExpression t) {
         if ((mode & EXPR) != 0 && token.kind == DOT) {
-            mode = EXPR;
+            selectExprMode();
             int pos = token.pos;
             nextToken();
             accept(CLASS);
@@ -2044,7 +2134,7 @@
             }
         } else if ((mode & TYPE) != 0) {
             if (token.kind != COLCOL) {
-                mode = TYPE;
+                selectTypeMode();
             }
         } else if (token.kind != COLCOL) {
             syntaxError(token.pos, Errors.DotClassExpected);
@@ -2064,7 +2154,7 @@
 
     JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
         checkSourceLevel(Feature.METHOD_REFERENCES);
-        mode = EXPR;
+        selectExprMode();
         List<JCExpression> typeArgs = null;
         if (token.kind == LT) {
             typeArgs = typeArguments(false);
@@ -2103,7 +2193,7 @@
         JCExpression t = qualident(true);
 
         int oldmode = mode;
-        mode = TYPE;
+        selectTypeMode();
         boolean diamondFound = false;
         int lastTypeargsPos = -1;
         if (token.kind == LT) {
@@ -2617,9 +2707,9 @@
         }
         case BREAK: {
             nextToken();
-            Name label = LAX_IDENTIFIER.accepts(token.kind) ? ident() : null;
+            JCExpression value = token.kind == SEMI ? null : parseExpression();
             accept(SEMI);
-            JCBreak t = toP(F.at(pos).Break(label));
+            JCBreak t = toP(F.at(pos).Break(value));
             return t;
         }
         case CONTINUE: {
@@ -2713,7 +2803,7 @@
             switch (token.kind) {
             case CASE:
             case DEFAULT:
-                cases.append(switchBlockStatementGroup());
+                cases.appendList(switchBlockStatementGroup());
                 break;
             case RBRACE: case EOF:
                 return cases.toList();
@@ -2724,28 +2814,69 @@
         }
     }
 
-    protected JCCase switchBlockStatementGroup() {
+    protected List<JCCase> switchBlockStatementGroup() {
         int pos = token.pos;
         List<JCStatement> stats;
         JCCase c;
+        ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
         switch (token.kind) {
-        case CASE:
+        case CASE: {
             nextToken();
-            JCExpression pat = parseExpression();
-            accept(COLON);
-            stats = blockStatements();
-            c = F.at(pos).Case(pat, stats);
+            ListBuffer<JCExpression> pats = new ListBuffer<>();
+            while (true) {
+                pats.append(term(EXPR | NOLAMBDA));
+                if (token.kind != COMMA) break;
+                nextToken();
+                checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
+            };
+            @SuppressWarnings("removal")
+            CaseKind caseKind;
+            JCTree body = null;
+            if (token.kind == ARROW) {
+                checkSourceLevel(Feature.SWITCH_RULE);
+                accept(ARROW);
+                caseKind = JCCase.RULE;
+                JCStatement statement = parseStatementAsBlock();
+                if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
+                    log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
+                }
+                stats = List.of(statement);
+                body = stats.head;
+            } else {
+                accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
+                caseKind = JCCase.STATEMENT;
+                stats = blockStatements();
+            }
+            c = F.at(pos).Case(caseKind, pats.toList(), stats, body);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
-            return c;
-        case DEFAULT:
+            return cases.append(c).toList();
+        }
+        case DEFAULT: {
             nextToken();
-            accept(COLON);
-            stats = blockStatements();
-            c = F.at(pos).Case(null, stats);
+            @SuppressWarnings("removal")
+            CaseKind caseKind;
+            JCTree body = null;
+            if (token.kind == ARROW) {
+                checkSourceLevel(Feature.SWITCH_RULE);
+                accept(ARROW);
+                caseKind = JCCase.RULE;
+                JCStatement statement = parseStatementAsBlock();
+                if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
+                    log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
+                }
+                stats = List.of(statement);
+                body = stats.head;
+            } else {
+                accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
+                caseKind = JCCase.STATEMENT;
+                stats = blockStatements();
+            }
+            c = F.at(pos).Case(caseKind, List.nil(), stats, body);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
-            return c;
+            return cases.append(c).toList();
+        }
         }
         throw new AssertionError("should not reach here");
     }
@@ -2946,7 +3077,7 @@
      */
     JCExpression annotationFieldValue() {
         if (LAX_IDENTIFIER.accepts(token.kind)) {
-            mode = EXPR;
+            selectExprMode();
             JCExpression t1 = term1();
             if (t1.hasTag(IDENT) && token.kind == EQ) {
                 int pos = token.pos;
@@ -2988,7 +3119,7 @@
             accept(RBRACE);
             return toP(F.at(pos).NewArray(null, List.nil(), buf.toList()));
         default:
-            mode = EXPR;
+            selectExprMode();
             return term1();
         }
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Aug 29 09:36:17 2018 +0200
@@ -49,6 +49,7 @@
 # kind name         an informative description of the kind of a declaration; see compiler.misc.kindname.*
 # target            a target version number, such as 1.5, 1.6, 1.7, taken from a com.sun.tools.javac.jvm.Target
 # token             the name of a non-terminal in source code; see compiler.misc.token.*
+# tree tag          the name of a non-terminal in source code; see compiler.misc.token.*
 # type              a Java type; e.g. int, X, X<T>
 # url               a URL
 # object            a Java object (unspecified)
@@ -187,6 +188,33 @@
 compiler.err.break.outside.switch.loop=\
     break outside switch or loop
 
+compiler.err.break.missing.value=\
+    missing break value
+
+compiler.err.break.outside.switch.expression=\
+    break outside of enclosing switch expression
+
+compiler.err.continue.outside.switch.expression=\
+    continue outside of enclosing switch expression
+
+compiler.err.return.outside.switch.expression=\
+    return outside of enclosing switch expression
+
+# 0: name
+compiler.err.break.ambiguous.target=\
+    ambiguous reference to ''{0}''\n\
+    (''{0}'' is both a label and an expression)
+
+# 0: tree tag
+compiler.err.break.expr.not.immediate=\
+    value break not supported in ''{0}''
+
+compiler.err.break.complex.value.no.switch.expression=\
+    unexpected value break
+
+compiler.err.switch.expression.empty=\
+    switch expression does not have any case clauses
+
 # 0: name
 compiler.err.call.must.be.first.stmt.in.ctor=\
     call to {0} must be first statement in constructor
@@ -799,12 +827,6 @@
 compiler.err.native.meth.cant.have.body=\
     native methods cannot have a body
 
-# 0: type, 1: type
-compiler.err.neither.conditional.subtype=\
-    incompatible types for ?: neither is a subtype of the other\n\
-    second operand: {0}\n\
-    third operand : {1}
-
 
 # 0: message segment
 compiler.misc.incompatible.type.in.conditional=\
@@ -814,6 +836,14 @@
 compiler.misc.conditional.target.cant.be.void=\
     target-type for conditional expression cannot be void
 
+compiler.misc.switch.expression.target.cant.be.void=\
+    target-type for switch expression cannot be void
+
+# 0: message segment
+compiler.misc.incompatible.type.in.switch.expression=\
+    bad type in switch expression\n\
+    {0}
+
 # 0: message segment
 compiler.misc.incompatible.ret.type.in.lambda=\
     bad return type in lambda expression\n\
@@ -1289,6 +1319,9 @@
 compiler.err.unreachable.stmt=\
     unreachable statement
 
+compiler.err.not.exhaustive=\
+    the switch expression does not cover all possible input values
+
 compiler.err.initializer.must.be.able.to.complete.normally=\
     initializer must be able to complete normally
 
@@ -2579,6 +2612,22 @@
 compiler.misc.kindname.instance.init=\
     instance initializer
 
+# the following are names of tree kinds:
+compiler.misc.tree.tag.forloop=\
+    for
+
+compiler.misc.tree.tag.foreachloop=\
+    for
+
+compiler.misc.tree.tag.whileloop=\
+    while
+
+compiler.misc.tree.tag.doloop=\
+    do
+
+compiler.misc.tree.tag.switch=\
+    switch
+
 #####
 
 compiler.misc.no.args=\
@@ -2768,6 +2817,15 @@
 compiler.misc.feature.private.intf.methods=\
     private interface methods
 
+compiler.misc.feature.multiple.case.labels=\
+    multiple case labels
+
+compiler.misc.feature.switch.rules=\
+    switch rules
+
+compiler.misc.feature.switch.expressions=\
+    switch expressions
+
 compiler.warn.underscore.as.identifier=\
     as of release 9, ''_'' is a keyword, and may not be used as an identifier
 
@@ -3257,6 +3315,14 @@
 compiler.err.illegal.argument.for.option=\
     illegal argument for {0}: {1}
 
+compiler.err.switch.null.not.allowed=\
+    null label in case is not allowed
+
+compiler.err.switch.case.unexpected.statement=\
+    unexpected statement in case, expected is an expression, a block or a throw statement
+
+compiler.err.switch.mixing.case.types=\
+    different case kinds used in the switch
 
 ############################################
 # messages previouly at javac.properties
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Aug 29 09:36:17 2018 +0200
@@ -47,10 +47,12 @@
 
 import javax.tools.JavaFileManager.Location;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.ModuleTree.ModuleKind;
 import com.sun.tools.javac.code.Directive.ExportsDirective;
 import com.sun.tools.javac.code.Directive.OpensDirective;
 import com.sun.tools.javac.code.Type.ModuleType;
+import com.sun.tools.javac.tree.JCTree.JCPolyExpression.PolyKind;
 
 /**
  * Root class for abstract syntax tree nodes. It provides definitions
@@ -149,10 +151,14 @@
          */
         SWITCH,
 
-        /** Case parts in switch statements, of type Case.
+        /** Case parts in switch statements/expressions, of type Case.
          */
         CASE,
 
+        /** Switch expression statements, of type Switch.
+         */
+        SWITCH_EXPRESSION,
+
         /** Synchronized statements, of type Synchonized.
          */
         SYNCHRONIZED,
@@ -1238,21 +1244,50 @@
      * A "case  :" of a switch.
      */
     public static class JCCase extends JCStatement implements CaseTree {
-        public JCExpression pat;
+        //as CaseKind is deprecated for removal (as it is part of a preview feature),
+        //using indirection through these fields to avoid unnecessary @SuppressWarnings:
+        @SuppressWarnings("removal")
+        public static final CaseKind STATEMENT = CaseKind.STATEMENT;
+        @SuppressWarnings("removal")
+        public static final CaseKind RULE = CaseKind.RULE;
+        @SuppressWarnings("removal")
+        public final CaseKind caseKind;
+        public List<JCExpression> pats;
         public List<JCStatement> stats;
-        protected JCCase(JCExpression pat, List<JCStatement> stats) {
-            this.pat = pat;
+        public JCTree body;
+        public boolean completesNormally;
+        protected JCCase(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pats,
+                         List<JCStatement> stats, JCTree body) {
+            Assert.checkNonNull(pats);
+            Assert.check(pats.isEmpty() || pats.head != null);
+            this.caseKind = caseKind;
+            this.pats = pats;
             this.stats = stats;
+            this.body = body;
         }
         @Override
         public void accept(Visitor v) { v.visitCase(this); }
 
-        @DefinedBy(Api.COMPILER_TREE)
+        @Override @DefinedBy(Api.COMPILER_TREE)
         public Kind getKind() { return Kind.CASE; }
-        @DefinedBy(Api.COMPILER_TREE)
-        public JCExpression getExpression() { return pat; }
-        @DefinedBy(Api.COMPILER_TREE)
-        public List<JCStatement> getStatements() { return stats; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return pats.head; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        @SuppressWarnings("removal")
+        public List<JCExpression> getExpressions() { return pats; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        @SuppressWarnings("removal")
+        public List<JCStatement> getStatements() {
+            return caseKind == CaseKind.STATEMENT ? stats : null;
+        }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        @SuppressWarnings("removal")
+        public JCTree getBody() { return body; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        @SuppressWarnings("removal")
+        public CaseKind getCaseKind() {
+            return caseKind;
+        }
         @Override @DefinedBy(Api.COMPILER_TREE)
         public <R,D> R accept(TreeVisitor<R,D> v, D d) {
             return v.visitCase(this, d);
@@ -1264,6 +1299,36 @@
     }
 
     /**
+     * A "switch ( ) { }" construction.
+     */
+    @SuppressWarnings("removal")
+    public static class JCSwitchExpression extends JCPolyExpression implements SwitchExpressionTree {
+        public JCExpression selector;
+        public List<JCCase> cases;
+        protected JCSwitchExpression(JCExpression selector, List<JCCase> cases) {
+            this.selector = selector;
+            this.cases = cases;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitSwitchExpression(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.SWITCH_EXPRESSION; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return selector; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public List<JCCase> getCases() { return cases; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitSwitchExpression(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return SWITCH_EXPRESSION;
+        }
+    }
+
+    /**
      * A synchronized block.
      */
     public static class JCSynchronized extends JCStatement implements SynchronizedTree {
@@ -1484,19 +1549,27 @@
      * A break from a loop or switch.
      */
     public static class JCBreak extends JCStatement implements BreakTree {
-        public Name label;
+        public JCExpression value;
         public JCTree target;
-        protected JCBreak(Name label, JCTree target) {
-            this.label = label;
+        protected JCBreak(JCExpression value, JCTree target) {
+            this.value = value;
             this.target = target;
         }
         @Override
         public void accept(Visitor v) { v.visitBreak(this); }
+        public boolean isValueBreak() {
+            return target != null && target.hasTag(SWITCH_EXPRESSION);
+        }
 
         @DefinedBy(Api.COMPILER_TREE)
         public Kind getKind() { return Kind.BREAK; }
         @DefinedBy(Api.COMPILER_TREE)
-        public Name getLabel() { return label; }
+        public Name getLabel() {
+            return value != null && value.getKind() == Kind.IDENTIFIER ? ((JCIdent) value).getName() : null;
+        }
+        @DefinedBy(Api.COMPILER_TREE)
+        @SuppressWarnings("removal")
+        public JCExpression getValue() { return value; }
         @Override @DefinedBy(Api.COMPILER_TREE)
         public <R,D> R accept(TreeVisitor<R,D> v, D d) {
             return v.visitBreak(this, d);
@@ -2934,9 +3007,9 @@
 
     /** (let int x = 3; in x+2) */
     public static class LetExpr extends JCExpression {
-        public List<JCVariableDecl> defs;
+        public List<JCStatement> defs;
         public JCExpression expr;
-        protected LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
+        protected LetExpr(List<JCStatement> defs, JCExpression expr) {
             this.defs = defs;
             this.expr = expr;
         }
@@ -2994,7 +3067,9 @@
         JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body);
         JCLabeledStatement Labelled(Name label, JCStatement body);
         JCSwitch Switch(JCExpression selector, List<JCCase> cases);
-        JCCase Case(JCExpression pat, List<JCStatement> stats);
+        JCSwitchExpression SwitchExpression(JCExpression selector, List<JCCase> cases);
+        JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pat,
+                    List<JCStatement> stats, JCTree body);
         JCSynchronized Synchronized(JCExpression lock, JCBlock body);
         JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
         JCTry Try(List<JCTree> resources,
@@ -3007,7 +3082,7 @@
                                 JCExpression elsepart);
         JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart);
         JCExpressionStatement Exec(JCExpression expr);
-        JCBreak Break(Name label);
+        JCBreak Break(JCExpression value);
         JCContinue Continue(Name label);
         JCReturn Return(JCExpression expr);
         JCThrow Throw(JCExpression expr);
@@ -3049,7 +3124,7 @@
         JCProvides Provides(JCExpression serviceName, List<JCExpression> implNames);
         JCRequires Requires(boolean isTransitive, boolean isStaticPhase, JCExpression qualId);
         JCUses Uses(JCExpression qualId);
-        LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr);
+        LetExpr LetExpr(List<JCStatement> defs, JCExpression expr);
     }
 
     /** A generic visitor class for trees.
@@ -3070,6 +3145,7 @@
         public void visitLabelled(JCLabeledStatement that)   { visitTree(that); }
         public void visitSwitch(JCSwitch that)               { visitTree(that); }
         public void visitCase(JCCase that)                   { visitTree(that); }
+        public void visitSwitchExpression(JCSwitchExpression that)               { visitTree(that); }
         public void visitSynchronized(JCSynchronized that)   { visitTree(that); }
         public void visitTry(JCTry that)                     { visitTree(that); }
         public void visitCatch(JCCatch that)                 { visitTree(that); }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Aug 29 09:36:17 2018 +0200
@@ -27,6 +27,7 @@
 
 import java.io.*;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.ModuleTree.ModuleKind;
 import com.sun.tools.javac.code.*;
@@ -835,18 +836,43 @@
 
     public void visitCase(JCCase tree) {
         try {
-            if (tree.pat == null) {
+            if (tree.pats.isEmpty()) {
                 print("default");
             } else {
                 print("case ");
-                printExpr(tree.pat);
+                printExprs(tree.pats);
             }
-            print(": ");
+            if (tree.caseKind == JCCase.STATEMENT) {
+                print(":");
+                println();
+                indent();
+                printStats(tree.stats);
+                undent();
+                align();
+            } else {
+                print(" -> ");
+                printStat(tree.stats.head);
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        try {
+            print("switch ");
+            if (tree.selector.hasTag(PARENS)) {
+                printExpr(tree.selector);
+            } else {
+                print("(");
+                printExpr(tree.selector);
+                print(")");
+            }
+            print(" {");
             println();
-            indent();
-            printStats(tree.stats);
-            undent();
+            printStats(tree.cases);
             align();
+            print("}");
         } catch (IOException e) {
             throw new UncheckedIOException(e);
         }
@@ -956,7 +982,7 @@
     public void visitBreak(JCBreak tree) {
         try {
             print("break");
-            if (tree.label != null) print(" " + tree.label);
+            if (tree.value != null) print(" " + tree.value);
             print(";");
         } catch (IOException e) {
             throw new UncheckedIOException(e);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Aug 29 09:36:17 2018 +0200
@@ -140,15 +140,17 @@
     @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitBreak(BreakTree node, P p) {
         JCBreak t = (JCBreak) node;
-        return M.at(t.pos).Break(t.label);
+        JCExpression value = copy(t.value, p);
+        return M.at(t.pos).Break(value);
     }
 
     @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitCase(CaseTree node, P p) {
         JCCase t = (JCCase) node;
-        JCExpression pat = copy(t.pat, p);
+        List<JCExpression> pats = copy(t.pats, p);
         List<JCStatement> stats = copy(t.stats, p);
-        return M.at(t.pos).Case(pat, stats);
+        JCTree body = copy(t.body, p);
+        return M.at(t.pos).Case(t.caseKind, pats, stats, body);
     }
 
     @DefinedBy(Api.COMPILER_TREE)
@@ -371,6 +373,15 @@
     }
 
     @DefinedBy(Api.COMPILER_TREE)
+    @SuppressWarnings("removal")
+    public JCTree visitSwitchExpression(SwitchExpressionTree node, P p) {
+        JCSwitchExpression t = (JCSwitchExpression) node;
+        JCExpression selector = copy(t.selector, p);
+        List<JCCase> cases = copy(t.cases, p);
+        return M.at(t.pos).SwitchExpression(selector, cases);
+    }
+
+    @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitSynchronized(SynchronizedTree node, P p) {
         JCSynchronized t = (JCSynchronized) node;
         JCExpression lock = copy(t.lock, p);
@@ -559,7 +570,7 @@
         switch (tree.getTag()) {
             case LETEXPR: {
                 LetExpr t = (LetExpr) node;
-                List<JCVariableDecl> defs = copy(t.defs, p);
+                List<JCStatement> defs = copy(t.defs, p);
                 JCExpression expr = copy(t.expr, p);
                 return M.at(t.pos).LetExpr(defs, expr);
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Aug 29 09:36:17 2018 +0200
@@ -27,6 +27,7 @@
 
 import java.util.Iterator;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.ModuleTree.ModuleKind;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.tools.javac.code.*;
@@ -273,8 +274,15 @@
         return tree;
     }
 
-    public JCCase Case(JCExpression pat, List<JCStatement> stats) {
-        JCCase tree = new JCCase(pat, stats);
+    public JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pats,
+                       List<JCStatement> stats, JCTree body) {
+        JCCase tree = new JCCase(caseKind, pats, stats, body);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCSwitchExpression SwitchExpression(JCExpression selector, List<JCCase> cases) {
+        JCSwitchExpression tree = new JCSwitchExpression(selector, cases);
         tree.pos = pos;
         return tree;
     }
@@ -325,7 +333,7 @@
         return tree;
     }
 
-    public JCBreak Break(Name label) {
+    public JCBreak Break(JCExpression label) {
         JCBreak tree = new JCBreak(label, null);
         tree.pos = pos;
         return tree;
@@ -599,7 +607,7 @@
         return tree;
     }
 
-    public LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
+    public LetExpr LetExpr(List<JCStatement> defs, JCExpression expr) {
         LetExpr tree = new LetExpr(defs, expr);
         tree.pos = pos;
         return tree;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Wed Aug 29 09:36:17 2018 +0200
@@ -176,10 +176,15 @@
     }
 
     public void visitCase(JCCase tree) {
-        scan(tree.pat);
+        scan(tree.pats);
         scan(tree.stats);
     }
 
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        scan(tree.selector);
+        scan(tree.cases);
+    }
+
     public void visitSynchronized(JCSynchronized tree) {
         scan(tree.lock);
         scan(tree.body);
@@ -214,6 +219,7 @@
     }
 
     public void visitBreak(JCBreak tree) {
+        scan(tree.value);
     }
 
     public void visitContinue(JCContinue tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Wed Aug 29 09:36:17 2018 +0200
@@ -207,11 +207,17 @@
     }
 
     public void visitCase(JCCase tree) {
-        tree.pat = translate(tree.pat);
+        tree.pats = translate(tree.pats);
         tree.stats = translate(tree.stats);
         result = tree;
     }
 
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        tree.selector = translate(tree.selector);
+        tree.cases = translateCases(tree.cases);
+        result = tree;
+    }
+
     public void visitSynchronized(JCSynchronized tree) {
         tree.lock = translate(tree.lock);
         tree.body = translate(tree.body);
@@ -252,6 +258,8 @@
     }
 
     public void visitBreak(JCBreak tree) {
+        if (tree.isValueBreak())
+            tree.value = translate(tree.value);
         result = tree;
     }
 
@@ -419,7 +427,7 @@
     }
 
     public void visitLetExpr(LetExpr tree) {
-        tree.defs = translateVarDefs(tree.defs);
+        tree.defs = translate(tree.defs);
         tree.expr = translate(tree.expr);
         result = tree;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java	Wed Aug 29 09:36:17 2018 +0200
@@ -219,6 +219,10 @@
         else if (arg instanceof Source) {
             return ((Source)arg).name;
         }
+        else if (arg instanceof Tag) {
+            return messages.getLocalizedString(l, "compiler.misc.tree.tag." +
+                                                  StringUtils.toLowerCase(((Tag) arg).name()));
+        }
         else {
             return String.valueOf(arg);
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java	Wed Aug 29 09:36:17 2018 +0200
@@ -158,6 +158,8 @@
             s = "@" + rawDiagnosticPosHelper.getPosition((JCExpression)arg);
         } else if (arg instanceof PathFileObject) {
             s = ((PathFileObject) arg).getShortName();
+        } else if (arg instanceof Tag) {
+            s = "compiler.misc.tree.tag." + StringUtils.toLowerCase(((Tag) arg).name());
         } else {
             s = super.formatArgument(diag, arg, null);
         }
--- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Wed Aug 29 09:36:17 2018 +0200
@@ -247,7 +247,7 @@
         FOR(TokenKind.FOR, XSTMT1|XSTART),  //  for
         IF(TokenKind.IF, XSTMT1|XSTART),  //  if
         RETURN(TokenKind.RETURN, XSTMT1|XTERM|XSTART),  //  return
-        SWITCH(TokenKind.SWITCH, XSTMT1|XSTART),  //  switch
+        SWITCH(TokenKind.SWITCH, XSTMT1|XEXPR),  //  switch
         SYNCHRONIZED(TokenKind.SYNCHRONIZED, XSTMT1|XDECL),  //  synchronized
         THROW(TokenKind.THROW, XSTMT1|XSTART),  //  throw
         TRY(TokenKind.TRY, XSTMT1|XSTART),  //  try
--- a/test/langtools/jdk/jshell/CompletenessTest.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/jdk/jshell/CompletenessTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -185,7 +185,12 @@
         "int n,",
         "int[] m = {1, 2},",
         "int[] m = {1, 2}, n = {3, 4},",
-        "Map<String,"
+        "Map<String,",
+        "switch (x) {",
+        "var v = switch (x) {",
+        "var v = switch (x) { case ",
+        "var v = switch (x) { case 0:",
+        "var v = switch (x) { case 0: break 12; ",
     };
 
     static final String[] unknown = new String[] {
--- a/test/langtools/lib/combo/tools/javac/combo/Diagnostics.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/lib/combo/tools/javac/combo/Diagnostics.java	Wed Aug 29 09:36:17 2018 +0200
@@ -65,6 +65,13 @@
                     .anyMatch(d -> d.getCode().equals(key));
     }
 
+    /** Do the diagnostics contain the specified warning key? */
+    public boolean containsWarningKey(String key) {
+        return diags.stream()
+                    .filter(d -> d.getKind() == Diagnostic.Kind.WARNING)
+                    .anyMatch(d -> d.getCode().equals(key));
+    }
+
     /** Get the error keys */
     public List<String> errorKeys() {
         return diags.stream()
--- a/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java	Wed Aug 29 09:36:17 2018 +0200
@@ -178,6 +178,14 @@
             fail("Expected successful compilation");
     }
 
+    /** Assert that all previous calls to compile() succeeded */
+    protected void assertCompileSucceededWithWarning(String warning) {
+        if (diags.errorsFound())
+            fail("Expected successful compilation");
+        if (!diags.containsWarningKey(warning))
+            fail("Expected compilation warning " + warning);
+    }
+
     /**
      * If the provided boolean is true, assert all previous compiles succeeded,
      * otherwise assert that a compile failed.
@@ -196,9 +204,22 @@
     }
 
     /** Assert that a previous call to compile() failed with a specific error key */
-    protected void assertCompileFailed(String message) {
+    protected void assertCompileFailed(String key) {
         if (!diags.errorsFound())
-            fail("Expected failed compilation: " + message);
+            fail("Expected failed compilation: " + key);
+        if (!diags.containsErrorKey(key))
+            fail("Expected compilation error " + key);
+    }
+
+    /** Assert that a previous call to compile() failed with a specific error key */
+    protected void assertCompileFailedOneOf(String... keys) {
+        if (!diags.errorsFound())
+            fail("Expected failed compilation with one of: " + Arrays.asList(keys));
+        boolean found = false;
+        for (String k : keys)
+            if (diags.containsErrorKey(k))
+                found = true;
+        fail(String.format("Expected compilation error with one of %s, found %s", Arrays.asList(keys), diags.keys()));
     }
 
     /** Assert that a previous call to compile() failed with all of the specified error keys */
--- a/test/langtools/tools/javac/ConditionalWithVoid.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/ConditionalWithVoid.java	Wed Aug 29 09:36:17 2018 +0200
@@ -4,13 +4,17 @@
  * @summary The compiler was allowing void types in its parsing of conditional expressions.
  * @author tball
  *
- * @compile/fail/ref=ConditionalWithVoid.out -XDrawDiagnostics ConditionalWithVoid.java
+ * @compile/fail/ref=ConditionalWithVoid.out --enable-preview -source 12 -XDrawDiagnostics ConditionalWithVoid.java
  */
 public class ConditionalWithVoid {
-    public void test(Object o) {
+    public void test(Object o, String s) {
         // Should fail to compile since Object.wait() has a void return type. Poly case.
         System.out.println(o instanceof String ? o.hashCode() : o.wait());
         // Should fail to compile since Object.wait() has a void return type. Standalone case.
         (o instanceof String ? o.hashCode() : o.wait()).toString();
+        // Should fail to compile since Object.wait() has a void return type. Poly case.
+        System.out.println(switch (s) {case "" -> o.hashCode(); default -> o.wait();});
+        // Should fail to compile since Object.wait() has a void return type. Standalone case.
+        (switch (s) {case "" -> o.hashCode(); default -> o.wait();}).toString();
     }
 }
--- a/test/langtools/tools/javac/ConditionalWithVoid.out	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/ConditionalWithVoid.out	Wed Aug 29 09:36:17 2018 +0200
@@ -1,3 +1,7 @@
 ConditionalWithVoid.java:12:71: compiler.err.void.not.allowed.here
-ConditionalWithVoid.java:14:30: compiler.err.neither.conditional.subtype: java.lang.Integer, void
-2 errors
+ConditionalWithVoid.java:14:53: compiler.err.void.not.allowed.here
+ConditionalWithVoid.java:16:82: compiler.err.void.not.allowed.here
+ConditionalWithVoid.java:18:64: compiler.err.void.not.allowed.here
+- compiler.note.preview.filename: ConditionalWithVoid.java
+- compiler.note.preview.recompile
+4 errors
--- a/test/langtools/tools/javac/desugar/BoxingAndSuper.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/desugar/BoxingAndSuper.java	Wed Aug 29 09:36:17 2018 +0200
@@ -61,6 +61,7 @@
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
 import com.sun.tools.javac.tree.JCTree.JCModifiers;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.tree.JCTree.LetExpr;
 import com.sun.tools.javac.tree.JCTree.Tag;
@@ -327,8 +328,8 @@
                     if (tree.hasTag(Tag.LETEXPR)) {
                         LetExpr le = (LetExpr) tree;
 
-                        for (JCVariableDecl var : le.defs) {
-                            letExprRemap.put(var.name.toString(), "$le" + i++);
+                        for (JCStatement var : le.defs) {
+                            letExprRemap.put(((JCVariableDecl) var).name.toString(), "$le" + i++);
                         }
                     }
                     return super.visitOther(node, p);
--- a/test/langtools/tools/javac/diags/CheckResourceKeys.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/diags/CheckResourceKeys.java	Wed Aug 29 09:36:17 2018 +0200
@@ -302,6 +302,7 @@
             // prefix/embedded strings
             "compiler.",
             "compiler.misc.",
+            "compiler.misc.tree.tag.",
             "opt.Xlint.desc.",
             "count.",
             "illegal.",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakAmbiguousTarget.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.break.ambiguous.target
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakAmbiguousTarget {
+    void m(int i, int j) {
+        j: print(switch (i) {
+            default: break j;
+        });
+    }
+    void print(int i) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakComplexValueNoSwitchExpression.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.break.complex.value.no.switch.expression
+
+class BreakComplexValueNoSwitchExpressions {
+    void t() {
+        while (true) {
+            break 1 + 1;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakExprNotImmediate.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.break.expr.not.immediate
+// key: compiler.misc.tree.tag.doloop
+// key: compiler.misc.tree.tag.foreachloop
+// key: compiler.misc.tree.tag.forloop
+// key: compiler.misc.tree.tag.switch
+// key: compiler.misc.tree.tag.whileloop
+// key: compiler.note.note
+// key: compiler.err.error
+// key: compiler.misc.count.error.plural
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// key: compiler.note.note
+// options: --enable-preview -source 12
+// run: backdoor
+
+class BreakExprNotImmediate {
+    int t(int i) {
+        return switch (i) {
+            case 0:
+                for (; ;) {
+                    break 1 + 1;
+                }
+            case 1:
+                for (String s : new String[0]) {
+                    break 1 + 1;
+                }
+            case 2:
+                while (true) {
+                    break 1 + 1;
+                }
+            case 3:
+                do {
+                    break 1 + 1;
+                } while (true);
+            case 4:
+                switch (i) {
+                    default: break 1 + 1;
+                }
+                break 0;
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakMissingValue.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.break.missing.value
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakMissingValue {
+    int t(int i) {
+        return switch (i) {
+            default: break;
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/BreakOutsideSwitchExpression.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.break.outside.switch.expression
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakOutsideSwitchExpression {
+    int t(int i) {
+        OUT: while (true) {
+            return switch (i) {
+                default: break OUT;
+            };
+        }
+        return -1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/ContinueOutsideSwitchExpression.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.continue.outside.switch.expression
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class ContinueOutsideSwitchExpression {
+    int t(int i) {
+        OUT: while (true) {
+            return switch (i) {
+                default: continue OUT;
+            };
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/IncompatibleTypesInSwitchExpression.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.incompatible.type.in.switch.expression
+// key: compiler.misc.inconvertible.types
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+
+class IncompatibleTypesInSwitchExpression {
+
+    interface A { }
+    interface B { }
+
+    B b = switch (0) { case 0 -> (A)null; default -> (B)null; };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/MultipleCaseLabels.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.misc.feature.multiple.case.labels
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source 12 -Xlint:preview
+
+class MultipleCaseLabels {
+    void m(int i) {
+        switch (i) {
+            case 0, 1, 2: break;
+        }
+    }
+}
--- a/test/langtools/tools/javac/diags/examples/NeitherConditionalSubtype.java	Tue Aug 28 09:01:54 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2010, 2014, 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.
- */
-
-// key: compiler.err.neither.conditional.subtype
-
-class NeitherConditionalSubtype {
-    public int test(boolean cond, Object o) {
-        // Should fail to compile since Object.wait() has a void return type.
-        (o instanceof String ? o.hashCode() : o.wait()).toString();
-        return 0;
-    }
-}
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/NotExhaustive.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.not.exhaustive
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class NotExhaustive {
+    int t(int i) {
+        return switch (i) {
+            case 0 -> -1;
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/ReturnOutsideSwitchExpression.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.return.outside.switch.expression
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class ReturnOutsideSwitchExpression {
+    int t(int i) {
+        return switch (i) {
+            default: return -1;
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchCaseUnexpectedStatement.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.switch.case.unexpected.statement
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class ReturnOutsideSwitchExpression {
+    void t(int i) {
+        switch (i) {
+            case 0 -> if (true);
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressionEmpty.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.switch.expression.empty
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class BreakOutsideSwitchExpression {
+    String t(E e) {
+        return switch (e) {
+        };
+    }
+    enum E {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressionTargetCantBeVoid.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.prob.found.req
+// key: compiler.misc.incompatible.ret.type.in.lambda
+// key: compiler.misc.switch.expression.target.cant.be.void
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class SwitchExpressionTargetCantBeVoid {
+
+    interface SAM {
+        void m();
+    }
+
+    void test(int cond, Object o1, Object o2, Object o3) {
+        SAM s = ()-> switch (cond) { case 0 -> o1; case 1 -> o2; default -> o3; };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchExpressions.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.misc.feature.switch.expressions
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source 12 -Xlint:preview
+
+class SwitchExpressions {
+    int m(int i) {
+        return switch (i) {
+            default: break -1;
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchMixingCaseTypes.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.switch.mixing.case.types
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source 12
+
+class SwitchMixingCaseTypes {
+
+    void test(int i) {
+        switch (i) {
+            case 0: break;
+            case 1 -> System.out.println();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchNullNotAllowed.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.err.switch.null.not.allowed
+
+class SwitchNullNotAllowed {
+
+    void test(Integer i) {
+        switch (i) {
+            case null: break;
+            case 0: break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/SwitchRules.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+// key: compiler.misc.feature.switch.rules
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source 12 -Xlint:preview
+
+class SwitchExpressions {
+    void m(int i) {
+        switch (i) {
+            default -> { break; }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ *
+ * 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.io.IOException;
+import java.util.List;
+
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import tools.javac.combo.JavacTemplateTestBase;
+
+import static java.util.stream.Collectors.toList;
+
+@Test
+public class ExpSwitchNestingTest extends JavacTemplateTestBase {
+    private static final String RUNNABLE = "Runnable r = () -> { # };";
+    private static final String INT_FN = "java.util.function.IntSupplier r = () -> { # };";
+    private static final String LABEL = "label: #";
+    private static final String DEF_LABEL_VAR = "int label = 0; { # }";
+    private static final String FOR = "for (int i=0; i<10; i++) { # }";
+    private static final String FOR_EACH = "for (int i : new int[] {}) { # }";
+    private static final String WHILE = "while (cond) { # }";
+    private static final String DO = "do { # } while (cond);";
+    private static final String SSWITCH = "switch (x) { case 0: # };";
+    private static final String ESWITCH_Z = "int res = switch (x) { case 0 -> { # } default -> 0; };";
+    private static final String ESWITCH_S = "String res_string = switch (x) { case 0 -> { # } default -> \"default\"; };";
+    private static final String INT_FN_ESWITCH = "java.util.function.IntSupplier r = switch (x) { case 0 -> { # } default -> null; };";
+    private static final String INT_ESWITCH_DEFAULT = "int res = switch (x) { default -> { # } };";
+    private static final String IF = "if (cond) { # }";
+    private static final String BLOCK = "{ # }";
+    private static final String BREAK_Z = "break 0;";
+    private static final String BREAK_S = "break \"hello world\";";
+    private static final String BREAK_INT_FN = "break () -> 0 ;";
+    private static final String BREAK_N = "break;";
+    private static final String BREAK_L = "break label;";
+    private static final String RETURN_Z = "return 0;";
+    private static final String RETURN_N = "return;";
+    private static final String RETURN_S = "return \"Hello\";";
+    private static final String CONTINUE_N = "continue;";
+    private static final String CONTINUE_L = "continue label;";
+    private static final String NOTHING = "System.out.println();";
+
+    // containers that do not require exhaustiveness
+    private static final List<String> CONTAINERS
+            = List.of(RUNNABLE, FOR, WHILE, DO, SSWITCH, IF, BLOCK);
+    // containers that do not require exhaustiveness that are statements
+    private static final List<String> CONTAINER_STATEMENTS
+            = List.of(FOR, WHILE, DO, SSWITCH, IF, BLOCK);
+
+    @AfterMethod
+    public void dumpTemplateIfError(ITestResult result) {
+        // Make sure offending template ends up in log file on failure
+        if (!result.isSuccess()) {
+            System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList()));
+        }
+    }
+
+    private void program(String... constructs) {
+        String s = "class C { static boolean cond = false; static int x = 0; void m() { # } }";
+        for (String c : constructs)
+            s = s.replace("#", c);
+        addSourceFile("C.java", new StringTemplate(s));
+    }
+
+    private void assertOK(String... constructs) {
+        reset();
+        addCompileOptions("--enable-preview", "-source", "12");
+        program(constructs);
+        try {
+            compile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        assertCompileSucceeded();
+    }
+
+    private void assertOKWithWarning(String warning, String... constructs) {
+        reset();
+        addCompileOptions("--enable-preview", "-source", "12");
+        program(constructs);
+        try {
+            compile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        assertCompileSucceededWithWarning(warning);
+    }
+
+    private void assertFail(String expectedDiag, String... constructs) {
+        reset();
+        addCompileOptions("--enable-preview", "-source", "12");
+        program(constructs);
+        try {
+            compile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        assertCompileFailed(expectedDiag);
+    }
+
+    public void testReallySimpleCases() {
+        for (String s : CONTAINERS)
+            assertOK(s, NOTHING);
+        for (String s : CONTAINER_STATEMENTS)
+            assertOK(LABEL, s, NOTHING);
+    }
+
+    public void testLambda() {
+        assertOK(RUNNABLE, RETURN_N);
+        assertOK(RUNNABLE, NOTHING);
+        assertOK(INT_FN, RETURN_Z);
+        assertFail("compiler.err.break.outside.switch.loop", RUNNABLE, BREAK_N);
+        assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_Z);
+        assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_S);
+        assertFail("compiler.err.break.outside.switch.loop", INT_FN, BREAK_N);
+        assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_Z);
+        assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_S);
+        assertFail("compiler.err.cont.outside.loop", RUNNABLE, CONTINUE_N);
+        assertFail("compiler.err.undef.label", RUNNABLE, BREAK_L);
+        assertFail("compiler.err.undef.label", RUNNABLE, CONTINUE_L);
+        assertFail("compiler.err.cont.outside.loop", INT_FN, CONTINUE_N);
+        assertFail("compiler.err.undef.label", INT_FN, BREAK_L);
+        assertFail("compiler.err.undef.label", INT_FN, CONTINUE_L);
+        assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, BREAK_L);
+        assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, CONTINUE_L);
+        assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, BREAK_L);
+        assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, CONTINUE_L);
+    }
+
+    public void testEswitch() {
+        //Int-valued switch expressions
+        assertOK(ESWITCH_Z, BREAK_Z);
+        assertOK(LABEL, BLOCK, ESWITCH_Z, BREAK_Z);
+        assertFail("compiler.err.break.missing.value", ESWITCH_Z, BREAK_N);
+        assertFail("compiler.err.prob.found.req", ESWITCH_Z, BREAK_S);
+        assertFail("compiler.err.cant.resolve.location", ESWITCH_Z, BREAK_L);
+        assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_Z, BREAK_L);
+        assertFail("compiler.err.undef.label", ESWITCH_Z, CONTINUE_L);
+        assertFail("compiler.err.cont.outside.loop", ESWITCH_Z, CONTINUE_N);
+        assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_N);
+        assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_Z);
+
+        assertOK(INT_ESWITCH_DEFAULT, BREAK_Z);
+        assertFail("compiler.err.break.missing.value", INT_ESWITCH_DEFAULT, BREAK_N);
+        assertFail("compiler.err.prob.found.req", INT_ESWITCH_DEFAULT, BREAK_S);
+        assertFail("compiler.err.cant.resolve.location", INT_ESWITCH_DEFAULT, BREAK_L);
+
+
+        // String-valued switch expressions
+        assertOK(ESWITCH_S, BREAK_S);
+        assertOK(LABEL, BLOCK, ESWITCH_S, BREAK_S);
+        assertFail("compiler.err.break.missing.value", ESWITCH_S, BREAK_N);
+        assertFail("compiler.err.prob.found.req", ESWITCH_S, BREAK_Z);
+        assertFail("compiler.err.cant.resolve.location", ESWITCH_S, BREAK_L);
+        assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_S, BREAK_L);
+        assertFail("compiler.err.undef.label", ESWITCH_S, CONTINUE_L);
+        assertFail("compiler.err.cont.outside.loop", ESWITCH_S, CONTINUE_N);
+        assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_N);
+        assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_S);
+        // Function-valued switch expression
+        assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
+        assertFail("compiler.err.break.missing.value", INT_FN_ESWITCH, BREAK_N);
+        assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_Z);
+        assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_S);
+
+        assertFail("compiler.err.cant.resolve.location", INT_FN_ESWITCH, BREAK_L);
+        assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, INT_FN_ESWITCH, BREAK_L);
+        assertFail("compiler.err.undef.label", INT_FN_ESWITCH, CONTINUE_L);
+        assertFail("compiler.err.cont.outside.loop", INT_FN_ESWITCH, CONTINUE_N);
+        assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_N);
+        assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_S);
+
+    }
+
+    public void testNestedInExpSwitch() {
+        assertOK(ESWITCH_Z, IF,     BREAK_Z);
+        assertOK(ESWITCH_Z, BLOCK,  BREAK_Z);
+        //
+        assertOK(ESWITCH_Z, IF,     IF,     BREAK_Z);
+        assertOK(ESWITCH_Z, IF,     BLOCK,  BREAK_Z);
+        assertOK(ESWITCH_Z, BLOCK,  IF,     BREAK_Z);
+        assertOK(ESWITCH_Z, BLOCK,  BLOCK,  BREAK_Z);
+        //
+        assertOK(ESWITCH_Z, IF,     IF,     IF,     BREAK_Z);
+        assertOK(ESWITCH_Z, IF,     IF,     BLOCK,  BREAK_Z);
+        assertOK(ESWITCH_Z, IF,     BLOCK,  IF,     BREAK_Z);
+        assertOK(ESWITCH_Z, IF,     BLOCK,  BLOCK,  BREAK_Z);
+        assertOK(ESWITCH_Z, BLOCK,  IF,     IF,     BREAK_Z);
+        assertOK(ESWITCH_Z, BLOCK,  IF,     BLOCK,  BREAK_Z);
+        assertOK(ESWITCH_Z, BLOCK,  BLOCK,  IF,     BREAK_Z);
+        assertOK(ESWITCH_Z, BLOCK,  BLOCK,  BLOCK,  BREAK_Z);
+        //
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, BREAK_Z);
+        assertFail("compiler.err.break.complex.value.no.switch.expression", ESWITCH_Z, INT_FN, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, IF, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, IF, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, IF, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, IF, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, SSWITCH, IF, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, FOR, IF, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, WHILE, IF, BREAK_Z);
+        assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, DO, IF, BREAK_Z);
+    }
+
+    public void testBreakExpressionLabelDisambiguation() {
+        assertOK(DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
+        assertFail("compiler.err.break.ambiguous.target", LABEL, FOR, BLOCK, DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
+        assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, ESWITCH_Z, LABEL, FOR, BREAK_L); //label break
+        assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, BREAK_L); //expression break
+        //
+    }
+
+    public void testFunReturningSwitchExp() {
+        assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
+    }
+
+    public void testContinueLoops() {
+        assertOK(LABEL, FOR, CONTINUE_L);
+        assertOK(LABEL, FOR_EACH, CONTINUE_L);
+        assertOK(LABEL, WHILE, CONTINUE_L);
+        assertOK(LABEL, DO, CONTINUE_L);
+        assertFail("compiler.err.not.loop.label", LABEL, CONTINUE_L);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/expswitch/TEST.properties	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+TestNG.dirs = .
+
+lib.dirs = /lib/combo
+
+modules = \
+        jdk.compiler/com.sun.tools.javac.util
--- a/test/langtools/tools/javac/failover/CheckAttributedTree.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/failover/CheckAttributedTree.java	Wed Aug 29 09:36:17 2018 +0200
@@ -95,6 +95,7 @@
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.tree.EndPosTable;
 import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.tree.JCTree.JCImport;
 import com.sun.tools.javac.tree.TreeInfo;
@@ -446,6 +447,12 @@
                 scan(tree.defs);
             }
 
+            @Override
+            public void visitBreak(JCBreak tree) {
+                if (tree.isValueBreak())
+                    super.visitBreak(tree);
+            }
+
             JavaFileObject sourcefile;
             EndPosTable endPosTable;
             Info encl;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lambda/BadSwitchExpressionLambda.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,24 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Adding switch expressions
+ * @compile/fail/ref=BadSwitchExpressionLambda.out -XDrawDiagnostics --enable-preview -source 12 BadSwitchExpressionLambda.java
+ */
+
+class BadSwitchExpressionLambda {
+
+    interface SAM {
+        void invoke();
+    }
+
+    public static void m() {}
+    public static void r(SAM sam) {}
+
+    void test(int i) {
+        SAM sam1 = () -> m(); //ok
+        SAM sam2 = () -> switch (i) { case 0 -> m(); default -> m(); }; //not ok
+        r(() -> m()); //ok
+        r(() -> switch (i) { case 0 -> m(); default -> m(); }); //not ok
+        return switch (i) { case 0 -> m(); default -> m(); }; //not ok
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/lambda/BadSwitchExpressionLambda.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+BadSwitchExpressionLambda.java:19:26: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.switch.expression.target.cant.be.void))
+BadSwitchExpressionLambda.java:21:9: compiler.err.cant.apply.symbol: kindname.method, r, BadSwitchExpressionLambda.SAM, @11, kindname.class, BadSwitchExpressionLambda, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.switch.expression.target.cant.be.void)))
+BadSwitchExpressionLambda.java:22:16: compiler.err.prob.found.req: (compiler.misc.unexpected.ret.val)
+- compiler.note.preview.filename: BadSwitchExpressionLambda.java
+- compiler.note.preview.recompile
+3 errors
--- a/test/langtools/tools/javac/lib/DPrinter.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/lib/DPrinter.java	Wed Aug 29 09:36:17 2018 +0200
@@ -737,7 +737,7 @@
 
         @Override
         public void visitCase(JCCase tree) {
-            printTree("pat", tree.pat);
+            printList("pat", tree.pats);
             printList("stats", tree.stats);
         }
 
@@ -782,7 +782,7 @@
 
         @Override
         public void visitBreak(JCBreak tree) {
-            printName("label", tree.label);
+            printTree("value", tree.value);
         }
 
         @Override
--- a/test/langtools/tools/javac/parser/JavacParserTest.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/parser/JavacParserTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -82,6 +82,9 @@
 import javax.tools.SimpleJavaFileObject;
 import javax.tools.ToolProvider;
 
+import com.sun.source.tree.CaseTree;
+import com.sun.source.util.TreePathScanner;
+
 public class JavacParserTest extends TestCase {
     static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
     static final JavaFileManager fm = tool.getStandardFileManager(null, null, null);
@@ -1039,6 +1042,135 @@
     }
 
     @Test
+    void testCaseBodyStatements() throws IOException {
+        String code = "class C {" +
+                      "    void t(int i) {" +
+                      "        switch (i) {" +
+                      "            case 0 -> i++;" +
+                      "            case 1 -> { i++; }" +
+                      "            case 2 -> throw new RuntimeException();" +
+                      "            case 3 -> if (true) ;" +
+                      "            default -> i++;" +
+                      "        }" +
+                      "        switch (i) {" +
+                      "            case 0: i++; break;" +
+                      "            case 1: { i++; break;}" +
+                      "            case 2: throw new RuntimeException();" +
+                      "            case 3: if (true) ; break;" +
+                      "            default: i++; break;" +
+                      "        }" +
+                      "        int j = switch (i) {" +
+                      "            case 0 -> i + 1;" +
+                      "            case 1 -> { break i + 1; }" +
+                      "            default -> throw new RuntimeException();" +
+                      "        };" +
+                      "        int k = switch (i) {" +
+                      "            case 0: break i + 1;" +
+                      "            case 1: { break i + 1; }" +
+                      "            default: throw new RuntimeException();" +
+                      "        };" +
+                      "    }" +
+                      "}";
+        String expectedErrors = "Test.java:1:178: compiler.err.switch.case.unexpected.statement\n";
+        StringWriter out = new StringWriter();
+        JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null,
+                Arrays.asList("-XDrawDiagnostics", "--enable-preview", "-source", "12"),
+                null, Arrays.asList(new MyFileObject(code)));
+
+        CompilationUnitTree cut = ct.parse().iterator().next();
+        Trees trees = Trees.instance(ct);
+        List<String> spans = new ArrayList<>();
+
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitCase(CaseTree tree, Void v) {
+                if (tree.getBody() != null) {
+                    int start = (int) trees.getSourcePositions().getStartPosition(cut, tree.getBody());
+                    int end = (int) trees.getSourcePositions().getEndPosition(cut, tree.getBody());
+                    spans.add(code.substring(start, end));
+                } else {
+                    spans.add("<null>");
+                }
+                return super.visitCase(tree, v);
+            }
+        }.scan(cut, null);
+
+        List<String> expectedSpans = List.of(
+                "i++;", "{ i++; }", "throw new RuntimeException();", "if (true) ;", "i++;",
+                "<null>", "<null>", "<null>", "<null>", "<null>",
+                "i + 1"/*TODO semicolon?*/, "{ break i + 1; }", "throw new RuntimeException();",
+                "<null>", "<null>", "<null>");
+        assertEquals("the error spans are not correct; actual:" + spans, expectedSpans, spans);
+        String toString = normalize(cut.toString());
+        String expectedToString =
+                "\n" +
+                "class C {\n" +
+                "    \n" +
+                "    void t(int i) {\n" +
+                "        switch (i) {\n" +
+                "        case 0 -> i++;\n" +
+                "        case 1 -> {\n" +
+                "            i++;\n" +
+                "        }\n" +
+                "        case 2 -> throw new RuntimeException();\n" +
+                "        case 3 -> if (true) ;\n" +
+                "        default -> i++;\n" +
+                "        }\n" +
+                "        switch (i) {\n" +
+                "        case 0:\n" +
+                "            i++;\n" +
+                "            break;\n" +
+                "        \n" +
+                "        case 1:\n" +
+                "            {\n" +
+                "                i++;\n" +
+                "                break;\n" +
+                "            }\n" +
+                "        \n" +
+                "        case 2:\n" +
+                "            throw new RuntimeException();\n" +
+                "        \n" +
+                "        case 3:\n" +
+                "            if (true) ;\n" +
+                "            break;\n" +
+                "        \n" +
+                "        default:\n" +
+                "            i++;\n" +
+                "            break;\n" +
+                "        \n" +
+                "        }\n" +
+                "        int j = switch (i) {\n" +
+                "        case 0 -> break i + 1;\n" +
+                "        case 1 -> {\n" +
+                "            break i + 1;\n" +
+                "        }\n" +
+                "        default -> throw new RuntimeException();\n" +
+                "        };\n" +
+                "        int k = switch (i) {\n" +
+                "        case 0:\n" +
+                "            break i + 1;\n" +
+                "        \n" +
+                "        case 1:\n" +
+                "            {\n" +
+                "                break i + 1;\n" +
+                "            }\n" +
+                "        \n" +
+                "        default:\n" +
+                "            throw new RuntimeException();\n" +
+                "        \n" +
+                "        };\n" +
+                "    }\n" +
+                "}";
+        System.err.println("toString:");
+        System.err.println(toString);
+        System.err.println("expectedToString:");
+        System.err.println(expectedToString);
+        assertEquals("the error spans are not correct; actual:" + toString, expectedToString, toString);
+        String actualErrors = normalize(out.toString());
+        assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors);
+    }
+
+    @Test
     void testTypeParamsWithoutMethod() throws IOException {
         assert tool != null;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BlockExpression.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * @bug 8206986
+ * @summary Verify rule cases with expression statements and throw statements work.
+ * @compile --enable-preview -source 12 BlockExpression.java
+ * @run main/othervm --enable-preview BlockExpression
+ */
+
+public class BlockExpression {
+
+    public static void main(String... args) {
+        T t = T.B;
+
+        try {
+            int ii = switch (t) {
+                case A -> 0;
+                default -> throw new IllegalStateException();
+            };
+            throw new AssertionError("Expected exception not thrown.");
+        } catch (IllegalStateException ex) {
+            //OK
+        }
+    }
+
+    enum T {
+        A, B;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BooleanNumericNonNumeric.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,26 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify the type of a conditional expression with nested switch expression is computed properly
+ * @compile/fail/ref=BooleanNumericNonNumeric.out -XDrawDiagnostics --enable-preview -source 12 BooleanNumericNonNumeric.java
+ */
+
+public class BooleanNumericNonNumeric {
+
+    private void test(boolean b, int i) {
+        int r1 = 1 + (b ? switch (i) { //boolean, error
+            default -> true;
+        } : false);
+        int r2 = 1 + (b ? switch (i) { //int, ok
+            default -> 0;
+        } : 1);
+        (b ? switch (i) { //int, error
+            default -> 0;
+        } : 1).toString();
+        (b ? switch (i) { //"object", ok
+            case 0 -> true;
+            default -> 0;
+        } : 1).toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BooleanNumericNonNumeric.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+BooleanNumericNonNumeric.java:11:20: compiler.err.operator.cant.be.applied.1: +, int, boolean
+BooleanNumericNonNumeric.java:19:15: compiler.err.cant.deref: int
+- compiler.note.preview.filename: BooleanNumericNonNumeric.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/BreakTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure BreakTree.getLabel returns reasonable values
+ * @modules jdk.compiler
+ */
+
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.lang.model.element.Name;
+import javax.tools.*;
+
+import com.sun.source.tree.BreakTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+
+public class BreakTest {
+
+    private static final String CODE =
+            "public class C {" +
+            "    void t1(Integer i) {" +
+            "        LABEL: switch (i) {" +
+            "            case null: i++; break LABEL;" +
+            "            default: i++; break;" +
+            "        }" +
+            "    }" +
+            "    int t2(Integer i) {" +
+            "        return switch (i) {" +
+            "            case null: break LABEL;" +
+            "            default: break 2;" +
+            "        }" +
+            "    }" +
+            "}";
+
+    public static void main(String[] args) throws Exception {
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+        DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+        StringWriter out = new StringWriter();
+        JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+            List.of("-XDdev", "--enable-preview", "-source", "12"), null,
+            Arrays.asList(new MyFileObject(CODE)));
+        List<String> labels = new ArrayList<>();
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitBreak(BreakTree node, Void p) {
+                Name label = node.getLabel();
+                labels.add(label != null ? label.toString() : null);
+                return super.visitBreak(node, p);
+            }
+        }.scan(ct.parse(), null);
+
+        List<String> expected = Arrays.asList("LABEL", null, "LABEL", null);
+
+        if (!expected.equals(labels)) {
+            throw new AssertionError("Unexpected labels found: " + labels);
+        }
+    }
+
+    static class MyFileObject extends SimpleJavaFileObject {
+        private String text;
+
+        public MyFileObject(String text) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return text;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/EmptySwitch.java	Wed Aug 29 09:36:17 2018 +0200
@@ -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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify than an empty switch expression is rejected.
+ * @compile/fail/ref=EmptySwitch.out --enable-preview -source 12 -XDrawDiagnostics EmptySwitch.java
+ */
+
+public class EmptySwitch {
+    private void print(EmptySwitchEnum t) {
+        (switch (t) {
+        }).toString();
+    }
+
+    enum EmptySwitchEnum {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/EmptySwitch.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,4 @@
+EmptySwitch.java:33:10: compiler.err.switch.expression.empty
+- compiler.note.preview.filename: EmptySwitch.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExhaustiveEnumSwitch.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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
+ * @bug 8206986
+ * @summary Verify that an switch expression over enum can be exhaustive without default.
+ * @compile --enable-preview -source 12 ExhaustiveEnumSwitch.java
+ * @compile ExhaustiveEnumSwitchExtra.java
+ * @run main/othervm --enable-preview ExhaustiveEnumSwitch
+ */
+
+public class ExhaustiveEnumSwitch {
+    public static void main(String... args) {
+        new ExhaustiveEnumSwitch().run();
+    }
+
+    private void run() {
+        ExhaustiveEnumSwitchEnum v = ExhaustiveEnumSwitchEnum.valueOf("F");
+
+        try {
+            print(v);
+            throw new AssertionError("Expected exception did not occur.");
+        } catch (IncompatibleClassChangeError err) {
+            //ok
+        }
+    }
+
+    private String print(ExhaustiveEnumSwitchEnum t) {
+        return switch (t) {
+            case A -> "A";
+            case B -> "B";
+        };
+    }
+
+}
+enum ExhaustiveEnumSwitchEnum {
+    A, B;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExhaustiveEnumSwitchExtra.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+enum ExhaustiveEnumSwitchEnum {
+    A, B, F;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,3 @@
+ExpressionSwitch.java:30:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions)
+ExpressionSwitch.java:31:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules)
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,115 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Check expression switch works.
+ * @compile/fail/ref=ExpressionSwitch-old.out -source 9 -Xlint:-options -XDrawDiagnostics ExpressionSwitch.java
+ * @compile --enable-preview -source 12 ExpressionSwitch.java
+ * @run main/othervm --enable-preview ExpressionSwitch
+ */
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public class ExpressionSwitch {
+    public static void main(String... args) {
+        new ExpressionSwitch().run();
+    }
+
+    private void run() {
+        check(T.A, "A");
+        check(T.B, "B");
+        check(T.C, "other");
+        assertEquals(exhaustive1(T.C), "C");
+        assertEquals(scopesIsolated(T.B), "B");
+        assertEquals(lambdas1(T.B).get(), "B");
+        assertEquals(lambdas2(T.B).get(), "B");
+        localClass(T.A);
+    }
+
+    private String print(T t) {
+        return switch (t) {
+            case A -> "A";
+            case B -> { break "B"; }
+            default -> { break "other"; }
+        };
+    }
+
+    private String exhaustive1(T t) {
+        return switch (t) {
+            case A -> "A";
+            case B -> { break "B"; }
+            case C -> "C";
+            case D -> "D";
+        };
+    }
+
+    private String exhaustive2(T t) {
+        return switch (t) {
+            case A -> "A";
+            case B -> "B";
+            case C -> "C";
+            case D -> "D";
+        };
+    }
+
+    private String scopesIsolated(T t) {
+        return switch (t) {
+            case A -> { String res = "A"; break res;}
+            case B -> { String res = "B"; break res;}
+            default -> { String res = "default"; break res;}
+        };
+    }
+
+    private Supplier<String> lambdas1(T t) {
+        return switch (t) {
+            case A -> () -> "A";
+            case B -> { break () -> "B"; }
+            default -> () -> "default";
+        };
+    }
+
+    private Supplier<String> lambdas2(T t) {
+        return switch (t) {
+            case A: break () -> "A";
+            case B: { break () -> "B"; }
+            default: break () -> "default";
+        };
+    }
+
+    private void localClass(T t) {
+        String good = "good";
+        class L {
+            public String c() {
+                STOP: switch (t) {
+                    default: break STOP;
+                }
+                return switch (t) {
+                    default: break good;
+                };
+            }
+        }
+        String result = new L().c();
+        if (!Objects.equals(result, good)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    private void check(T t, String expected) {
+        String result = print(t);
+        assertEquals(result, expected);
+    }
+
+    private void assertEquals(Object result, Object expected) {
+        if (!Objects.equals(result, expected)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    enum T {
+        A, B, C, D;
+    }
+    void t() {
+        Runnable r = () -> {};
+        r.run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks1.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * 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
+ * @bug 8206986
+ * @summary Verify behavior of various kinds of breaks.
+ * @compile --enable-preview -source 12 ExpressionSwitchBreaks1.java
+ * @run main/othervm --enable-preview ExpressionSwitchBreaks1
+ */
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public class ExpressionSwitchBreaks1 {
+    public static void main(String... args) {
+        new ExpressionSwitchBreaks1().run();
+    }
+
+    private void run() {
+        check(print1(0, 0), "0-0");
+        check(print1(0, 1), "0-1");
+        check(print1(0, -1), "0-X");
+        check(print1(-1, -1), "X");
+        check(print2(0, 0, 0), "0-0-0");
+        check(print2(0, 0, 1), "0-0-1");
+        check(print2(0, 0, 2), "0-0-2");
+        check(print2(0, 0, -1), "0-0-X");
+        check(print2(0, 1, -1), "0-1");
+        check(print2(0, -1, -1), "0-X");
+        check(print2(1, -1, -1), "1");
+        check(print2(2, 5, 5), "2-X-5");
+        check(print2(-11, -1, -1), "X");
+    }
+
+    private String print1(int i, int j) {
+        switch (i) {
+            case 0:
+                return switch (j) {
+                    case 0:
+                        if (true) break "0-0";
+                    case 1:
+                        break "0-1";
+                    default:
+                        break "0-X";
+                };
+            default: return "X";
+        }
+    }
+
+    private String print2(int i, int j, int k) {
+        return switch (i) {
+            case 0:
+                String r;
+                OUTER: switch (j) {
+                    case 0:
+                        String res;
+                        INNER: switch (k) {
+                            case 0: res = "0-0-0"; break;
+                            case 1: res = "0-0-1"; break;
+                            case 2: res = "0-0-2"; break INNER;
+                            default: r = "0-0-X"; break OUTER;
+                        }
+                        r = res;
+                        break;
+                    case 1:
+                        r = "0-1";
+                        break;
+                    default:
+                        r = "0-X";
+                        break;
+                }
+                break r;
+            case 1:
+                break "1";
+            case 2:
+                LOP: while (j-- > 0) {
+                    if (k == 5) {
+                        k--;
+                        continue;
+                    }
+                    break LOP;
+                }
+                Supplier<String> getter = () -> { return "2-X-5"; };
+                break getter.get();
+            default:
+                break "X";
+        };
+    }
+
+    private void check(String result, String expected) {
+        if (!Objects.equals(result, expected)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    enum T {
+        A, B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,52 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Check behavior for invalid breaks.
+ * @compile/fail/ref=ExpressionSwitchBreaks2.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchBreaks2.java
+ */
+
+public class ExpressionSwitchBreaks2 {
+    private String print(int i, int j) {
+        LOOP: while (true) {
+        OUTER: switch (i) {
+            case 0:
+                return switch (j) {
+                    case 0:
+                        break "0-0";
+                    case 1:
+                        break ; //error: missing value
+                    case 2:
+                        break OUTER; //error: jumping outside of the switch expression
+                    case 3: {
+                        int x = -1;
+                        x: switch (i + j) {
+                            case 0: break x; //error: cannot disambiguate, wrong type as well
+                        }
+                        break "X";
+                    }
+                    case 4: return "X"; //error: no returns from inside of the switch expression
+                    case 5: continue;   //error: no continue out of the switch expression
+                    case 6: continue LOOP; //error: dtto, but with a label
+                    case 7: continue UNKNOWN; //error: unknown label
+                    default: {
+                        String x = "X";
+                        x: switch (i + j) {
+                            case 0: break ""; //error: cannot break from switch expression that is not immediatelly enclosing
+                        }
+                        break "X";
+                    }
+                };
+            case 1:
+                break "1" + undef; //error: complex value and no switch expression
+        }
+        }
+        j: print(switch (i) {
+            default: break j; //error: "j" is ambiguous (expression/label)
+        }, 0);
+        j2: print(switch (i) {
+            default: break j2;
+        }, 0);
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBreaks2.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,15 @@
+ExpressionSwitchBreaks2.java:17:25: compiler.err.break.missing.value
+ExpressionSwitchBreaks2.java:19:25: compiler.err.break.outside.switch.expression
+ExpressionSwitchBreaks2.java:23:37: compiler.err.break.ambiguous.target: x
+ExpressionSwitchBreaks2.java:27:29: compiler.err.return.outside.switch.expression
+ExpressionSwitchBreaks2.java:28:29: compiler.err.continue.outside.switch.expression
+ExpressionSwitchBreaks2.java:29:29: compiler.err.continue.outside.switch.expression
+ExpressionSwitchBreaks2.java:30:29: compiler.err.undef.label: UNKNOWN
+ExpressionSwitchBreaks2.java:34:37: compiler.err.break.expr.not.immediate: compiler.misc.tree.tag.switch
+ExpressionSwitchBreaks2.java:40:17: compiler.err.break.complex.value.no.switch.expression
+ExpressionSwitchBreaks2.java:40:29: compiler.err.cant.resolve.location: kindname.variable, undef, , , (compiler.misc.location: kindname.class, ExpressionSwitchBreaks2, null)
+ExpressionSwitchBreaks2.java:44:22: compiler.err.break.ambiguous.target: j
+ExpressionSwitchBreaks2.java:47:22: compiler.err.break.outside.switch.expression
+- compiler.note.preview.filename: ExpressionSwitchBreaks2.java
+- compiler.note.preview.recompile
+12 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify various corner cases with nested switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchBugs.java
+ * @run main/othervm --enable-preview ExpressionSwitchBugs
+ */
+
+public class ExpressionSwitchBugs {
+    public static void main(String... args) {
+        new ExpressionSwitchBugs().testNested();
+    }
+
+    private void testNested() {
+        int i = 0;
+        check(42, id(switch (42) {
+            default: i++; break 42;
+        }));
+        i = 0;
+        check(43, id(switch (42) {
+            case 42: while (i == 0) {
+                i++;
+            }
+            break 42 + i;
+            default: i++; break 42;
+        }));
+        i = 0;
+        check(42, id(switch (42) {
+            case 42: if (i == 0) {
+                break 42;
+            }
+            default: i++; break 43;
+        }));
+        i = 0;
+        check(42, id(switch (42) {
+            case 42: if (i == 0) {
+                break 41 + switch (0) {
+                    case 0 -> 1;
+                    default -> -1;
+                };
+            }
+            default: i++; break 43;
+        }));
+    }
+
+    private int id(int i) {
+        return i;
+    }
+
+    private int id(Object o) {
+        return -1;
+    }
+
+    private void check(int actual, int expected) {
+        if (actual != expected) {
+            throw new AssertionError("Unexpected result: " + actual);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchCodeFromJLS.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check switch expressions
+ * @compile --enable-preview -source 12 ExpressionSwitchCodeFromJLS.java
+ * @run main/othervm --enable-preview ExpressionSwitchCodeFromJLS
+ */
+
+public class ExpressionSwitchCodeFromJLS {
+    static void howMany(int k) {
+        switch (k) {
+            case 1: System.out.print("one ");
+            case 2: System.out.print("too ");
+            case 3: System.out.println("many");
+        }
+    }
+    static void howManyRule(int k) {
+        switch (k) {
+            case 1 -> System.out.println("one");
+            case 2 -> System.out.println("two");
+            case 3 -> System.out.println("many");
+        }
+    }
+    static void howManyGroup(int k) {
+        switch (k) {
+            case 1: System.out.println("one");
+                break;  // exit the switch
+            case 2: System.out.println("two");
+                break;  // exit the switch
+            case 3: System.out.println("many");
+                break;  // not needed, but good style
+        }
+    }
+    public static void main(String[] args) {
+        howMany(3);
+        howMany(2);
+        howMany(1);
+        howManyRule(1);
+        howManyRule(2);
+        howManyRule(3);
+        howManyGroup(1);
+        howManyGroup(2);
+        howManyGroup(3);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchDA.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check definite (un)assignment for in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchDA.java
+ * @run main/othervm --enable-preview ExpressionSwitchDA
+ */
+
+public class ExpressionSwitchDA {
+    public static void test1() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 : i=42; break;
+            default: i=42;
+        }
+        System.out.println(i);
+    }
+    public static void test2(){
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0  -> i=42;
+            default -> i=42;
+        }
+        System.out.println(i);
+    }
+    public static void test3(){
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0  -> { i=42; }
+            default -> { i=42; }
+        }
+        System.out.println(i);
+    }
+    public static void test4(){
+        int i;
+        int j = 0;
+        int k = switch (j) {
+            case 0  -> i=42;
+            default -> i=42;
+        };
+        System.out.println(i);
+    }
+    public static void test5(){
+        int i;
+        int j = 0;
+        int k = switch (j) {
+            case 0  -> { i=42; break 42; }
+            default -> i=42;
+        };
+        System.out.println(i);
+    }
+    public static void test6(){
+        int i;
+        int j = 0;
+        int k = switch (j) {
+            case 0  -> i=42;
+            default -> { i=42; break 42; }
+        };
+        System.out.println(i);
+    }
+    public static void test7(){
+        int i;
+        int j = 0;
+        int k = switch (j) {
+            case 0  -> { i=42; break 42; }
+            default -> { i=42; break 42; }
+        };
+        System.out.println(i);
+    }
+    public static void test8() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 : i=42; break;
+            default: throw new NullPointerException();
+        }
+        System.out.println(i);
+    }
+    public static void test9() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 -> i=42;
+            default ->  throw new NullPointerException();
+        }
+        System.out.println(i);
+    }
+    public static void test10() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 -> { i=42; System.out.print(i);}
+            default ->  throw new NullPointerException();
+        }
+        System.out.println(i);
+    }
+    public static void test11() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 -> { i=42; System.out.print(i);}
+            default ->  { throw new NullPointerException(); }
+        }
+        System.out.println(i);
+    }
+    public static void test12() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 : i=42; break;
+            default: return;
+        }
+        System.out.println(i);
+    }
+    public static void test13() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 -> i=42;
+            default -> { return; }
+        }
+        System.out.println(i);
+    }
+    public static void test14() {
+        int i;
+        int j = 0;
+        switch (j) {
+            case 0 -> { i=42; }
+            default -> { return; }
+        }
+        System.out.println(i);
+    }
+    public static void test15() {
+        final int i;
+        int j = 0;
+        switch (j) {
+            case 0 -> { i=42; }
+            default -> { i=42; }
+        }
+        System.out.println(i);
+    }
+    public static void main(String[] args) {
+        test1();
+        test2();
+        test3();
+        test4();
+        test5();
+        test6();
+        test7();
+        test8();
+        test9();
+        test10();
+        test11();
+        test12();
+        test13();
+        test14();
+        test15();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check fall through in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchFallThrough.java
+ * @run main/othervm --enable-preview ExpressionSwitchFallThrough
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class ExpressionSwitchFallThrough {
+    public static void main(String... args) {
+        new ExpressionSwitchFallThrough().run();
+    }
+
+    private void run() {
+        runTest(this::expression1);
+        runTest(this::expression2);
+    }
+
+    private void runTest(Function<T, String> print) {
+        check(T.A,  print, "ab");
+        check(T.B,  print, "b");
+        check(T.C,  print, "");
+    }
+
+    private String expression1(T t) {
+        String help = "";
+        return switch (t) {
+            case A: help = "a";
+            case B: help += "b";
+            default: break help;
+        };
+    }
+
+    private String expression2(T t) {
+        String help = "";
+        return switch (t) {
+            case A: help = "a";
+            case B: help += "b";
+            default: break help;
+        };
+    }
+
+    private void check(T t, Function<T, String> print, String expected) {
+        String result = print.apply(t);
+        if (!Objects.equals(result, expected)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    enum T {
+        A, B, C;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough1.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * 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
+ * @bug 8206986
+ * @summary Check fall through in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchFallThrough1.java
+ * @run main/othervm --enable-preview ExpressionSwitchFallThrough1
+ */
+
+import java.util.Objects;
+
+public class ExpressionSwitchFallThrough1 {
+    public static void main(String... args) {
+        new ExpressionSwitchFallThrough1().test();
+    }
+
+    private void test() {
+        assertEquals("01", printExprFallThrough(0));
+        assertEquals("1", printExprFallThrough(1));
+        assertEquals("other", printExprFallThrough(3));
+        assertEquals("01", printStatementFallThrough(0));
+        assertEquals("1", printStatementFallThrough(1));
+        assertEquals("other", printStatementFallThrough(3));
+    }
+
+    private String printExprFallThrough(Integer p) {
+        String result = "";
+        return switch (p) {
+            case 0: result += "0";
+            case 1: result += "1";
+                break result;
+            default: break "other";
+        };
+    }
+
+    private String printStatementFallThrough(Integer p) {
+        String result = "";
+        switch (p) {
+            case 0: result += "0";
+            case 1: result += "1";
+                break ;
+            default: result = "other";
+                break;
+        }
+        return result;
+    }
+
+    private static void assertEquals(Object expected, Object actual) {
+        if (!Objects.equals(actual, expected)) {
+            throw new AssertionError("Unexpected result: " + actual + ", expected: " + expected);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInExpressionSwitch.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Check switch expressions embedded in switch expressions.
+ * @compile --enable-preview -source 12 ExpressionSwitchInExpressionSwitch.java
+ * @run main/othervm --enable-preview ExpressionSwitchInExpressionSwitch
+ */
+
+public class ExpressionSwitchInExpressionSwitch {
+    public static void main(String[] args) {
+
+        int j = 42;
+        int i = switch (j) {
+            default -> (switch (j) { default -> 0; } )+1;
+        };
+        if (i!=1) {
+            throw new AssertionError("Unexpected result: " + i);
+        }
+        i = switch (j) {
+            default -> {
+                int k = switch (j) {
+                    default -> {
+                        break 42;
+                    }
+                };
+                System.out.println("didn't break to the top level");
+                break 43;
+            }
+        };
+        if (i!=43) {
+            throw new AssertionError("Unexpected result: " + i);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Check types inferred for switch expressions.
+ * @compile/fail/ref=ExpressionSwitchInfer.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchInfer.java
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExpressionSwitchInfer {
+
+    private static final String NULL = "null";
+
+    private <T> T test(List<T> l, Class<T> c, String param) {
+        test(param == NULL ? new ArrayList<>() : new ArrayList<>(), CharSequence.class, param).charAt(0);
+        test(param == NULL ? new ArrayList<>() : new ArrayList<>(), CharSequence.class, param).substring(0);
+
+        test(switch (param) {
+            case NULL -> new ArrayList<>();
+            default -> new ArrayList<>();
+        }, CharSequence.class, param).charAt(0);
+        test(switch (param) {
+            case NULL -> new ArrayList<>();
+            default -> new ArrayList<>();
+        }, CharSequence.class, param).substring(0);
+
+        String str = switch (param) {
+            case "" -> {
+                break 0;
+            } default ->"default";
+        };
+
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+ExpressionSwitchInfer.java:17:95: compiler.err.cant.resolve.location.args: kindname.method, substring, , int, (compiler.misc.location: kindname.interface, java.lang.CharSequence, null)
+ExpressionSwitchInfer.java:26:38: compiler.err.cant.resolve.location.args: kindname.method, substring, , int, (compiler.misc.location: kindname.interface, java.lang.CharSequence, null)
+ExpressionSwitchInfer.java:30:23: compiler.err.prob.found.req: (compiler.misc.incompatible.type.in.switch.expression: (compiler.misc.inconvertible.types: int, java.lang.String))
+- compiler.note.preview.filename: ExpressionSwitchInfer.java
+- compiler.note.preview.recompile
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchIntersectionTypes.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Verify behavior when an intersection type is inferred for switch expression.
+ * @compile --enable-preview -source 12 ExpressionSwitchIntersectionTypes.java
+ * @run main/othervm --enable-preview ExpressionSwitchIntersectionTypes
+ */
+
+public class ExpressionSwitchIntersectionTypes<X  extends java.io.Serializable & Runnable> {
+
+    void test1(int i, X x) {
+        Runnable r1 = switch (i) {
+            default -> x;
+        };
+        r1.run();
+    }
+
+    void test2(int i, X x) {
+        (switch (i) {
+            default -> x;
+        }).run();
+    }
+
+    public static void main(String[] args) {
+        ExpressionSwitchIntersectionTypes t = new ExpressionSwitchIntersectionTypes();
+        try {
+            t.test1(0, "");
+            throw new AssertionError("Expected exception didn't occur.");
+        } catch (ClassCastException ex) {
+            //good
+        }
+        try {
+            t.test2(0, "");
+            throw new AssertionError("Expected exception didn't occur.");
+        } catch (ClassCastException ex) {
+            //good
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify behavior of not exhaustive switch expressions.
+ * @compile/fail/ref=ExpressionSwitchNotExhaustive.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchNotExhaustive.java
+ */
+
+public class ExpressionSwitchNotExhaustive {
+    private String print(int i) {
+        return switch (i) {
+            case 42 -> "42";
+            case 43 -> "43";
+        };
+    }
+    private String e(E e) {
+        return switch (e) {
+            case A -> "42";
+        };
+    }
+    private String f(int i, E e) {
+        return switch (i) {
+            case 0:
+                String s;
+                switch (e) {
+                    case A:
+                        s = "42";
+                        break;
+                }
+                break s;
+            default:
+                break "43";
+        };
+    }
+    enum E {
+        A, B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchNotExhaustive.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,6 @@
+ExpressionSwitchNotExhaustive.java:10:16: compiler.err.not.exhaustive
+ExpressionSwitchNotExhaustive.java:16:16: compiler.err.not.exhaustive
+ExpressionSwitchNotExhaustive.java:29:23: compiler.err.var.might.not.have.been.initialized: s
+- compiler.note.preview.filename: ExpressionSwitchNotExhaustive.java
+- compiler.note.preview.recompile
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnreachable.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,57 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify reachability in switch expressions.
+ * @compile/fail/ref=ExpressionSwitchUnreachable.out -XDrawDiagnostics --enable-preview -source 12 ExpressionSwitchUnreachable.java
+ */
+
+public class ExpressionSwitchUnreachable {
+
+    public static void main(String[] args) {
+        int z = 42;
+        int i = switch (z) {
+            case 0 -> {
+                break 42;
+                System.out.println("Unreachable");  //Unreachable
+            }
+            default -> 0;
+        };
+        i = switch (z) {
+            case 0 -> {
+                break 42;
+                break 42; //Unreachable
+            }
+            default -> 0;
+        };
+        i = switch (z) {
+            case 0:
+                System.out.println("0");
+                break 42;
+                System.out.println("1");    //Unreachable
+            default : break 42;
+        };
+        i = switch (z) {
+            case 0 -> 42;
+            default -> {
+                break 42;
+                System.out.println("Unreachable"); //Unreachable
+            }
+        };
+        i = switch (z) {
+            case 0: break 42;
+            default:
+                System.out.println("0");
+                break 42;
+                System.out.println("1");    //Unreachable
+        };
+        i = switch (z) {
+            case 0:
+            default:
+                System.out.println("0");
+                break 42;
+                System.out.println("1");    //Unreachable
+        };
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchUnreachable.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,9 @@
+ExpressionSwitchUnreachable.java:15:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:22:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:30:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:37:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:45:17: compiler.err.unreachable.stmt
+ExpressionSwitchUnreachable.java:52:17: compiler.err.unreachable.stmt
+- compiler.note.preview.filename: ExpressionSwitchUnreachable.java
+- compiler.note.preview.recompile
+6 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ParseIncomplete.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure than parser can parse incomplete sources
+ * @modules jdk.compiler
+ */
+
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.tools.*;
+
+import com.sun.source.util.JavacTask;
+
+public class ParseIncomplete {
+
+    private static final String CODE =
+            "public class C {" +
+            "    void t1(Integer i) {" +
+            "        switch (i) {" +
+            "            case null: i++; break;" +
+            "            case 0, 1: i++; break;" +
+            "            default: i++; break;" +
+            "        }" +
+            "    }" +
+            "    int t2(Integer i) {" +
+            "        return switch (i) {" +
+            "            case null: break 0;" +
+            "            case 0, 1: break 1;" +
+            "            default: break 2;" +
+            "        }" +
+            "    }" +
+            "}";
+
+    public static void main(String[] args) throws Exception {
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+        DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+        for (int i = 0; i < CODE.length(); i++) {
+            String code = CODE.substring(0, i + 1);
+            StringWriter out = new StringWriter();
+            try {
+                JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+                    List.of("-XDdev", "--enable-preview", "-source", "12"), null,
+                    Arrays.asList(new MyFileObject(code)));
+                ct.parse().iterator().next();
+            } catch (Throwable t) {
+                System.err.println("Unexpected exception for code: " + code);
+                System.err.println("output: " + out);
+                throw t;
+            }
+            if (!out.toString().isEmpty()) {
+                System.err.println("Unexpected compiler for code: " + code);
+                System.err.println(out);
+                throw new AssertionError();
+            }
+        }
+    }
+
+    static class MyFileObject extends SimpleJavaFileObject {
+        private String text;
+
+        public MyFileObject(String text) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return text;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ParserRecovery.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify the parser handles broken input gracefully.
+ * @compile/fail/ref=ParserRecovery.out -XDrawDiagnostics --enable-preview -source 12 ParserRecovery.java
+ */
+
+public class ParserRecovery {
+    void t1(int e) {
+         int i = switch (e) { case any; };
+    }
+    void t2(int e) {
+         switch (e) { case any; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ParserRecovery.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+ParserRecovery.java:10:39: compiler.err.expected2: :, ->
+ParserRecovery.java:13:31: compiler.err.expected2: :, ->
+- compiler.note.preview.filename: ParserRecovery.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/SwitchExpressionScopesIsolated.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that scopes in rule cases are isolated.
+ * @compile/fail/ref=SwitchExpressionScopesIsolated.out -XDrawDiagnostics --enable-preview -source 12 SwitchExpressionScopesIsolated.java
+ */
+
+public class SwitchExpressionScopesIsolated {
+
+    private String scopesIsolated(int i) {
+        return switch (i) {
+            case 0 -> { String res = ""; break res; }
+            case 1 -> { res = ""; break res; }
+            default -> { res = ""; break res; }
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/SwitchExpressionScopesIsolated.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,7 @@
+SwitchExpressionScopesIsolated.java:13:25: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+SwitchExpressionScopesIsolated.java:13:41: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+SwitchExpressionScopesIsolated.java:14:26: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+SwitchExpressionScopesIsolated.java:14:42: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchExpressionScopesIsolated, null)
+- compiler.note.preview.filename: SwitchExpressionScopesIsolated.java
+- compiler.note.preview.recompile
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/SwitchExpressionSimpleVisitorTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure SimpleTreeVisitor.visitSwitchExpression behaves as it should
+ * @modules jdk.compiler
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.tools.*;
+
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.SwitchExpressionTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.SimpleTreeVisitor;
+import com.sun.source.util.TreePathScanner;
+
+public class SwitchExpressionSimpleVisitorTest {
+
+    public static void main(String[] args) throws Exception {
+        new SwitchExpressionSimpleVisitorTest().run();
+    }
+
+    void run() throws Exception {
+        String code = "class Test {\n" +
+                      "    int t(int i) {\n" +
+                      "         return switch(i) {\n" +
+                      "              default: break -1;\n" +
+                      "         }\n" +
+                      "    }\n" +
+                      "}\n";
+        int[] callCount = new int[1];
+        int[] switchExprNodeCount = new int[1];
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitSwitchExpression(SwitchExpressionTree node, Void p) {
+                node.accept(new SimpleTreeVisitor<Void, Void>() {
+                    @Override
+                    protected Void defaultAction(Tree defaultActionNode, Void p) {
+                        callCount[0]++;
+                        if (node == defaultActionNode) {
+                            switchExprNodeCount[0]++;
+                        }
+                        return null;
+                    }
+                }, null);
+                return super.visitSwitchExpression(node, p);
+            }
+        }.scan(parse(code), null);
+
+        if (callCount[0] != 1 || switchExprNodeCount[0] != 1) {
+            throw new AssertionError("Unexpected counts; callCount=" + callCount[0] +
+                                     ", switchExprNodeCount=" + switchExprNodeCount[0]);
+        }
+    }
+
+    private CompilationUnitTree parse(String code) throws IOException {
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+        DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+        StringWriter out = new StringWriter();
+        JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+            List.of("--enable-preview", "-source", "12"), null,
+            Arrays.asList(new MyFileObject(code)));
+        return ct.parse().iterator().next();
+    }
+
+    static class MyFileObject extends SimpleJavaFileObject {
+        private String text;
+
+        public MyFileObject(String text) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return text;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/CaseTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure CaseTree methods return expected values
+ * @modules jdk.compiler
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.tools.*;
+
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+
+public class CaseTest {
+
+    public static void main(String[] args) throws Exception {
+        new CaseTest().testLabels();
+        new CaseTest().testStatement();
+        new CaseTest().testRule();
+    }
+
+    void testLabels() throws Exception {
+        String code = "class Test {\n" +
+                      "    void t(int i) {\n" +
+                      "         switch(i) {\n" +
+                      "              case 0: break;\n" +
+                      "              case 1, 2: breal;\n" +
+                      "              default: breal;\n" +
+                      "         }\n" +
+                      "    }\n" +
+                      "}\n";
+        List<String> labels = new ArrayList<>();
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitCase(CaseTree node, Void p) {
+                labels.add(String.valueOf(node.getExpression()));
+                labels.add(node.getExpressions().stream()
+                                                .map(String::valueOf)
+                                                .collect(Collectors.joining(",", "[", "]")));
+                return super.visitCase(node, p);
+            }
+        }.scan(parse(code), null);
+
+        List<String> expected = Arrays.asList("0", "[0]", "1", "[1,2]", "null", "[]");
+
+        if (!expected.equals(labels)) {
+            throw new AssertionError("Unexpected labels found: " + labels);
+        }
+    }
+
+    void testStatement() throws Exception {
+        String code = "class Test {\n" +
+                      "    void t(int i) {\n" +
+                      "         switch(i) {\n" +
+                      "              case 0:" +
+                      "                  System.err.println();\n" +
+                      "                  break;\n" +
+                      "         }\n" +
+                      "    }\n" +
+                      "}\n";
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitCase(CaseTree node, Void p) {
+                if (node.getStatements().size() != 2) {
+                    throw new AssertionError("Unexpected statements: " + node.getStatements());
+                }
+                if (node.getBody() != null) {
+                    throw new AssertionError("Unexpected body: " + node.getBody());
+                }
+                return super.visitCase(node, p);
+            }
+        }.scan(parse(code), null);
+    }
+
+    void testRule() throws Exception {
+        String code = "class Test {\n" +
+                      "    void t(int i) {\n" +
+                      "         switch(i) {\n" +
+                      "              case 0 -> {" +
+                      "                  System.err.println();\n" +
+                      "              };\n" +
+                      "         }\n" +
+                      "    }\n" +
+                      "}\n";
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitCase(CaseTree node, Void p) {
+                if (node.getStatements() != null) {
+                    throw new AssertionError("Unexpected statements: " + node.getStatements());
+                }
+                if (node.getBody().getKind() != Tree.Kind.BLOCK) {
+                    throw new AssertionError("Unexpected body: " + node.getBody());
+                }
+                return super.visitCase(node, p);
+            }
+        }.scan(parse(code), null);
+    }
+
+    private CompilationUnitTree parse(String code) throws IOException {
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+        DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+        StringWriter out = new StringWriter();
+        JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+            List.of("-XDdev", "--enable-preview", "-source", "12"), null,
+            Arrays.asList(new MyFileObject(code)));
+        return ct.parse().iterator().next();
+    }
+
+    static class MyFileObject extends SimpleJavaFileObject {
+        private String text;
+
+        public MyFileObject(String text) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return text;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsExpression-old.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,4 @@
+MultipleLabelsExpression.java:31:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions)
+MultipleLabelsExpression.java:32:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules)
+MultipleLabelsExpression.java:33:19: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels)
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsExpression.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify cases with multiple labels work properly.
+ * @compile/fail/ref=MultipleLabelsExpression-old.out -source 9 -Xlint:-options -XDrawDiagnostics MultipleLabelsExpression.java
+ * @compile --enable-preview -source 12 MultipleLabelsExpression.java
+ * @run main/othervm --enable-preview MultipleLabelsExpression
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class MultipleLabelsExpression {
+    public static void main(String... args) {
+        new MultipleLabelsExpression().run();
+    }
+
+    private void run() {
+        runTest(this::expression1);
+    }
+
+    private void runTest(Function<T, String> print) {
+        check(T.A,  print, "A");
+        check(T.B,  print, "B-C");
+        check(T.C,  print, "B-C");
+        check(T.D,  print, "D");
+        check(T.E,  print, "other");
+    }
+
+    private String expression1(T t) {
+        return switch (t) {
+            case A -> "A";
+            case B, C -> { break "B-C"; }
+            case D -> "D";
+            default -> "other";
+        };
+    }
+
+    private void check(T t, Function<T, String> print, String expected) {
+        String result = print.apply(t);
+        if (!Objects.equals(result, expected)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    enum T {
+        A, B, C, D, E;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsStatement-old.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,2 @@
+MultipleLabelsStatement.java:35:21: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels)
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsStatement.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,53 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify cases with multiple labels work properly.
+ * @compile/fail/ref=MultipleLabelsStatement-old.out -source 9 -Xlint:-options -XDrawDiagnostics MultipleLabelsStatement.java
+ * @compile --enable-preview -source 12 MultipleLabelsStatement.java
+ * @run main/othervm --enable-preview MultipleLabelsStatement
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class MultipleLabelsStatement {
+    public static void main(String... args) {
+        new MultipleLabelsStatement().run();
+    }
+
+    private void run() {
+        runTest(this::statement1);
+    }
+
+    private void runTest(Function<T, String> print) {
+        check(T.A,  print, "A");
+        check(T.B,  print, "B-C");
+        check(T.C,  print, "B-C");
+        check(T.D,  print, "D");
+        check(T.E,  print, "other");
+    }
+
+    private String statement1(T t) {
+        String res;
+
+        switch (t) {
+            case A: res = "A"; break;
+            case B, C: res = "B-C"; break;
+            case D: res = "D"; break;
+            default: res = "other"; break;
+        }
+
+        return res;
+    }
+
+    private void check(T t, Function<T, String> print, String expected) {
+        String result = print.apply(t);
+        if (!Objects.equals(result, expected)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    enum T {
+        A, B, C, D, E;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/RuleParsingTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8206986
+ * @summary Ensure rule cases can be parsed correctly for complex expressions.
+ * @modules jdk.compiler
+ */
+
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map.Entry;
+
+import javax.tools.*;
+
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.TreePathScanner;
+import com.sun.source.util.Trees;
+
+public class RuleParsingTest {
+
+    public static void main(String[] args) throws Exception {
+        new RuleParsingTest().testParseComplexExpressions();
+    }
+
+    void testParseComplexExpressions() throws Exception {
+        String[] expressions = {
+            "(a)",
+            "a",
+            "a + a",
+            "~a + a",
+            "a = a",
+            "a += a",
+            "a + (a)",
+            "a + (a) b",
+            "true ? a : b",
+            "m(() -> {})",
+            "m(() -> 1)",
+            "m(a -> 1)",
+            "m((t a) -> 1)",
+        };
+        StringBuilder code = new StringBuilder();
+        List<Entry<Long, Long>> spans = new ArrayList<>();
+        code.append("class Test {\n" +
+                    "    void t(int i) {\n");
+        for (boolean switchExpr : new boolean[] {false, true}) {
+            if (switchExpr) {
+                code.append("         int j = switch(i) {\n");
+            } else {
+                code.append("         switch(i) {\n");
+            }
+            for (String expr : expressions) {
+                code.append("case ");
+                int start = code.length();
+                code.append(expr);
+                spans.add(new SimpleEntry<>((long) start, (long) code.length()));
+                code.append(" -> {}");
+            }
+            code.append("         };\n");
+        }
+        code.append("    }\n" +
+                    "}\n");
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+        DiagnosticListener<JavaFileObject> noErrors = d -> { throw new AssertionError(d.getMessage(null)); };
+
+        StringWriter out = new StringWriter();
+        JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+            List.of("--enable-preview", "-source", "12"), null,
+            Arrays.asList(new MyFileObject(code.toString())));
+        CompilationUnitTree cut = ct.parse().iterator().next();
+        Trees trees = Trees.instance(ct);
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitCase(CaseTree node, Void p) {
+                long start = trees.getSourcePositions().getStartPosition(cut, node.getExpression());
+                long end = trees.getSourcePositions().getEndPosition(cut, node.getExpression());
+                if (!spans.remove(new SimpleEntry<>(start, end))) {
+                    throw new AssertionError("Did not find an expression span in expected spans: " +
+                                             start + "-" + end +
+                                             " '" + node.getExpression().toString() + "'");
+                }
+                return super.visitCase(node, p);
+            }
+        }.scan(cut, null);
+
+        if (!spans.isEmpty()) {
+            throw new AssertionError("Remaning spans: " + spans);
+        }
+    }
+
+    static class MyFileObject extends SimpleJavaFileObject {
+        private String text;
+
+        public MyFileObject(String text) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return text;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchArrowBrokenConstant.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,32 @@
+/*
+ * @test /nodymaticcopyright/
+ * @bug 8206986
+ * @summary Verify reasonable errors are produced when neither ':' nor '->'
+ *          is found are the expression of a case
+ * @compile/fail/ref=SwitchArrowBrokenConstant.out -source 12 --enable-preview -Xlint:-preview -XDrawDiagnostics SwitchArrowBrokenConstant.java
+ */
+
+public class SwitchArrowBrokenConstant {
+
+    private String likeLambda(int i) {
+        switch (i) {
+            case (a, b) -> {}
+        }
+        return switch (i) {
+            case (a, b) -> {}
+        };
+        switch (i) {
+            case a;
+        }
+        return switch (i) {
+            case a;
+        };
+        switch (i) {
+            default ;
+        }
+        return switch (i) {
+            default ;
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchArrowBrokenConstant.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,11 @@
+SwitchArrowBrokenConstant.java:13:20: compiler.err.expected: ')'
+SwitchArrowBrokenConstant.java:13:23: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:16:20: compiler.err.expected: ')'
+SwitchArrowBrokenConstant.java:16:23: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:19:19: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:22:19: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:25:20: compiler.err.expected2: :, ->
+SwitchArrowBrokenConstant.java:28:20: compiler.err.expected2: :, ->
+- compiler.note.preview.filename: SwitchArrowBrokenConstant.java
+- compiler.note.preview.recompile
+8 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchNoExtraTypes.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify switch over boolean/long/float/double is not allowed.
+ * @compile/fail/ref=SwitchNoExtraTypes.out -XDrawDiagnostics SwitchNoExtraTypes.java
+ */
+
+public class SwitchNoExtraTypes {
+
+    private void switchBoolean(boolean b) {
+        switch (b) {
+            case true: return ;
+        }
+    }
+
+    private void switchLong(long l) {
+        switch (l) {
+            case 0: return ;
+        }
+    }
+
+    private void switchFloat(float f) {
+        switch (f) {
+            case 0: return ;
+        }
+    }
+
+    private void switchDouble(double d) {
+        switch (d) {
+            case 0: return ;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchNoExtraTypes.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+SwitchNoExtraTypes.java:11:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: boolean, int)
+SwitchNoExtraTypes.java:17:16: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: long, int)
+SwitchNoExtraTypes.java:23:16: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: float, int)
+SwitchNoExtraTypes.java:29:16: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: double, int)
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchObject.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify switch over Object is not allowed.
+ * @compile/fail/ref=SwitchObject.out -XDrawDiagnostics SwitchObject.java
+ */
+public class SwitchObject {
+
+    private int longSwitch(Object o) {
+        switch (o) {
+            case -1: return 0;
+            case "": return 1;
+            default: return 3;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchObject.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,2 @@
+SwitchObject.java:10:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, int)
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementArrow-old.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,3 @@
+SwitchStatementArrow.java:41:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules)
+SwitchStatementArrow.java:42:21: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels)
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementArrow.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * @test /nodymaticcopyright/
+ * @bug 8206986
+ * @summary Verify rule cases work properly.
+ * @compile/fail/ref=SwitchStatementArrow-old.out -source 9 -Xlint:-options -XDrawDiagnostics SwitchStatementArrow.java
+ * @compile --enable-preview -source 12 SwitchStatementArrow.java
+ * @run main/othervm --enable-preview SwitchStatementArrow
+ */
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class SwitchStatementArrow {
+    public static void main(String... args) {
+        new SwitchStatementArrow().run();
+    }
+
+    private void run() {
+        runTest(this::statement1);
+        runTest(this::scope);
+    }
+
+    private void runTest(Function<T, String> print) {
+        check(T.A,  print, "A");
+        check(T.B,  print, "B-C");
+        check(T.C,  print, "B-C");
+        try {
+            print.apply(T.D);
+            throw new AssertionError();
+        } catch (IllegalStateException ex) {
+            if (!Objects.equals("D", ex.getMessage()))
+                throw new AssertionError(ex);
+        }
+        check(T.E,  print, "other");
+    }
+
+    private String statement1(T t) {
+        String res;
+
+        switch (t) {
+            case A -> { res = "A"; }
+            case B, C -> res = "B-C";
+            case D -> throw new IllegalStateException("D");
+            default -> { res = "other"; break; }
+        }
+
+        return res;
+    }
+
+    private String scope(T t) {
+        String res;
+
+        switch (t) {
+            case A -> { String r = "A"; res = r; }
+            case B, C -> {String r = "B-C"; res = r; }
+            case D -> throw new IllegalStateException("D");
+            default -> { String r = "other"; res = r; break; }
+        }
+
+        return res;
+    }
+
+    private int r;
+
+    private void check(T t, Function<T, String> print, String expected) {
+        String result = print.apply(t);
+        if (!Objects.equals(result, expected)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    enum T {
+        A, B, C, D, E;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that rule and ordinary cases cannot be mixed.
+ * @compile/fail/ref=SwitchStatementBroken.out -XDrawDiagnostics --enable-preview -source 12 SwitchStatementBroken.java
+ */
+
+public class SwitchStatementBroken {
+
+    private void statementBroken(int i) {
+        String res;
+
+        switch (i) {
+            case 0 -> { res = "NULL-A"; }
+            case 1: { res = "NULL-A"; break; }
+            case 2: { res = "NULL-A"; break; }
+            default -> { res = "NULL-A"; break; }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,4 @@
+SwitchStatementBroken.java:15:13: compiler.err.switch.mixing.case.types
+- compiler.note.preview.filename: SwitchStatementBroken.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken2.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,27 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that not allowed types of statements cannot be used in rule case.
+ * @compile/fail/ref=SwitchStatementBroken2.out -XDrawDiagnostics --enable-preview -source 12 SwitchStatementBroken2.java
+ */
+
+public class SwitchStatementBroken2 {
+
+    private void statementArrowNotArbitraryStatements(int i, int j) {
+        String res;
+
+        switch (i) {
+            case 0 -> res = "NULL-A";
+            case 1 -> { res = "NULL-A"; }
+            case 2 -> throw new IllegalStateException();
+            case 3 -> if  (j < 0) res = "A"; else res = "B";
+            case 4 -> while (j-- > 0) res += "I";
+            case 5 -> switch (j) {
+                case 0: res = "0"; break;
+            }
+            case 7 -> int i;
+            default -> if  (j < 0) res = "A"; else res = "B";
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken2.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,8 @@
+SwitchStatementBroken2.java:17:23: compiler.err.switch.case.unexpected.statement
+SwitchStatementBroken2.java:18:23: compiler.err.switch.case.unexpected.statement
+SwitchStatementBroken2.java:19:23: compiler.err.switch.case.unexpected.statement
+SwitchStatementBroken2.java:22:27: compiler.err.variable.not.allowed
+SwitchStatementBroken2.java:23:24: compiler.err.switch.case.unexpected.statement
+- compiler.note.preview.filename: SwitchStatementBroken2.java
+- compiler.note.preview.recompile
+5 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementScopesIsolated.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify that scopes in rule cases are isolated.
+ * @compile/fail/ref=SwitchStatementScopesIsolated.out -XDrawDiagnostics --enable-preview -source 12 SwitchStatementScopesIsolated.java
+ */
+
+public class SwitchStatementScopesIsolated {
+
+    private void scopesIsolated(int i) {
+        switch (i) {
+            case 0 -> { String res = "NULL-A"; }
+            case 1 -> { res = "NULL-A"; }
+            default -> { res = "NULL-A"; }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementScopesIsolated.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,5 @@
+SwitchStatementScopesIsolated.java:13:25: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchStatementScopesIsolated, null)
+SwitchStatementScopesIsolated.java:14:26: compiler.err.cant.resolve.location: kindname.variable, res, , , (compiler.misc.location: kindname.class, SwitchStatementScopesIsolated, null)
+- compiler.note.preview.filename: SwitchStatementScopesIsolated.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchnull/SwitchNullDisabled.java	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8206986
+ * @summary Verify "case null" is not allowed.
+ * @compile/fail/ref=SwitchNullDisabled.out -XDrawDiagnostics SwitchNullDisabled.java
+ */
+
+public class SwitchNullDisabled {
+    private int switchNull(String str) {
+        switch (str) {
+            case null: return 0;
+            case "": return 1;
+            default: return 2;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchnull/SwitchNullDisabled.out	Wed Aug 29 09:36:17 2018 +0200
@@ -0,0 +1,2 @@
+SwitchNullDisabled.java:11:18: compiler.err.switch.null.not.allowed
+1 error
--- a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -47,11 +47,14 @@
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
+
 import javax.tools.*;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.Tree;
 import com.sun.source.util.TreeScanner;
 import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCCase;
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
 import com.sun.tools.javac.tree.JCTree.TypeBoundKind;
@@ -150,6 +153,11 @@
                             // The modifiers will not found by TreeScanner,
                             // but the embedded annotations will be.
                             reflectiveScan(((JCModuleDecl) tree).mods.annotations);
+                        } else if (tree instanceof JCCase &&
+                                   ((JCCase) tree).getCaseKind() == CaseKind.RULE &&
+                                   f.getName().equals("stats")) {
+                            //value case, visit value:
+                            reflectiveScan(((JCCase) tree).getBody());
                         } else {
                             reflectiveScan(f.get(tree));
                         }
--- a/test/langtools/tools/javac/tree/TreePosTest.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/test/langtools/tools/javac/tree/TreePosTest.java	Wed Aug 29 09:36:17 2018 +0200
@@ -69,6 +69,7 @@
 import javax.tools.JavaFileObject;
 import javax.tools.StandardJavaFileManager;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.util.JavacTask;
 import com.sun.tools.javac.api.JavacTool;
@@ -76,6 +77,7 @@
 import com.sun.tools.javac.tree.EndPosTable;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCAnnotatedType;
+import com.sun.tools.javac.tree.JCTree.JCCase;
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.tree.JCTree.JCNewClass;
 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
@@ -440,6 +442,15 @@
                 super.visitVarDef(tree);
         }
 
+        @Override
+        public void visitCase(JCCase tree) {
+            if (tree.getCaseKind() == CaseKind.RULE) {
+                scan(tree.getBody());
+            } else {
+                super.visitCase(tree);
+            }
+        }
+
         boolean check(Info encl, Info self) {
             if (excludeTags.size() > 0) {
                 if (encl != null && excludeTags.contains(getTagName(encl.tag))