changeset 52758:268a41142f4b amber-demo

Automatic merge with patterns
author mcimadamore
date Fri, 05 Oct 2018 19:50:15 +0200
parents a8d4aa1f4e14 caa0d8cd8e5d
children 9a7a275389fc
files
diffstat 91 files changed, 4803 insertions(+), 281 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+/**
+ * A binding pattern tree
+ */
+public interface BindingPatternTree extends PatternTree {
+
+    /**
+     * Returns the type of the bind variable.
+     * @return the type
+     */
+    Tree getType();
+
+}
+
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Fri Oct 05 19:50:15 2018 +0200
@@ -32,7 +32,7 @@
  *
  * For example:
  * <pre>
- *   case <em>expression</em> :
+ *   case <em>pattern</em> :
  *       <em>statements</em>
  *
  *   default :
@@ -48,10 +48,13 @@
 public interface CaseTree extends Tree {
     /**
      * 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.
+     * {@code null} if this is the default case
+     * or this case covers a non-constant pattern.
+     * If this case has multiple patterns, returns the first label.
      * @return the expression for the case, or null
+     * @deprecated use {@link #getPattern()}
      */
+    @Deprecated
     ExpressionTree getExpression();
 
     /**
@@ -69,6 +72,13 @@
     List<? extends ExpressionTree> getExpressions();
 
     /**
+     * Returns the patterns for this case.
+     * For default case, returns an empty list.
+     * @return the patterns for this case
+     */
+    List<? extends PatternTree> getPatterns();
+
+    /**
      * For case with kind {@linkplain CaseKind#STATEMENT},
      * returns the statements labeled by the case.
      * Returns {@code null} for case with kind
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/LiteralPatternTree.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+/**
+ * A literal pattern tree
+ */
+public interface LiteralPatternTree extends PatternTree {
+
+    /**
+     * The literal value of this pattern.
+     * @return literal value of this pattern
+     */
+    public ExpressionTree getValue();
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/MatchesTree.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+/**
+ * A tree node for an {@code matches} expression.
+ *
+ * For example:
+ * <pre>
+ *   <em>expression</em> matches <em>pattern</em>
+ * </pre>
+ *
+ */
+public interface MatchesTree extends ExpressionTree {
+    /**
+     * Returns the expression to be matched.
+     * @return the expression
+     */
+    ExpressionTree getExpression();
+
+    /**
+     * Returns the pattern to match against.
+     * @return the pattern
+     */
+    Tree getPattern();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+import javax.lang.model.element.Name;
+
+/**
+ * A super-type for all the patterns.
+ */
+public interface PatternTree extends Tree {
+
+    /**
+     * A doc to make build happy
+     * @return something
+     */
+    Name getBinding();
+}
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Fri Oct 05 19:50:15 2018 +0200
@@ -179,6 +179,11 @@
         LABELED_STATEMENT(LabeledStatementTree.class),
 
         /**
+         * Used for instances of {@link MatchesTree}.
+         */
+        MATCHES(MatchesTree.class),
+
+        /**
          * Used for instances of {@link MethodTree}.
          */
         METHOD(MethodTree.class),
@@ -220,6 +225,16 @@
         PARENTHESIZED(ParenthesizedTree.class),
 
         /**
+         * Used for instances of {@link BindingPatternTree}.
+         */
+        BINDING_PATTERN(BindingPatternTree.class),
+
+        /**
+         * Used for instances of {@link LiteralPatternTree}.
+         */
+        LITERAL_PATTERN(LiteralPatternTree.class),
+
+        /**
          * Used for instances of {@link PrimitiveTypeTree}.
          */
         PRIMITIVE_TYPE(PrimitiveTypeTree.class),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Fri Oct 05 19:50:15 2018 +0200
@@ -258,6 +258,30 @@
     R visitLiteral(LiteralTree node, P p);
 
     /**
+     * Visits a MatchesTree node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    R visitMatches(MatchesTree node, P p);
+
+    /**
+     * Visits an BindingPattern node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    R visitBindingPattern(BindingPatternTree node, P p);
+
+    /**
+     * Visits a LiteralPattern node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    R visitLiteralPattern(LiteralPatternTree node, P p);
+
+    /**
      * Visits a MethodTree node.
      * @param node the node being visited
      * @param p a parameter value
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Fri Oct 05 19:50:15 2018 +0200
@@ -566,6 +566,42 @@
      * @return  the result of {@code defaultAction}
      */
     @Override
+    public R visitMatches(MatchesTree 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 visitBindingPattern(BindingPatternTree 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 visitLiteralPattern(LiteralPatternTree 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 visitArrayAccess(ArrayAccessTree node, P p) {
         return defaultAction(node, p);
     }
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Oct 05 19:50:15 2018 +0200
@@ -365,7 +365,7 @@
     @Override
     @SuppressWarnings("removal")
     public R visitCase(CaseTree node, P p) {
-        R r = scan(node.getExpressions(), p);
+        R r = scan(node.getPatterns(), p);
         if (node.getCaseKind() == CaseKind.RULE)
             r = scanAndReduce(node.getBody(), p, r);
         else
@@ -689,6 +689,44 @@
      * @return the result of scanning
      */
     @Override
+    public R visitMatches(MatchesTree node, P p) {
+        R r = scan(node.getExpression(), p);
+        r = scanAndReduce(node.getPattern(), p, r);
+        return r;
+    }
+
+    /**
+     * {@inheritDoc} This implementation scans the children in left to right order.
+     *
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    @Override
+    public R visitBindingPattern(BindingPatternTree node, P p) {
+        return scan(node.getType(), p);
+    }
+
+    /**
+     * {@inheritDoc} This implementation scans the children in left to right order.
+     *
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    @Override
+    public R visitLiteralPattern(LiteralPatternTree node, P p) {
+        return scan(node.getValue(), p);
+    }
+
+    /**
+     * {@inheritDoc} This implementation scans the children in left to right order.
+     *
+     * @param node  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return the result of scanning
+     */
+    @Override
     public R visitArrayAccess(ArrayAccessTree node, P p) {
         R r = scan(node.getExpression(), p);
         r = scanAndReduce(node.getIndex(), p, r);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Fri Oct 05 19:50:15 2018 +0200
@@ -319,6 +319,11 @@
      */
     public static final long BODY_ONLY_FINALIZE = 1L<<17; //blocks only
 
+    /**
+     * Flag to indicate the given variable is a match binding variable.
+     */
+    public static final long MATCH_BINDING = 1L<<58;
+
     /** Modifier masks.
      */
     public static final int
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Oct 05 19:50:15 2018 +0200
@@ -49,6 +49,7 @@
 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
 import com.sun.tools.javac.jvm.*;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@@ -58,6 +59,7 @@
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.JCLiteralPattern.LiteralPatternKind;
 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -74,6 +76,7 @@
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
+import com.sun.tools.javac.tree.JCTree.GenericSwitch.SwitchKind;
 import com.sun.tools.javac.comp.Analyzer.AnalyzerMode;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
@@ -293,6 +296,8 @@
                isAssignableAsBlankFinal(v, env)))) {
             if (v.isResourceVariable()) { //TWR resource
                 log.error(pos, Errors.TryResourceMayNotBeAssigned(v));
+            } else if ((v.flags() & MATCH_BINDING) != 0) {
+                log.error(pos, Errors.PatternBindingMayNotBeAssigned(v));
             } else {
                 log.error(pos, Errors.CantAssignValToFinalVar(v));
             }
@@ -1320,7 +1325,13 @@
 
     public void visitWhileLoop(JCWhileLoop tree) {
         attribExpr(tree.cond, env, syms.booleanType);
-        attribStat(tree.body, env.dup(tree));
+        // include x.T in while's body
+        Env<AttrContext> whileEnv = bindingEnv(env, getMatchBindings(types, log, tree.cond, true));
+        try {
+            attribStat(tree.body, whileEnv.dup(tree));
+        } finally {
+            whileEnv.info.scope.leave();
+        }
         result = null;
     }
 
@@ -1329,14 +1340,24 @@
             env.dup(env.tree, env.info.dup(env.info.scope.dup()));
         try {
             attribStats(tree.init, loopEnv);
-            if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
-            loopEnv.tree = tree; // before, we were not in loop!
-            attribStats(tree.step, loopEnv);
-            attribStat(tree.body, loopEnv);
+            List<BindingSymbol> matchBindings = List.nil();
+            if (tree.cond != null) {
+                attribExpr(tree.cond, loopEnv, syms.booleanType);
+                // include x.T in the evaluation scopes of body & step.
+                matchBindings = getMatchBindings(types, log, tree.cond, true);
+            }
+            Env<AttrContext> bodyEnv = bindingEnv(loopEnv, matchBindings);
+            try {
+                bodyEnv.tree = tree; // before, we were not in loop!
+                attribStats(tree.step, bodyEnv);
+                attribStat(tree.body, bodyEnv);
+            } finally {
+                bodyEnv.info.scope.leave();
+            }
             result = null;
         }
         finally {
-            loopEnv.info.scope.leave();
+            loopEnv.info.scope.leave(); // all injected match bindings vanish here.
         }
     }
 
@@ -1398,7 +1419,7 @@
     }
 
     public void visitSwitch(JCSwitch tree) {
-        handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
+        handleSwitch(tree, tree.selector, tree.cases, (t, k) -> ((JCSwitch) t).kind = k, (c, caseEnv) -> {
             attribStats(c.stats, caseEnv);
         });
         result = null;
@@ -1422,7 +1443,7 @@
         ListBuffer<DiagnosticPosition> caseTypePositions = new ListBuffer<>();
         ListBuffer<Type> caseTypes = new ListBuffer<>();
 
-        handleSwitch(tree, tree.selector, tree.cases, (c, caseEnv) -> {
+        handleSwitch(tree, tree.selector, tree.cases, (t, k) -> ((JCSwitchExpression) t).kind = k, (c, caseEnv) -> {
             caseEnv.info.breakResult = condInfo;
             attribStats(c.stats, caseEnv);
             new TreeScanner() {
@@ -1465,6 +1486,7 @@
     private void handleSwitch(JCTree switchTree,
                               JCExpression selector,
                               List<JCCase> cases,
+                              BiConsumer<JCTree, SwitchKind> kindSetter,
                               BiConsumer<JCCase, Env<AttrContext>> attribCase) {
         Type seltype = attribExpr(selector, env);
 
@@ -1472,15 +1494,31 @@
             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)
+            boolean hasPatternCases = cases.stream()
+                                           .flatMap(c -> c.pats.stream())
+                                           .anyMatch(pat -> pat.constExpression() == null); //XXX: null handling???
+            SwitchKind kind;
+            if (hasPatternCases) {
+                //TODO: check source level
+                kind = SwitchKind.MATCHING;
+            } else if ((seltype.tsym.flags() & Flags.ENUM) != 0) {
+                kind = SwitchKind.ENUM;
+            } else if (types.isSameType(seltype, syms.stringType)) {
+                kind = SwitchKind.STRING;
+            } else if (!types.isAssignable(seltype, syms.intType) &&
+                       !types.isSameType(seltype, syms.voidType)) {
+                //TODO: check source level
+                kind = SwitchKind.MATCHING;
+            } else {
                 seltype = chk.checkType(selector.pos(), seltype, syms.intType);
-
+                kind = SwitchKind.ORDINARY;
+            }
+            kindSetter.accept(switchTree, kind);
             // 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?
+            List<BindingSymbol> prevBindings = null;
             @SuppressWarnings("removal")
             CaseKind caseKind = null;
             boolean wasError = false;
@@ -1493,43 +1531,73 @@
                               Errors.SwitchMixingCaseTypes);
                     wasError = true;
                 }
-                if (c.getExpressions().nonEmpty()) {
-                    for (JCExpression pat : c.getExpressions()) {
+                List<BindingSymbol> matchBindings = prevBindings;
+                if (c.getPatterns().nonEmpty()) {
+                    for (JCPattern pat : c.getPatterns()) {
                         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())) {
+                            continue;
+                        }
+                        switch (kind) {
+                            case MATCHING:
+                                ResultInfo castInfo = unknownExprInfo;
+                                if (pat.getTag() == BINDINGPATTERN) {
+                                    JCBindingPattern bindingPattern = (JCBindingPattern) pat;
+                                    if (bindingPattern.vartype == null)
+                                        castInfo = castInfo(seltype);
+                                }
+                                Type patType = attribTree(pat, switchEnv, castInfo);
+                                chk.checkCastable(selector.pos(), seltype, patType);
+                                if (pat.getTag() == LITERALPATTERN && !labels.add(patType.constValue())) {
                                     log.error(c.pos(), Errors.DuplicateCaseLabel);
                                 }
-                            }
+                                break;
+                            case ENUM:
+                                Symbol sym = enumConstant(pat.constExpression(), seltype);
+                                if (sym == null) {
+                                    log.error(pat.constExpression().pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
+                                } else if (!labels.add(sym)) {
+                                    log.error(c.pos(), Errors.DuplicateCaseLabel);
+                                }
+                                break;
+                            default:
+                                Type pattype = attribExpr(pat.constExpression(), switchEnv, seltype);
+                                if (!pattype.hasTag(ERROR)) {
+                                    if (pattype.constValue() == null) {
+                                        log.error(pat.constExpression().pos(),
+                                                  (kind == SwitchKind.STRING ? Errors.StringConstReq
+                                                                                  : Errors.ConstExprReq));
+                                    } else if (!labels.add(pattype.constValue())) {
+                                        log.error(c.pos(), Errors.DuplicateCaseLabel);
+                                    }
+                                }
+                                break;
                         }
+                        matchBindings = getMatchBindings(types, log, pat, true, matchBindings);
                     }
-                } else if (hasDefault) {
-                    log.error(c.pos(), Errors.DuplicateDefaultLabel);
                 } else {
-                    hasDefault = true;
+                    if (hasDefault) {
+                        log.error(c.pos(), Errors.DuplicateDefaultLabel);
+                    } else {
+                        hasDefault = true;
+                    }
+                    matchBindings = getMatchBindings(types, log, null, true, matchBindings);
                 }
-                Env<AttrContext> caseEnv =
-                    switchEnv.dup(c, env.info.dup(switchEnv.info.scope.dup()));
+
+                Env<AttrContext> caseEnv = bindingEnv(switchEnv, matchBindings);
+
+                caseEnv.tree = c;
+
                 try {
                     attribCase.accept(c, caseEnv);
                 } finally {
                     caseEnv.info.scope.leave();
                     addVars(c.stats, switchEnv.info.scope);
                 }
+
+                flow.aliveAfterCase(caseEnv, c, make);
+                prevBindings = c.completesNormally ? matchBindings : null;
             }
         } finally {
             switchEnv.info.scope.leave();
@@ -1688,8 +1756,26 @@
                 unknownExprInfo :
                 resultInfo.dup(conditionalContext(resultInfo.checkContext));
 
-        Type truetype = attribTree(tree.truepart, env, condInfo);
-        Type falsetype = attribTree(tree.falsepart, env, condInfo);
+        /*  if e = "x ? y : z", then:
+                include x.T in y
+                include x.F in z
+        */
+
+        Type truetype;
+        Env<AttrContext> trueEnv = bindingEnv(env, getMatchBindings(types, log, tree.cond, true));
+        try {
+            truetype = attribTree(tree.truepart, trueEnv, condInfo);
+        } finally {
+            trueEnv.info.scope.leave();
+        }
+
+        Type falsetype;
+        Env<AttrContext> falseEnv = bindingEnv(env, getMatchBindings(types, log, tree.cond, false));
+        try {
+            falsetype = attribTree(tree.falsepart, falseEnv, condInfo);
+        } finally {
+            falseEnv.info.scope.leave();
+        }
 
         Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
                 condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
@@ -1847,11 +1933,32 @@
         BOOLEAN,
     };
 
+    Env<AttrContext> bindingEnv(Env<AttrContext> env, List<BindingSymbol> bindings) {
+        Env<AttrContext> env1 = env.dup(env.tree, env.info.dup(env.info.scope.dup()));
+        bindings.forEach(env1.info.scope::enter);
+        return env1;
+    }
+
     public void visitIf(JCIf tree) {
         attribExpr(tree.cond, env, syms.booleanType);
-        attribStat(tree.thenpart, env);
-        if (tree.elsepart != null)
-            attribStat(tree.elsepart, env);
+
+        // if (x) { y } [ else z ] include x.T in y; include x.F in z
+
+        Env<AttrContext> thenEnv = bindingEnv(env, getMatchBindings(types, log, tree.cond, true));
+        try {
+            attribStat(tree.thenpart, thenEnv);
+        } finally {
+            thenEnv.info.scope.leave();
+        }
+
+        if (tree.elsepart != null) {
+            Env<AttrContext> elseEnv = bindingEnv(env, getMatchBindings(types, log, tree.cond, false));
+            try {
+                attribStat(tree.elsepart, elseEnv);
+            } finally {
+                elseEnv.info.scope.leave();
+            }
+        }
         chk.checkEmptyIf(tree);
         result = null;
     }
@@ -3576,7 +3683,27 @@
     public void visitBinary(JCBinary tree) {
         // Attribute arguments.
         Type left = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.lhs, env));
-        Type right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, env));
+        // If e = "x && y", then, include x.T in y;  If e = "x || y", then, include x.F in y
+        List<BindingSymbol> matchBindings;
+        switch (tree.getTag()) {
+            case AND:
+                matchBindings = getMatchBindings(types, log, tree.lhs, true);
+                break;
+            case OR:
+                matchBindings = getMatchBindings(types, log, tree.lhs, false);
+                break;
+            default:
+                matchBindings = List.nil();
+                break;
+        }
+        Env<AttrContext> rhsEnv = bindingEnv(env, matchBindings);
+        Type right;
+        try {
+            right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, rhsEnv));
+        } finally {
+            rhsEnv.info.scope.leave();
+        }
+
         // Find operator.
         Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
         Type owntype = types.createErrorType(tree.type);
@@ -3619,13 +3746,7 @@
         boolean isPoly = allowPoly && (expr.hasTag(LAMBDA) || expr.hasTag(REFERENCE));
         if (isPoly) {
             //expression is a poly - we need to propagate target type info
-            castInfo = new ResultInfo(KindSelector.VAL, clazztype,
-                                      new Check.NestedCheckContext(resultInfo.checkContext) {
-                @Override
-                public boolean compatible(Type found, Type req, Warner warn) {
-                    return types.isCastable(found, req, warn);
-                }
-            });
+            castInfo = castInfo(clazztype);
         } else {
             //standalone cast - target-type info is not propagated
             castInfo = unknownExprInfo;
@@ -3655,6 +3776,75 @@
         result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo);
     }
 
+    public void visitPatternTest(JCMatches tree) {
+        Type exprtype = attribExpr(tree.expr, env); //no target type
+        ResultInfo castInfo = unknownExprInfo;
+        if (tree.pattern.getTag() == BINDINGPATTERN) {
+            JCBindingPattern bindingPattern = (JCBindingPattern) tree.pattern;
+            if (bindingPattern.vartype == null)
+                castInfo = castInfo(exprtype);
+        }
+        attribTree(tree.pattern, env, castInfo);
+        chk.checkCastable(tree.expr.pos(), exprtype, tree.pattern.type);
+        result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo);
+    }
+
+    ResultInfo castInfo(Type target) {
+        return target.isErroneous() ?
+                unknownExprInfo :
+                new ResultInfo(KindSelector.VAL, target,
+                        new Check.NestedCheckContext(resultInfo.checkContext) {
+                            @Override
+                            public boolean compatible(Type found, Type req, Warner warn) {
+                                return types.isCastable(found, req, warn);
+                            }
+                        });
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        if (tree.vartype != null) {
+            ResultInfo varInfo = new ResultInfo(KindSelector.TYP, resultInfo.pt, resultInfo.checkContext);
+            tree.type = attribTree(tree.vartype, env, varInfo);
+        } else {
+            tree.type = resultInfo.pt;
+        }
+        VarSymbol v = tree.symbol = new BindingSymbol(tree.name, tree.vartype != null ? tree.vartype.type : (tree.type.hasTag(BOT) ? syms.objectType : tree.type), env.info.scope.owner);
+        if (chk.checkUnique(tree.pos(), v, env.info.scope)) {
+            chk.checkTransparentVar(tree.pos(), v, env.info.scope);
+            // env.info.scope.enter(v); // we inject into scopes expressly at various points.
+        }
+        result = tree.type;
+    }
+
+    public void visitLiteralPattern(JCLiteralPattern tree) {
+        Type patType = attribTree(tree.value, env, resultInfo);
+
+        if (tree.value.hasTag(IDENT)) {
+            // Pattern is an identifier
+            JCIdent ident = (JCIdent)tree.value;
+            if (ident.sym.kind==TYP) {
+                tree.patternKind = LiteralPatternKind.TYPE;
+            } else {
+                tree.patternKind = LiteralPatternKind.CONSTANTEXPRESSIONORNULL;
+            }
+        } else if (tree.value.hasTag(SELECT)) {
+            // Pattern is a compound name
+            JCFieldAccess ident = (JCFieldAccess)tree.value;
+            if (ident.sym.kind==TYP) {
+                tree.patternKind = LiteralPatternKind.TYPE;
+            } else {
+                tree.patternKind = LiteralPatternKind.CONSTANTEXPRESSIONORNULL;
+            }
+        } else {
+            // Pattern must be null literal or a constant expression
+            tree.patternKind = LiteralPatternKind.CONSTANTEXPRESSIONORNULL;
+            if (!patType.isErroneous() && !patType.hasTag(BOT) && patType.constValue() == null) {
+                log.error(tree.pos(), Errors.ConstExprReq);
+            }
+        }
+        tree.type = patType;
+    }
+
     public void visitIndexed(JCArrayAccess tree) {
         Type owntype = types.createErrorType(tree.type);
         Type atype = attribExpr(tree.indexed, env);
@@ -5307,6 +5497,16 @@
         }
 
         @Override
+        public void visitBindingPattern(JCBindingPattern that) {
+            //initTypeIfNeeded(that);
+            if (that.symbol == null) {
+                that.symbol = new BindingSymbol(that.name, that.type, syms.noSymbol);
+                that.symbol.adr = 0;
+            }
+            super.visitBindingPattern(that);
+        }
+
+        @Override
         public void visitNewClass(JCNewClass that) {
             if (that.constructor == null) {
                 that.constructor = new MethodSymbol(0, names.init,
@@ -5373,4 +5573,12 @@
         }.scan(pid);
     }
 
+
+    public static List<BindingSymbol> getMatchBindings(Types types, Log log, JCTree expression, boolean whenTrue) {
+        return getMatchBindings(types, log, expression, whenTrue, null);
+    }
+
+    public static List<BindingSymbol> getMatchBindings(Types types, Log log, JCTree expression, boolean whenTrue, List<BindingSymbol> intersectWith) {
+        return new MatchBindingsComputer(types, log, expression, whenTrue).getBindings(intersectWith);
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java	Fri Oct 05 19:50:15 2018 +0200
@@ -60,8 +60,10 @@
         FLOW(5),
         TRANSTYPES(6),
         UNLAMBDA(7),
-        LOWER(8),
-        GENERATE(9);
+        TRANSSWITCHES(8),
+        TRANSPATTERNS(9),
+        LOWER(10),
+        GENERATE(11);
 
         CompileState(int value) {
             this.value = value;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Oct 05 19:50:15 2018 +0200
@@ -45,6 +45,7 @@
 
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.GenericSwitch.SwitchKind;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Flags.BLOCK;
@@ -255,6 +256,23 @@
         }
     }
 
+    public void aliveAfterCase(Env<AttrContext> env, JCCase that, TreeMaker make) {
+        //we need to disable diagnostics temporarily; the problem is that if
+        //a lambda expression contains e.g. an unreachable statement, an error
+        //message will be reported and will cause compilation to skip the flow analyis
+        //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
+        //related errors, which will allow for more errors to be detected
+        Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
+        try {
+            CaseAliveAnalyzer analyzer = new CaseAliveAnalyzer();
+
+            analyzer.analyzeTree(env, that.stats, make);
+            that.completesNormally = analyzer.isAlive();
+        } finally {
+            log.popDiagnosticHandler(diagHandler);
+        }
+    }
+
     /**
      * Definite assignment scan mode
      */
@@ -517,7 +535,7 @@
                 while (exits.nonEmpty()) {
                     PendingExit exit = exits.head;
                     exits = exits.tail;
-                    Assert.check(exit.tree.hasTag(RETURN));
+                    Assert.check(exit.tree.hasTag(RETURN), () -> exit.tree.toString());
                 }
             } finally {
                 lint = lintPrev;
@@ -597,39 +615,137 @@
         }
 
         public void visitSwitch(JCSwitch tree) {
-            ListBuffer<PendingExit> prevPendingExits = pendingExits;
-            pendingExits = new ListBuffer<>();
-            scan(tree.selector);
-            boolean hasDefault = false;
-            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 (tree.kind == SwitchKind.MATCHING) {
+                visitMatchingSwitch(tree);
+            } else {
+                visitLegacySwitch(tree);
+            }
+        }
+            // where
+            private void visitMatchingSwitch(JCSwitch tree) {
+                ListBuffer<PendingExit> prevPendingExits = pendingExits;
+                pendingExits = new ListBuffer<>();
+                scan(tree.selector);
+                boolean aliveInAnyArm = false;
+                boolean hasDefault = false;
+                for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+                    JCCase c = l.head;
+                    alive = true;
+                    if (c.pats.nonEmpty()) {
+                        for (JCPattern pat : c.pats) {
+                            if (patternDominated(tree.cases, pat, tree.selector.type)) {
+                                log.error(c, Errors.PatternDominated);
+                            }
+                            scan(pat);
+                        }
+                    } else {
+                        if (patternDominated(tree.cases, null, tree.selector.type)) {
+                            log.error(c, Errors.UnreachableStmt);
+                        }
+                        hasDefault = true;
                     }
+                    scanStats(c.stats);
+                    aliveInAnyArm |= alive;
                 }
-                scanStats(c.stats);
-                c.completesNormally = alive;
-                if (alive && c.caseKind == JCCase.RULE) {
-                    scanSyntheticBreak(make, tree);
-                    alive = false;
+                alive = aliveInAnyArm || !hasDefault;
+                alive |= resolveBreaks(tree, prevPendingExits);
+            }
+            //where:
+                private boolean patternDominated(List<JCCase> clauses, JCPattern givenPattern, Type selectorType) {
+                    // TODO: This needs to evolve as we add more support for other pattern kinds.
+                    boolean assignableCaseFound = false;
+                    OUTTER: for (List<JCCase> l = clauses; l.nonEmpty(); l = l.tail) {
+                        JCCase c = l.head;
+                        if (c.pats.isEmpty()) {
+                            if (givenPattern == null) {
+                                break ;
+                            } else {
+                                // default clause must be the last
+                                return l.nonEmpty();
+                            }
+                        }
+                        for (JCPattern pat : c.pats) {
+                            if (pat == givenPattern) {
+                                break OUTTER;
+                            }
+                            switch (pat.getTag()) {
+                                case BINDINGPATTERN: {
+                                    JCBindingPattern vpatt = (JCBindingPattern)pat;
+                                    if (vpatt.vartype == null) {
+                                        assignableCaseFound = true;
+                                        if (givenPattern != null)
+                                            return true;
+                                    } else {
+                                        if (types.isAssignable(selectorType, vpatt.type))
+                                            assignableCaseFound = true;
+                                        if (givenPattern != null) {
+                                            switch (givenPattern.getTag()) {
+                                                case BINDINGPATTERN:
+                                                    JCBindingPattern currentPattern = (JCBindingPattern)givenPattern;
+                                                    if (currentPattern.vartype != null) {
+                                                        if (types.isAssignable(types.erasure(currentPattern.vartype.type), types.erasure(vpatt.type)))
+                                                            return true;
+                                                    }
+                                                    break;
+                                                case LITERALPATTERN:
+                                                    JCLiteralPattern literalPattern = (JCLiteralPattern) givenPattern;
+                                                    if (literalPattern.type.constValue()==null) {
+                                                        return false; // null pattern is not dominated by a type test pattern
+                                                    } else if (types.isAssignable(literalPattern.type, vpatt.type)) {
+                                                        return true;
+                                                    }
+                                                    break;
+                                            }
+                                        }
+                                    }
+                                    break;
+                                }
+                                case LITERALPATTERN: {
+                                    break;  // does not dominate any other pattern.
+                                }
+                                default: {
+                                    Assert.check(false);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    return givenPattern != null ? assignableCaseFound : false;
                 }
-                // Warn about fall-through if lint switch fallthrough enabled.
-                if (alive &&
-                    lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
-                    c.stats.nonEmpty() && l.tail.nonEmpty())
-                    log.warning(Lint.LintCategory.FALLTHROUGH,
-                                l.tail.head.pos(),
-                                Warnings.PossibleFallThroughIntoCase);
+            private void visitLegacySwitch(JCSwitch tree) {
+                ListBuffer<PendingExit> prevPendingExits = pendingExits;
+                pendingExits = new ListBuffer<>();
+                scan(tree.selector);
+                boolean hasDefault = false;
+                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 (JCPattern pat : c.pats) {
+                            scan(pat);
+                        }
+                    }
+                    scanStats(c.stats);
+                    if (alive && c.caseKind == JCCase.RULE) {
+                        System.err.println("synthetic break: " + tree);
+                        scanSyntheticBreak(make, tree);
+                        alive = false;
+                    }
+                    // Warn about fall-through if lint switch fallthrough enabled.
+                    if (alive &&
+                        lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
+                        c.stats.nonEmpty() && l.tail.nonEmpty())
+                        log.warning(Lint.LintCategory.FALLTHROUGH,
+                                    l.tail.head.pos(),
+                                    Warnings.PossibleFallThroughIntoCase);
+                }
+                if (!hasDefault) {
+                    alive = true;
+                }
+                alive |= resolveBreaks(tree, prevPendingExits);
             }
-            if (!hasDefault) {
-                alive = true;
-            }
-            alive |= resolveBreaks(tree, prevPendingExits);
-        }
 
         @Override
         public void visitSwitchExpression(JCSwitchExpression tree) {
@@ -651,18 +767,18 @@
                 if (c.pats.isEmpty())
                     hasDefault = true;
                 else {
-                    for (JCExpression pat : c.pats) {
+                    for (JCPattern 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());
+                        if (constants != null && pat.hasTag(LITERALPATTERN)) {
+                            JCExpression lit = ((JCLiteralPattern) pat).value;
+                            if (lit.hasTag(IDENT))
+                                constants.remove(((JCIdent) lit).name);
+                            if (lit.type != null)
+                                constants.remove(lit.type.constValue());
                         }
                     }
                 }
                 scanStats(c.stats);
-                c.completesNormally = alive;
             }
             if ((constants == null || !constants.isEmpty()) && !hasDefault) {
                 log.error(tree, Errors.NotExhaustive);
@@ -803,12 +919,15 @@
             analyzeTree(env, env.tree, make);
         }
         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
+            analyzeTree(env, List.of(tree), make);
+        }
+        public void analyzeTree(Env<AttrContext> env, List<? extends JCTree> trees, TreeMaker make) {
             try {
                 attrEnv = env;
                 Flow.this.make = make;
                 pendingExits = new ListBuffer<>();
                 alive = true;
-                scan(tree);
+                scan(trees);
             } finally {
                 pendingExits = null;
                 Flow.this.make = null;
@@ -1425,6 +1544,19 @@
     }
 
     /**
+     * TODO
+     */
+    class CaseAliveAnalyzer extends AliveAnalyzer {
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            //skip
+        }
+        public boolean isAlive() {
+            return super.alive;
+        }
+    }
+
+    /**
      * Specialized pass that performs DA/DU on a lambda
      */
     class LambdaAssignAnalyzer extends AssignAnalyzer {
@@ -1621,7 +1753,7 @@
          */
         protected boolean trackable(VarSymbol sym) {
             return
-                sym.pos >= startPos &&
+                sym.pos >= startPos && ((sym.flags() & MATCH_BINDING) == 0) &&
                 ((sym.owner.kind == MTH ||
                 isFinalUninitializedField(sym)));
         }
@@ -2194,7 +2326,7 @@
                 if (c.pats.isEmpty()) {
                     hasDefault = true;
                 } else {
-                    for (JCExpression pat : c.pats) {
+                    for (JCPattern pat : c.pats) {
                         scanExpr(pat);
                     }
                 }
@@ -2555,6 +2687,11 @@
             // Do nothing for modules
         }
 
+        // TODO: 2017-02-02 JUST TO ALLOW THINGS TO CONTINUE
+        public void visitTypeTestPattern(JCBindingPattern tree) {
+            // Do nothing
+        }
+
     /**************************************************************************
      * main method
      *************************************************************************/
@@ -2755,6 +2892,11 @@
             // Do nothing for modules
         }
 
+        // TODO: 2017-02-02 JUST TO ALLOW THINGS TO CONTINUE
+        public void visitTypeTestPattern(JCBindingPattern tree) {
+            // Do nothing
+        }
+
     /**************************************************************************
      * main method
      *************************************************************************/
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Oct 05 19:50:15 2018 +0200
@@ -70,6 +70,7 @@
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import com.sun.tools.javac.tree.JCTree.GenericSwitch.SwitchKind;
 import static com.sun.tools.javac.jvm.Pool.DynamicMethod;
 
 import javax.lang.model.element.ElementKind;
@@ -718,9 +719,10 @@
             JCBreak br = make.Break(null);
             breaks.add(br);
             List<JCStatement> stmts = entry.getValue().append(br).toList();
-            cases.add(make.Case(JCCase.STATEMENT, List.of(make.Literal(entry.getKey())), stmts, null));
+            cases.add(make.Case(JCCase.STATEMENT, List.of(make.LiteralPattern(make.Literal(entry.getKey()))), stmts, null));
         }
         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
+        sw.kind = SwitchKind.STRING;
         for (JCBreak br : breaks) {
             br.target = sw;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Oct 05 19:50:15 2018 +0200
@@ -56,15 +56,17 @@
 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
 import static com.sun.tools.javac.code.TypeTag.*;
 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 com.sun.tools.javac.tree.JCTree.GenericSwitch.SwitchKind;
+import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
+
 /** This pass translates away some syntactic sugar: inner classes,
  *  class literals, assertions, foreach loops, etc.
  *
@@ -3358,60 +3360,23 @@
     }
 
     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;
-            }
+        Type target;
+        switch (tree.kind) {
+            case ENUM: target = tree.selector.type; break;
+            case STRING: target = syms.stringType; break;
+            case ORDINARY: target = syms.intType; break;
+            default:
+                Assert.error("Should not get here, kind: " + tree.kind);
+                throw new InternalError();
         }
-
-        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;
-        boolean stringSwitch = selsuper != null &&
-            types.isSameType(tree.selector.type, syms.stringType);
-        Type target = enumSwitch ? tree.selector.type :
-            (stringSwitch? syms.stringType : syms.intType);
         tree.selector = translate(tree.selector, target);
         tree.cases = translateCases(tree.cases);
-        if (enumSwitch) {
-            result = visitEnumSwitch(tree);
-        } else if (stringSwitch) {
-            result = visitStringSwitch(tree);
-        } else {
-            result = tree;
+        switch (tree.kind) {
+            case ENUM: result = visitEnumSwitch(tree); break;
+            case STRING: result = visitStringSwitch(tree); break;
+            case ORDINARY: result = tree; break;
+            default:
+                Assert.error("Should not get here, kind: " + tree.kind);
         }
     }
 
@@ -3429,14 +3394,16 @@
         ListBuffer<JCCase> cases = new ListBuffer<>();
         for (JCCase c : tree.cases) {
             if (c.pats.nonEmpty()) {
-                VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
-                JCLiteral pat = map.forConstant(label);
+                VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head.constExpression());
+                JCLiteral value = map.forConstant(label);
+                JCPattern pat = make.LiteralPattern(value);
                 cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
             } else {
                 cases.append(c);
             }
         }
         JCSwitch enumSwitch = make.Switch(selector, cases.toList());
+        enumSwitch.kind = SwitchKind.ORDINARY;
         patchTargets(enumSwitch, tree, enumSwitch);
         return enumSwitch;
     }
@@ -3502,7 +3469,7 @@
 
             for(JCCase oneCase : caseList) {
                 if (oneCase.pats.nonEmpty()) { // pats is empty for a "default" case
-                    JCExpression expression = oneCase.pats.head;
+                    JCExpression expression = oneCase.pats.head.constExpression();
                     String labelExpr = (String) expression.type.constValue();
                     Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
                     Assert.checkNull(mapping);
@@ -3564,6 +3531,7 @@
                                                        List.nil()).setType(syms.intType);
             JCSwitch switch1 = make.Switch(hashCodeCall,
                                         caseBuffer.toList());
+            switch1.kind = SwitchKind.ORDINARY;
             for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
                 int hashCode = entry.getKey();
                 Set<String> stringsWithHashCode = entry.getValue();
@@ -3586,7 +3554,7 @@
                 breakStmt.target = switch1;
                 lb.append(elsepart).append(breakStmt);
 
-                caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
+                caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.LiteralPattern(make.Literal(hashCode))), lb.toList(), null));
             }
 
             switch1.cases = caseBuffer.toList();
@@ -3598,6 +3566,7 @@
 
             ListBuffer<JCCase> lb = new ListBuffer<>();
             JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
+            switch2.kind = SwitchKind.ORDINARY;
             for(JCCase oneCase : caseList ) {
                 // Rewire up old unlabeled break statements to the
                 // replacement switch being created.
@@ -3608,11 +3577,11 @@
                 if (isDefault)
                     caseExpr = null;
                 else {
-                    caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
+                    caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head.constExpression()).
                                                                     type.constValue()));
                 }
 
-                lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
+                lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(make.LiteralPattern(caseExpr)),
                                     oneCase.getStatements(), null));
             }
 
@@ -3625,73 +3594,8 @@
 
     @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);
+        Assert.error("Shuld not get here!");
     }
-        //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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCLiteralPattern;
+import com.sun.tools.javac.tree.JCTree.JCUnary;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+
+
+public class MatchBindingsComputer extends TreeScanner {
+
+    private final JCTree tree;
+    private final Log log;
+    private final Types types;
+    boolean whenTrue;
+    List<BindingSymbol> bindings;
+
+    public MatchBindingsComputer(Types types, Log log, JCTree tree, boolean whenTrue) {
+        this.tree = tree;
+        this.whenTrue = whenTrue;
+        this.log = log;
+        this.types = types;
+    }
+
+    @Override
+    public void visitBindingPattern(JCBindingPattern tree) {
+        bindings = whenTrue ? List.of(tree.symbol) : List.nil();
+    }
+
+    @Override
+    public void visitLiteralPattern(JCLiteralPattern tree) {
+        //noop
+    }
+
+    @Override
+    public void visitBinary(JCBinary tree) {
+        switch (tree.getTag()) {
+            case AND:
+                // e.T = union(x.T, y.T)
+                // e.F = intersection(x.F, y.F)
+                scan(tree.lhs);
+                List<BindingSymbol> lhsBindings = bindings;
+                scan(tree.rhs);
+                List<BindingSymbol> rhsBindings = bindings;
+                bindings = whenTrue ? union(tree, lhsBindings, rhsBindings) : intersection(tree, lhsBindings, rhsBindings);
+                break;
+            case OR:
+                // e.T = intersection(x.T, y.T)
+                // e.F = union(x.F, y.F)
+                scan(tree.lhs);
+                lhsBindings = bindings;
+                scan(tree.rhs);
+                rhsBindings = bindings;
+                bindings = whenTrue ? intersection(tree, lhsBindings, rhsBindings) : union(tree, lhsBindings, rhsBindings);
+                break;
+            default:
+                super.visitBinary(tree);
+                break;
+        }
+    }
+
+    @Override
+    public void visitUnary(JCUnary tree) {
+        switch (tree.getTag()) {
+            case NOT:
+                // e.T = x.F  // flip 'em
+                // e.F = x.T
+                whenTrue = !whenTrue;
+                scan(tree.arg);
+                whenTrue = !whenTrue;
+                break;
+            default:
+                super.visitUnary(tree);
+                break;
+        }
+    }
+
+    @Override
+    public void visitConditional(JCConditional tree) {
+        /* if e = "x ? y : z", then:
+               e.T = union(intersect(y.T, z.T), intersect(x.T, z.T), intersect(x.F, y.T))
+               e.F = union(intersect(y.F, z.F), intersect(x.T, z.F), intersect(x.F, y.F))
+        */
+        if (whenTrue) {
+            List<BindingSymbol> xT, yT, zT, xF;
+            scan(tree.cond);
+            xT = bindings;
+            scan(tree.truepart);
+            yT = bindings;
+            scan(tree.falsepart);
+            zT = bindings;
+            whenTrue = false;
+            scan(tree.cond);
+            xF = bindings;
+            whenTrue = true;
+            bindings = union(tree, intersection(tree, yT, zT), intersection(tree, xT, zT), intersection(tree, xF, yT));
+        } else {
+            List<BindingSymbol> xF, yF, zF, xT;
+            scan(tree.cond);
+            xF = bindings;
+            scan(tree.truepart);
+            yF = bindings;
+            scan(tree.falsepart);
+            zF = bindings;
+            whenTrue = true;
+            scan(tree.cond);
+            xT = bindings;
+            whenTrue = false;
+            bindings = union(tree, intersection(tree, yF, zF), intersection(tree, xT, zF), intersection(tree, xF, yF));
+        }
+    }
+
+    private List<BindingSymbol> intersection(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> rhsBindings) {
+        // It is an error if, for intersection(a,b), if a and b contain the same variable name but with different types.
+        List<BindingSymbol> list = List.nil();
+        for (BindingSymbol v1 : lhsBindings) {
+            for (BindingSymbol v2 : rhsBindings) {
+                if (v1.name == v2.name) {
+                    if (types.isSameType(v1.type, v2.type)) {
+                        list = list.append(new IntersectionBindingSymbol(List.of(v1, v2)));
+                    } else {
+                        log.error(tree.pos(), Errors.MatchBindingExistsWithDifferentType);
+                    }
+                }
+            }
+        }
+        return list;
+    }
+
+    @SafeVarargs
+    private final List<BindingSymbol> union(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> ... rhsBindings_s) {
+        // It is an error if for union(a,b), a and b contain the same name (disjoint union).
+        List<BindingSymbol> list = lhsBindings;
+        for (List<BindingSymbol> rhsBindings : rhsBindings_s) {
+            for (BindingSymbol v : rhsBindings) {
+                for (BindingSymbol ov : list) {
+                    if (ov.name == v.name) {
+                        log.error(tree.pos(), Errors.MatchBindingExists);
+                    }
+                }
+                list = list.append(v);
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public void scan(JCTree tree) {
+        bindings = List.nil();
+        super.scan(tree);
+    }
+
+    public List<BindingSymbol> getBindings(List<BindingSymbol> intersectWith) {
+        scan(tree);
+        if (intersectWith != null) {
+            bindings = intersection(tree, intersectWith, bindings);
+        }
+        return bindings;
+    }
+    
+    public static class BindingSymbol extends VarSymbol {
+        
+        public BindingSymbol(Name name, Type type, Symbol owner) {
+            super(Flags.FINAL | Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner);
+        }
+
+        public boolean isAliasFor(BindingSymbol b) {
+            return aliases().containsAll(b.aliases());
+        }
+
+        List<BindingSymbol> aliases() {
+            return List.of(this);
+        }
+    }
+
+    public static class IntersectionBindingSymbol extends BindingSymbol {
+
+        List<BindingSymbol> aliases = List.nil();
+
+        public IntersectionBindingSymbol(List<BindingSymbol> aliases) {
+            super(aliases.head.name, aliases.head.type, aliases.head.owner);
+            this.aliases = aliases.stream()
+                    .flatMap(b -> b.aliases().stream())
+                    .collect(List.collector());
+        }
+
+        @Override
+        List<BindingSymbol> aliases() {
+            return aliases;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.GenericSwitch.SwitchKind;
+import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
+import com.sun.tools.javac.tree.JCTree.JCCase;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCLiteralPattern;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCForLoop;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCIf;
+import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
+import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
+import com.sun.tools.javac.tree.JCTree.JCLiteralPattern.LiteralPatternKind;
+import com.sun.tools.javac.tree.JCTree.JCMatches;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCSwitch;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
+import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeTranslator;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
+import static com.sun.tools.javac.code.TypeTag.BOT;
+import static com.sun.tools.javac.tree.JCTree.Tag.SWITCH;
+
+/**
+ * This pass translates pattern-matching constructs, such as __match and __matches.
+ */
+public class TransPatterns extends TreeTranslator {
+
+    protected static final Context.Key<TransPatterns> transPatternsKey = new Context.Key<>();
+
+    public static TransPatterns instance(Context context) {
+        TransPatterns instance = context.get(transPatternsKey);
+        if (instance == null)
+            instance = new TransPatterns(context);
+        return instance;
+    }
+
+    private Symtab syms;
+    private TreeMaker make;
+    private Types types;
+    private Operators operators;
+    private Log log;
+    private ConstFold constFold;
+    private Names names;
+
+    BindingContext bindingContext = new BindingContext() {
+        @Override
+        VarSymbol getBindingFor(BindingSymbol varSymbol) {
+            return null;
+        }
+
+        @Override
+        JCStatement decorateStatement(JCStatement stat) {
+            return stat;
+        }
+
+        @Override
+        JCExpression decorateExpression(JCExpression expr) {
+            return expr;
+        }
+
+        @Override
+        BindingContext pop() {
+            //do nothing
+            return this;
+        }
+    };
+
+    JCLabeledStatement pendingMatchLabel = null;
+
+    boolean debugTransPatterns;
+
+    private MethodSymbol currentMethodSym = null;
+
+    protected TransPatterns(Context context) {
+        context.put(transPatternsKey, this);
+        syms = Symtab.instance(context);
+        make = TreeMaker.instance(context);
+        types = Types.instance(context);
+        operators = Operators.instance(context);
+        log = Log.instance(context);
+        constFold = ConstFold.instance(context);
+        names = Names.instance(context);
+        debugTransPatterns = Options.instance(context).isSet("debug.patterns");
+    }
+
+    public void visitPatternTest(JCMatches tree) {
+        JCTree pattern = tree.pattern;
+        switch (pattern.getTag()) {
+            case BINDINGPATTERN:{
+                JCBindingPattern patt = (JCBindingPattern)pattern;
+                VarSymbol pattSym = patt.symbol;
+                Type tempType = tree.expr.type.hasTag(BOT) ?
+                        syms.objectType
+                        : tree.expr.type;
+                VarSymbol temp = new VarSymbol(pattSym.flags(),
+                        pattSym.name.append(names.fromString("$temp")),
+                        tempType,
+                        patt.symbol.owner);
+                JCExpression translatedExpr = translate(tree.expr);
+                Type castTargetType = types.boxedTypeOrType(pattSym.erasure(types));
+                if (patt.vartype == null || tree.expr.type.isPrimitive()) {
+                    result = make.Literal(BOOLEAN,1).setType(syms.booleanType);
+                } else {
+                    result = makeTypeTest(make.Ident(temp), make.Type(castTargetType));
+                }
+
+                VarSymbol bindingVar = bindingContext.getBindingFor(patt.symbol);
+                if (bindingVar != null) {
+                    JCAssign fakeInit = (JCAssign)make.at(tree.pos).Assign(
+                            make.Ident(bindingVar), convert(make.Ident(temp), castTargetType)).setType(bindingVar.erasure(types));
+                    result = makeBinary(Tag.AND, (JCExpression)result,
+                            makeBinary(Tag.EQ, fakeInit, convert(make.Ident(temp), castTargetType)));
+                }
+                result = make.at(tree.pos).LetExpr(make.VarDef(temp, translatedExpr), (JCExpression)result).setType(syms.booleanType);
+                break;
+            }
+            case LITERALPATTERN: {
+                JCLiteralPattern patt = (JCLiteralPattern)pattern;
+                if (patt.patternKind == LiteralPatternKind.TYPE) {
+                    result = makeTypeTest(tree.expr, patt.value);
+                } else {
+                    JCExpression ce = ((JCLiteralPattern) pattern).value;
+                    JCExpression lhs = ce.type.hasTag(BOT) ?
+                            tree.expr
+                            : make.TypeCast(make.Type(ce.type), tree.expr).setType(ce.type.baseType());
+                    if (!ce.type.hasTag(BOT) && tree.expr.type.isReference()) {
+                        result = translate(makeBinary(
+                                Tag.AND,
+                                makeTypeTest(tree.expr, make.Type(types.boxedTypeOrType(ce.type))),
+                                makeBinary(JCTree.Tag.EQ, lhs, ce)));
+                    } else {
+                        result = translate(makeBinary(JCTree.Tag.EQ, lhs, ce));
+                    }
+                }
+                break;
+            }
+            default: {
+                Assert.error("Cannot get here");
+            }
+        }
+    }
+
+    @Override
+    public void visitBinary(JCBinary tree) {
+        List<BindingSymbol> matchBindings;
+        switch (tree.getTag()) {
+            case AND:
+                matchBindings = Attr.getMatchBindings(types, log, tree.lhs, true);
+                break;
+            case OR:
+                matchBindings = Attr.getMatchBindings(types, log, tree.lhs, false);
+                break;
+            default:
+                matchBindings = List.nil();
+                break;
+        }
+
+        bindingContext = new BasicBindingContext(matchBindings);
+        try {
+            super.visitBinary(tree);
+            result = bindingContext.decorateExpression(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitBreak(JCBreak tree) {
+        if (tree.target.hasTag(SWITCH) && ((JCSwitch) tree.target).kind == SwitchKind.MATCHING) {
+            Assert.checkNonNull(pendingMatchLabel);
+            tree.target = pendingMatchLabel;
+            result = tree;
+        } else {
+            super.visitBreak(tree);
+        }
+    }
+
+    @Override
+    public void visitConditional(JCConditional tree) {
+        bindingContext = new BasicBindingContext(
+                Attr.getMatchBindings(types, log, tree.cond, true)
+                        .appendList(Attr.getMatchBindings(types, log, tree.cond, false)));
+        try {
+            super.visitConditional(tree);
+            result = bindingContext.decorateExpression(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitIf(JCIf tree) {
+        bindingContext = new BasicBindingContext(
+                Attr.getMatchBindings(types, log, tree.cond, true)
+                        .appendList(Attr.getMatchBindings(types, log, tree.cond, false)));
+        try {
+            super.visitIf(tree);
+            result = bindingContext.decorateStatement(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitForLoop(JCForLoop tree) {
+        bindingContext = new BasicBindingContext(Attr.getMatchBindings(types, log, tree.cond, true));
+        try {
+            super.visitForLoop(tree);
+            result = bindingContext.decorateStatement(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitWhileLoop(JCWhileLoop tree) {
+        bindingContext = new BasicBindingContext(Attr.getMatchBindings(types, log, tree.cond, true));
+        try {
+            super.visitWhileLoop(tree);
+            result = bindingContext.decorateStatement(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitSwitch(JCSwitch tree) {
+        if (tree.kind == SwitchKind.MATCHING) {
+            JCLabeledStatement prevMatchLabel = pendingMatchLabel;
+            try {
+                pendingMatchLabel = make.Labelled(names.fromString("match$" + tree.pos), null);
+                VarSymbol fallthroughSym = new VarSymbol(0, names.fromString("fallthrough$" + tree.pos), syms.booleanType, currentMethodSym);
+
+                JCStatement fallthroughInit = make.at(tree.pos).VarDef(fallthroughSym, make.Literal(BOOLEAN, 0).setType(syms.booleanType));
+
+                List<JCStatement> resultStatements = List.of(fallthroughInit);
+
+                for (JCCase clause : tree.cases) {
+                    Assert.check(clause.pats.size() <= 1);
+                    final JCExpression jcMatches = clause.pats.nonEmpty() ? make.PatternTest(tree.selector, clause.pats.head) : make.Literal(BOOLEAN, 1);
+                    jcMatches.setType(syms.booleanType);
+                    JCStatement body;
+                    List<JCStatement> stats = clause.stats;
+                    if (clause.completesNormally) {
+                        stats = stats.append(make.at(tree.pos).Exec(make.Assign(make.Ident(fallthroughSym), make.Literal(BOOLEAN, 1).setType(syms.booleanType)).setType(syms.booleanType)));
+                    }
+                    body = make.Block(0, stats);
+                    JCStatement translatedIf = translate(make.If(jcMatches, body, null));
+                    JCIf testStatement = translatedIf.hasTag(Tag.IF) ? (JCIf)translatedIf : (JCIf) ((JCBlock)translatedIf).stats.tail.head;
+
+                    testStatement.cond = makeBinary(Tag.OR,
+                            make.Ident(fallthroughSym),
+                            testStatement.cond);
+
+                    resultStatements = resultStatements.append(translatedIf);
+                }
+                pendingMatchLabel.body = make.Block(0, resultStatements);
+                result = pendingMatchLabel;
+            } finally {
+                pendingMatchLabel = prevMatchLabel;
+            }
+        } else {
+            super.visitSwitch(tree);
+        }
+    }
+
+
+    @Override
+    public void visitMethodDef(JCMethodDecl tree) {
+        MethodSymbol prevMethodSym = currentMethodSym;
+        try {
+            currentMethodSym = tree.sym;
+            super.visitMethodDef(tree);
+        } finally {
+            currentMethodSym = prevMethodSym;
+        }
+    }
+
+    @Override
+    public void visitIdent(JCIdent tree) {
+        VarSymbol bindingVar = null;
+        if ((tree.sym.flags() & Flags.MATCH_BINDING) != 0) {
+            bindingVar = bindingContext.getBindingFor((BindingSymbol)tree.sym);
+        }
+        if (bindingVar == null) {
+            super.visitIdent(tree);
+        } else {
+            result = make.at(tree.pos).Ident(bindingVar);
+        }
+    }
+
+    public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
+        try {
+            this.make = make;
+            translate(cdef);
+        } finally {
+            // note that recursive invocations of this method fail hard
+            this.make = null;
+        }
+
+        if (debugTransPatterns) {
+            System.err.println(cdef);
+        }
+        return cdef;
+    }
+
+    /** Make an instanceof expression.
+     *  @param lhs      The expression.
+     *  @param type     The type to be tested.
+     */
+
+    JCInstanceOf makeTypeTest(JCExpression lhs, JCExpression type) {
+        JCInstanceOf tree = make.TypeTest(lhs, type);
+        tree.type = syms.booleanType;
+        return tree;
+    }
+
+    /** Make an attributed binary expression (copied from Lower).
+     *  @param optag    The operators tree tag.
+     *  @param lhs      The operator's left argument.
+     *  @param rhs      The operator's right argument.
+     */
+    JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
+        JCBinary tree = make.Binary(optag, lhs, rhs);
+        tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
+        tree.type = tree.operator.type.getReturnType();
+        return tree;
+    }
+
+    JCExpression convert(JCExpression expr, Type target) {
+        JCExpression result = make.at(expr.pos()).TypeCast(make.Type(target), expr);
+        result.type = (expr.type.constValue() != null) ?
+                constFold.coerce(expr.type, target) : target;
+        return result;
+    }
+
+    JCExpression makeDefaultValue(int pos, Type type) {
+        if (type.isReference()) {
+            return make.at(pos).Literal(BOT, null).setType(syms.botType);
+        } else {
+            final Object value;
+            switch (type.getTag()) {
+                case BYTE:
+                    value = (byte)0;
+                    break;
+                case SHORT:
+                    value = (short)0;
+                    break;
+                case INT:
+                    value = 0;
+                    break;
+                case FLOAT:
+                    value = 0f;
+                    break;
+                case LONG:
+                    value = 0L;
+                    break;
+                case DOUBLE:
+                    value = 0D;
+                    break;
+                case CHAR:
+                    value = (char)0;
+                    break;
+                case BOOLEAN:
+                    value = false;
+                    break;
+                default:
+                    Assert.error();
+                    return null;
+            }
+            return make.at(pos).Literal(value);
+        }
+    }
+
+    abstract class BindingContext {
+        abstract VarSymbol getBindingFor(BindingSymbol varSymbol);
+        abstract JCStatement decorateStatement(JCStatement stat);
+        abstract JCExpression decorateExpression(JCExpression expr);
+        abstract BindingContext pop();
+    }
+
+    class BasicBindingContext extends BindingContext {
+        List<BindingSymbol> matchBindings;
+        Map<BindingSymbol, VarSymbol> hoistedVarMap;
+        BindingContext parent;
+
+        public BasicBindingContext(List<BindingSymbol> matchBindings) {
+            this.matchBindings = matchBindings;
+            this.parent = bindingContext;
+            this.hoistedVarMap = matchBindings.stream()
+                    .filter(v -> parent.getBindingFor(v) == null)
+                    .collect(Collectors.toMap(v -> v, v -> new VarSymbol(v.flags(), v.name.append(names.fromString("$binding")), v.type, v.owner)));
+        }
+
+        @Override
+        VarSymbol getBindingFor(BindingSymbol varSymbol) {
+            VarSymbol res = parent.getBindingFor(varSymbol);
+            if (res != null) {
+                return res;
+            }
+            return hoistedVarMap.entrySet().stream()
+                    .filter(e -> e.getKey().isAliasFor(varSymbol))
+                    .findFirst()
+                    .map(e -> e.getValue()).orElse(null);
+        }
+
+        @Override
+        JCStatement decorateStatement(JCStatement stat) {
+            if (hoistedVarMap.isEmpty()) return stat;
+            ListBuffer<JCStatement> stats = new ListBuffer<>();
+            for (VarSymbol vsym : hoistedVarMap.values()) {
+                stats.add(makeHoistedVarDecl(stat.pos, vsym));
+            }
+            stats.add(stat);
+            return make.at(stat.pos).Block(0, stats.toList());
+        }
+
+        @Override
+        JCExpression decorateExpression(JCExpression expr) {
+            for (VarSymbol vsym : hoistedVarMap.values()) {
+                expr = make.at(expr.pos).LetExpr(makeHoistedVarDecl(expr.pos, vsym), expr).setType(expr.type);
+            }
+            return expr;
+        }
+
+        @Override
+        BindingContext pop() {
+            return bindingContext = parent;
+        }
+
+        private JCVariableDecl makeHoistedVarDecl(int pos, VarSymbol varSymbol) {
+            return make.at(pos).VarDef(varSymbol, makeDefaultValue(pos, varSymbol.erasure(types)));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransSwitches.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,276 @@
+/*
+ * 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.tools.javac.comp;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
+import com.sun.tools.javac.tree.JCTree.JCCase;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
+import com.sun.tools.javac.tree.JCTree.JCLambda;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCPattern;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCSwitch;
+import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
+import com.sun.tools.javac.tree.JCTree.JCThrow;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeTranslator;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Names;
+
+/**
+ * This pass translates JDK12 switch constructs, like cases with multiple patterns, rule switches
+ * and switch expressions.
+ */
+public class TransSwitches extends TreeTranslator {
+
+    protected static final Context.Key<TransSwitches> transSwitchesKey = new Context.Key<>();
+
+    public static TransSwitches instance(Context context) {
+        TransSwitches instance = context.get(transSwitchesKey);
+        if (instance == null)
+            instance = new TransSwitches(context);
+        return instance;
+    }
+
+    private Symtab syms;
+    private Resolve rs;
+    private Names names;
+    private TypeEnvs typeEnvs;
+    private Target target;
+
+    /** The current method symbol.
+     */
+    private MethodSymbol currentMethodSym;
+
+    /** Environment for symbol lookup, set by translateTopLevelClass.
+     */
+    private Env<AttrContext> attrEnv;
+
+    private TreeMaker make;
+
+    public TransSwitches(Context context) {
+        context.put(transSwitchesKey, this);
+        syms = Symtab.instance(context);
+        rs = Resolve.instance(context);
+        names = Names.instance(context);
+        typeEnvs = TypeEnvs.instance(context);
+        target = Target.instance(context);
+    }
+
+    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<JCPattern> patterns = c.pats;
+                    while (patterns.tail.nonEmpty()) {
+                        JCCase cse = make_at(c.pos()).Case(JCCase.STATEMENT,
+                                                           List.of(patterns.head),
+                                                           List.nil(),
+                                                           null);
+                        cse.completesNormally = true;
+                        cases.append(cse);
+                        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.selector = translate(tree.selector);
+        tree.cases = translateCases(cases.toList());
+
+        result = tree;
+    }
+
+    @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.kind = tree.kind;
+        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));
+            JCCase res = make.Case(c.caseKind, c.pats, statements.toList(), null);
+            res.completesNormally = c.completesNormally;
+            return res;
+        }
+
+    public void visitClassDef(JCClassDecl tree) {
+        MethodSymbol currentMethodSymPrev = currentMethodSym;
+        Env<AttrContext> prevEnv = attrEnv;
+
+        try {
+            currentMethodSym = null;
+            attrEnv = typeEnvs.get(tree.sym);
+            if (attrEnv == null)
+                attrEnv = prevEnv;
+            super.visitClassDef(tree);
+        } finally {
+            attrEnv = prevEnv;
+            currentMethodSym = currentMethodSymPrev;
+        }
+    }
+
+    public void visitMethodDef(JCMethodDecl tree) {
+        MethodSymbol prevMethodSym = currentMethodSym;
+        try {
+            currentMethodSym = tree.sym;
+            super.visitMethodDef(tree);
+        } finally {
+            currentMethodSym = prevMethodSym;
+        }
+    }
+
+    public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
+        try {
+            this.make = make;
+            translate(cdef);
+        } finally {
+            // note that recursive invocations of this method fail hard
+            this.make = null;
+        }
+
+        return cdef;
+    }
+
+    //from Lower (probably generalize):
+    private DiagnosticPosition make_pos;
+
+    /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
+     *  pos as make_pos, for use in diagnostics.
+     **/
+    TreeMaker make_at(DiagnosticPosition pos) {
+        make_pos = pos;
+        return make.at(pos);
+    }
+
+    /** Make an attributed class instance creation expression.
+     *  @param ctype    The class type.
+     *  @param args     The constructor arguments.
+     */
+    JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
+        JCNewClass tree = make.NewClass(null,
+            null, make.QualIdent(ctype.tsym), args, null);
+        tree.constructor = rs.resolveConstructor(
+            make_pos, attrEnv, ctype, TreeInfo.types(args), List.nil());
+        tree.type = ctype;
+        return tree;
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Oct 05 19:50:15 2018 +0200
@@ -567,6 +567,19 @@
         result = tree;
     }
 
+    public void visitPatternTest(JCMatches tree) {
+        tree.expr = translate(tree.expr, null);
+        tree.pattern = translate(tree.pattern, null);
+        result = tree;
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        if (tree.vartype != null) {
+            tree.vartype = translate(tree.vartype, null);
+        }
+        result = tree;
+    }
+    
     public void visitSwitchExpression(JCSwitchExpression tree) {
         Type selsuper = types.supertype(tree.selector.type);
         boolean enumSwitch = selsuper != null &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Oct 05 19:50:15 2018 +0200
@@ -1153,7 +1153,7 @@
             for (int i = 0; i < labels.length; i++) {
                 if (l.head.pats.nonEmpty()) {
                     Assert.check(l.head.pats.size() == 1);
-                    int val = ((Number)l.head.pats.head.type.constValue()).intValue();
+                    int val = ((Number)l.head.pats.head.constExpression().type.constValue()).intValue();
                     labels[i] = val;
                     if (val < lo) lo = val;
                     if (hi < val) hi = val;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Oct 05 19:50:15 2018 +0200
@@ -1561,6 +1561,18 @@
                 compileStates.put(env, CompileState.UNLAMBDA);
             }
 
+            if (shouldStop(CompileState.TRANSSWITCHES))
+                return;
+
+            env.tree = TransSwitches.instance(context).translateTopLevelClass(env, env.tree, localMake);
+            compileStates.put(env, CompileState.TRANSSWITCHES);
+
+            if (shouldStop(CompileState.TRANSSWITCHES))
+                return;
+
+            env.tree = TransPatterns.instance(context).translateTopLevelClass(env, env.tree, localMake);
+            compileStates.put(env, CompileState.TRANSPATTERNS);
+
             if (shouldStop(CompileState.LOWER))
                 return;
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Oct 05 19:50:15 2018 +0200
@@ -361,6 +361,7 @@
                 case DO:
                 case TRY:
                 case SWITCH:
+                case MATCH:
                 case RETURN:
                 case THROW:
                 case BREAK:
@@ -583,6 +584,11 @@
             Name name = token.name();
             nextToken();
             return name;
+        } else if (token.kind == MATCHES || token.kind == TokenKind.MATCH || token.kind == VAR) {
+            //'matches', 'match', 'var' are just identifiers when inside other expressions
+            Name name = token.name();
+            nextToken();
+            return name;
         } else {
             accept(IDENTIFIER);
             if (advanceOnErrors) {
@@ -736,6 +742,25 @@
         return term(EXPR);
     }
 
+
+    /** parses patterns.
+     */
+
+    public JCPattern parsePattern() {
+        int pos = token.pos;
+        if (token.kind == VAR) {
+            nextToken();
+            return toP(F.at(pos).BindingPattern(ident(), null));
+        } else {
+            JCExpression e = term(EXPR | TYPE | NOLAMBDA);
+            if (token.kind == IDENTIFIER) {
+                return toP(F.at(pos).BindingPattern(ident(), e));
+            } else {
+                return toP(F.at(pos).LiteralPattern(e));
+            }
+        }
+    }
+
     /**
      * parses (optional) type annotations followed by a type. If the
      * annotations are present before the type and are not consumed during array
@@ -886,6 +911,7 @@
 
     /*  Expression2Rest = {infixop Expression3}
      *                  | Expression3 instanceof Type
+     *                  | Expression3 matches Pattern
      *  infixop         = "||"
      *                  | "&&"
      *                  | "|"
@@ -898,6 +924,7 @@
      *                  | "*" | "/" | "%"
      */
     JCExpression term2Rest(JCExpression t, int minprec) {
+
         JCExpression[] odStack = newOdStack();
         Token[] opStack = newOpStack();
 
@@ -908,13 +935,25 @@
         Token topOp = Tokens.DUMMY;
         while (prec(token.kind) >= minprec) {
             opStack[top] = topOp;
-            top++;
-            topOp = token;
-            nextToken();
-            odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3();
+
+            if (token.kind == INSTANCEOF) {
+                int pos = token.pos;
+                nextToken();
+                JCExpression typ = parseType();
+                odStack[top] = F.at(pos).TypeTest(odStack[top], typ);
+            } else if (token.kind == MATCHES) {
+                int pos = token.pos;
+                nextToken();
+                JCPattern pat = parsePattern();
+                odStack[top] = F.at(pos).PatternTest(odStack[top], pat);
+            } else {
+                topOp = token;
+                nextToken();
+                top++;
+                odStack[top] = term3();
+            }
             while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
-                odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1],
-                                        odStack[top]);
+                odStack[top - 1] = F.at(topOp.pos).Binary(optag(topOp.kind), odStack[top - 1], odStack[top]);
                 top--;
                 topOp = opStack[top];
             }
@@ -931,19 +970,18 @@
         return t;
     }
     //where
-        /** Construct a binary or type test node.
-         */
-        private JCExpression makeOp(int pos,
-                                    TokenKind topOp,
-                                    JCExpression od1,
-                                    JCExpression od2)
-        {
-            if (topOp == INSTANCEOF) {
-                return F.at(pos).TypeTest(od1, od2);
-            } else {
-                return F.at(pos).Binary(optag(topOp), od1, od2);
+        Filter<TokenKind> matchFilter = tk -> {
+            switch (tk) {
+                case LPAREN:
+                case DOT:
+                case EQ:
+                    return false;
+                case MATCHES:
+                    return true;
+                default: return optag(tk) == Tag.NO_TAG;
             }
-        }
+        };
+
         /** If tree is a concatenation of string literals, replace it
          *  by a single literal representing the concatenated string.
          */
@@ -1210,7 +1248,7 @@
                 t = insertAnnotationsToMostInner(expr, typeAnnos, false);
             }
             break;
-        case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
+        case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM: case MATCH: case MATCHES: case VAR:
             if (typeArgs != null) return illegal();
             if ((mode & EXPR) != 0 && (mode & NOLAMBDA) == 0 && peekToken(ARROW)) {
                 t = lambdaExpressionOrStatement(false, false, pos);
@@ -1408,14 +1446,14 @@
     private List<JCCase> switchExpressionStatementGroup() {
         ListBuffer<JCCase> caseExprs = new ListBuffer<>();
         int casePos = token.pos;
-        ListBuffer<JCExpression> pats = new ListBuffer<>();
+        ListBuffer<JCPattern> pats = new ListBuffer<>();
 
         if (token.kind == DEFAULT) {
             nextToken();
         } else {
             accept(CASE);
             while (true) {
-                pats.append(term(EXPR | NOLAMBDA));
+                pats.append(parsePattern());
                 if (token.kind != COMMA) break;
                 checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
                 nextToken();
@@ -1654,6 +1692,7 @@
                         case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
                         case TRUE: case FALSE: case NULL:
                         case NEW: case IDENTIFIER: case ASSERT: case ENUM: case UNDERSCORE:
+                        case VAR: case MATCH: case MATCHES:
                         case BYTE: case SHORT: case CHAR: case INT:
                         case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
                             return ParensResult.CAST;
@@ -1664,6 +1703,21 @@
                 case ASSERT:
                 case ENUM:
                 case IDENTIFIER:
+                case VAR:
+                case MATCH: // ??
+                case MATCHES: // ??
+                    if (tk == IDENTIFIER && S.token(lookahead + 1).kind == MATCHES) {
+                        // Identifier, "matches" -> ! explicit lambda
+                        return ParensResult.PARENS;
+                    }
+                    if (peekToken(lookahead, MATCHES)) {
+                        Token next = S.token(lookahead + 1);
+                        if (next.kind == COMMA || next.kind == RPAREN) {
+                            // Identifier matches ','|')' -> explicit lambda
+                            return ParensResult.EXPLICIT_LAMBDA;
+                        }
+                        return ParensResult.PARENS;
+                    }
                     if (peekToken(lookahead, LAX_IDENTIFIER)) {
                         // Identifier, Identifier/'_'/'assert'/'enum' -> explicit lambda
                         return ParensResult.EXPLICIT_LAMBDA;
@@ -1764,7 +1818,8 @@
     }
 
     /** Accepts all identifier-like tokens */
-    protected Filter<TokenKind> LAX_IDENTIFIER = t -> t == IDENTIFIER || t == UNDERSCORE || t == ASSERT || t == ENUM;
+    protected Filter<TokenKind> LAX_IDENTIFIER = t -> t == IDENTIFIER || t == UNDERSCORE || t == ASSERT || t == ENUM ||
+            t == MATCHES || t == TokenKind.MATCH || t == VAR;
 
     enum ParensResult {
         CAST,
@@ -2522,6 +2577,13 @@
         case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
         case ASSERT:
             return List.of(parseSimpleStatement());
+        case MATCH:
+            //is it a match statement?
+            if (isMatchStatement()) {
+                return List.of(parseSimpleStatement());
+            } else {
+                break;
+            }
         case MONKEYS_AT:
         case FINAL: {
             Comment dc = token.comment(CommentStyle.JAVADOC);
@@ -2548,28 +2610,54 @@
             log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.LocalEnum);
             dc = token.comment(CommentStyle.JAVADOC);
             return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
-        default:
-            Token prevToken = token;
-            JCExpression t = term(EXPR | TYPE);
-            if (token.kind == COLON && t.hasTag(IDENT)) {
-                nextToken();
-                JCStatement stat = parseStatementAsBlock();
-                return List.of(F.at(pos).Labelled(prevToken.name(), stat));
-            } else if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
-                pos = token.pos;
-                JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
-                F.at(pos);
-                return localVariableDeclarations(mods, t);
-            } else {
-                // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
-                t = checkExprStat(t);
-                accept(SEMI);
-                JCExpressionStatement expr = toP(F.at(pos).Exec(t));
-                return List.of(expr);
+        }
+        //otherwise
+        Token prevToken = token;
+        JCExpression t = term(EXPR | TYPE);
+        if (token.kind == COLON && t.hasTag(IDENT)) {
+            nextToken();
+            JCStatement stat = parseStatementAsBlock();
+            return List.of(F.at(pos).Labelled(prevToken.name(), stat));
+        } else if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
+            pos = token.pos;
+            JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
+            F.at(pos);
+            return localVariableDeclarations(mods, t);
+        } else {
+            // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
+            t = checkExprStat(t);
+            accept(SEMI);
+            JCExpressionStatement expr = toP(F.at(pos).Exec(t));
+            return List.of(expr);
+        }
+    }
+
+    //where
+        boolean isMatchStatement() {
+            //we need a LPAREN
+            if (!peekToken(LPAREN)) {
+                return false;
+            }
+            //then we scan through the contents of the '(...)', looking for a matching closing parens,
+            //followed by an '{'.
+            int depth = 1;
+            for (int lookahead = 2 ; ; lookahead++) {
+                TokenKind tk = S.token(lookahead).kind;
+                switch (tk) {
+                    case LPAREN:
+                        depth++;
+                        break;
+                    case RPAREN:
+                        depth--;
+                        if (depth == 0) {
+                            return S.token(lookahead + 1).kind == LBRACE;
+                        }
+                        break;
+                    case EOF:
+                        return false;
+                }
             }
         }
-    }
-    //where
         private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
             ListBuffer<JCStatement> stats =
                     variableDeclarators(mods, type, new ListBuffer<>(), true);
@@ -2676,6 +2764,7 @@
             }
             return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
         }
+        case MATCH:
         case SWITCH: {
             nextToken();
             JCExpression selector = parExpression();
@@ -2794,7 +2883,7 @@
 
     /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
      *  SwitchBlockStatementGroup = SwitchLabel BlockStatements
-     *  SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
+     *  SwitchLabel = CASE Pattern ":" | DEFAULT ":"
      */
     List<JCCase> switchBlockStatementGroups() {
         ListBuffer<JCCase> cases = new ListBuffer<>();
@@ -2822,9 +2911,9 @@
         switch (token.kind) {
         case CASE: {
             nextToken();
-            ListBuffer<JCExpression> pats = new ListBuffer<>();
+            ListBuffer<JCPattern> pats = new ListBuffer<>();
             while (true) {
-                pats.append(term(EXPR | NOLAMBDA));
+                pats.append(parsePattern());
                 if (token.kind != COMMA) break;
                 nextToken();
                 checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
@@ -4221,7 +4310,7 @@
     /** Return precedence of operator represented by token,
      *  -1 if token is not a binary operator. @see TreeInfo.opPrec
      */
-    static int prec(TokenKind token) {
+    int prec(TokenKind token) {
         JCTree.Tag oc = optag(token);
         return (oc != NO_TAG) ? TreeInfo.opPrec(oc) : -1;
     }
@@ -4241,7 +4330,7 @@
     /** Return operation tag of binary operator represented by token,
      *  No_TAG if token is not a binary operator.
      */
-    static JCTree.Tag optag(TokenKind token) {
+    JCTree.Tag optag(TokenKind token) {
         switch (token) {
         case BARBAR:
             return OR;
@@ -4305,6 +4394,8 @@
             return MOD_ASG;
         case INSTANCEOF:
             return TYPETEST;
+        case MATCHES:
+             return peekToken(matchFilter) ? PATTERNTEST : NO_TAG;
         default:
             return NO_TAG;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Fri Oct 05 19:50:15 2018 +0200
@@ -145,6 +145,8 @@
         INT("int", Tag.NAMED),
         INTERFACE("interface"),
         LONG("long", Tag.NAMED),
+        MATCH("__match", Tag.NAMED),
+        MATCHES("__matches", Tag.NAMED),
         NATIVE("native"),
         NEW("new"),
         PACKAGE("package"),
@@ -163,6 +165,7 @@
         THROWS("throws"),
         TRANSIENT("transient"),
         TRY("try"),
+        VAR("var", Tag.NAMED),
         VOID("void", Tag.NAMED),
         VOLATILE("volatile"),
         WHILE("while"),
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Oct 05 19:50:15 2018 +0200
@@ -535,6 +535,10 @@
     auto-closeable resource {0} may not be assigned
 
 # 0: symbol
+compiler.err.pattern.binding.may.not.be.assigned=\
+    pattern binding {0} may not be assigned
+
+# 0: symbol
 compiler.err.multicatch.parameter.may.not.be.assigned=\
     multi-catch parameter {0} may not be assigned
 
@@ -1322,6 +1326,9 @@
 compiler.err.unreachable.stmt=\
     unreachable statement
 
+compiler.err.pattern.dominated=\
+    the pattern is dominated by a preceding pattern
+
 compiler.err.not.exhaustive=\
     the switch expression does not cover all possible input values
 
@@ -3321,6 +3328,12 @@
 compiler.err.illegal.argument.for.option=\
     illegal argument for {0}: {1}
 
+compiler.err.match.binding.exists.with.different.type=\
+    illegal attempt to redefine an existing match binding with different type
+
+compiler.err.match.binding.exists=\
+    illegal attempt to redefine an existing match binding
+
 compiler.err.switch.null.not.allowed=\
     null label in case is not allowed
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Oct 05 19:50:15 2018 +0200
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.io.StringWriter;
 import java.util.*;
+import java.util.stream.Collectors;
 
 import javax.lang.model.element.Modifier;
 import javax.lang.model.type.TypeKind;
@@ -38,6 +39,7 @@
 import com.sun.tools.javac.code.Directive.RequiresDirective;
 import com.sun.tools.javac.code.Scope.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -151,13 +153,17 @@
          */
         SWITCH,
 
+        /** Switch expression statements, of type Switch.
+         */
+        SWITCH_EXPRESSION,
+
         /** Case parts in switch statements/expressions, of type Case.
          */
         CASE,
 
-        /** Switch expression statements, of type Switch.
+        /** Case parts in match statements, of type Clause.
          */
-        SWITCH_EXPRESSION,
+        CLAUSE,
 
         /** Synchronized statements, of type Synchonized.
          */
@@ -235,6 +241,15 @@
          */
         TYPETEST,
 
+        /** Pattern test expression, of type PatternTest.
+         */
+        PATTERNTEST,
+
+        /** Patterns.
+         */
+        BINDINGPATTERN,
+        LITERALPATTERN,
+
         /** Indexed array expressions, of type Indexed.
          */
         INDEXED,
@@ -1211,12 +1226,21 @@
         }
     }
 
+    public interface GenericSwitch {
+        public enum SwitchKind {
+            ORDINARY,
+            STRING,
+            ENUM,
+            MATCHING;
+        }
+    }
     /**
      * A "switch ( ) { }" construction.
      */
-    public static class JCSwitch extends JCStatement implements SwitchTree {
+    public static class JCSwitch extends JCStatement implements SwitchTree, GenericSwitch {
         public JCExpression selector;
         public List<JCCase> cases;
+        public SwitchKind kind;
         protected JCSwitch(JCExpression selector, List<JCCase> cases) {
             this.selector = selector;
             this.cases = cases;
@@ -1252,11 +1276,11 @@
         public static final CaseKind RULE = CaseKind.RULE;
         @SuppressWarnings("removal")
         public final CaseKind caseKind;
-        public List<JCExpression> pats;
+        public List<JCPattern> pats;
         public List<JCStatement> stats;
         public JCTree body;
         public boolean completesNormally;
-        protected JCCase(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pats,
+        protected JCCase(@SuppressWarnings("removal") CaseKind caseKind, List<JCPattern> pats,
                          List<JCStatement> stats, JCTree body) {
             Assert.checkNonNull(pats);
             Assert.check(pats.isEmpty() || pats.head != null);
@@ -1270,11 +1294,19 @@
 
         @Override @DefinedBy(Api.COMPILER_TREE)
         public Kind getKind() { return Kind.CASE; }
-        @Override @DefinedBy(Api.COMPILER_TREE)
-        public JCExpression getExpression() { return pats.head; }
+        @DefinedBy(Api.COMPILER_TREE)
+        @Deprecated
+        public JCExpression getExpression() {
+            return pats.nonEmpty() ? pats.head.constExpression() : null;
+        }
         @Override @DefinedBy(Api.COMPILER_TREE)
         @SuppressWarnings("removal")
-        public List<JCExpression> getExpressions() { return pats; }
+        public java.util.List<JCExpression> getExpressions() {
+            return pats.stream()
+                       .map(pat -> pat.constExpression())
+                       .collect(Collectors.toList());
+        }
+        public List<JCPattern> getPatterns() { return pats; }
         @Override @DefinedBy(Api.COMPILER_TREE)
         @SuppressWarnings("removal")
         public List<JCStatement> getStatements() {
@@ -1298,13 +1330,16 @@
         }
     }
 
+
+
     /**
      * A "switch ( ) { }" construction.
      */
     @SuppressWarnings("removal")
-    public static class JCSwitchExpression extends JCPolyExpression implements SwitchExpressionTree {
+    public static class JCSwitchExpression extends JCPolyExpression implements SwitchExpressionTree, GenericSwitch {
         public JCExpression selector;
         public List<JCCase> cases;
+        public SwitchKind kind;
         protected JCSwitchExpression(JCExpression selector, List<JCCase> cases) {
             this.selector = selector;
             this.cases = cases;
@@ -2136,6 +2171,144 @@
     }
 
     /**
+     * A pattern match test.
+     */
+    public static class JCMatches extends JCExpression
+            implements MatchesTree {
+        public JCExpression expr;
+        public JCPattern pattern;
+        protected JCMatches(JCExpression expr, JCPattern pattern) {
+            this.expr = expr;
+            this.pattern = pattern;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitPatternTest(this); }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() { return Kind.MATCHES; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCPattern getPattern() { return pattern; }
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return expr; }
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitMatches(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return PATTERNTEST;
+        }
+    }
+
+    /**
+     * Pattern matching forms.
+     */
+    public static abstract class JCPattern extends JCTree
+            implements PatternTree {
+        public JCExpression constExpression() {
+            return null;
+        }        
+    }
+
+    public static class JCBindingPattern extends JCPattern
+            implements BindingPatternTree {
+        public Name name;
+        public BindingSymbol symbol;
+        public JCExpression vartype;   /** Null if var pattern */
+
+        protected JCBindingPattern(Name name, BindingSymbol symbol, JCExpression vartype) {
+            this.name = name;
+            this.symbol = symbol;
+            this.vartype = vartype;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getBinding() {
+            return name;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Tree getType() {
+            return vartype;
+        }
+
+        @Override
+        public void accept(Visitor v) {
+            v.visitBindingPattern(this);
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.BINDING_PATTERN;
+        }
+
+        @Override
+        @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitBindingPattern(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return BINDINGPATTERN;
+        }
+    }
+
+    public static class JCLiteralPattern extends JCPattern
+            implements LiteralPatternTree {
+
+        public JCExpression value;
+        public LiteralPatternKind patternKind;
+
+        protected JCLiteralPattern(JCExpression value) {
+            Assert.checkNonNull(value);
+            this.value = value;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        @Override
+        public Name getBinding() {
+            return null;
+        }
+
+        @Override
+        public void accept(Visitor v) {
+            v.visitLiteralPattern(this);
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.LITERAL_PATTERN;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getValue() {
+            return value;
+        }
+
+        @Override
+        @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitLiteralPattern(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return LITERALPATTERN;
+        }
+
+        @Override
+        public JCExpression constExpression() {
+            return value;
+        }
+
+        public enum LiteralPatternKind {
+            CONSTANTEXPRESSIONORNULL,
+            TYPE
+        }
+    }
+
+    /**
      * An array selection
      */
     public static class JCArrayAccess extends JCExpression implements ArrayAccessTree {
@@ -3069,7 +3242,7 @@
         JCLabeledStatement Labelled(Name label, JCStatement body);
         JCSwitch Switch(JCExpression selector, List<JCCase> cases);
         JCSwitchExpression SwitchExpression(JCExpression selector, List<JCCase> cases);
-        JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pat,
+        JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCPattern> pat,
                     List<JCStatement> stats, JCTree body);
         JCSynchronized Synchronized(JCExpression lock, JCBlock body);
         JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
@@ -3106,6 +3279,9 @@
         JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs);
         JCTypeCast TypeCast(JCTree expr, JCExpression type);
         JCInstanceOf TypeTest(JCExpression expr, JCTree clazz);
+        JCMatches PatternTest(JCExpression expr, JCPattern clazz);
+        JCBindingPattern BindingPattern(Name name, JCExpression vartype);
+        JCLiteralPattern LiteralPattern(JCExpression cexp);
         JCArrayAccess Indexed(JCExpression indexed, JCExpression index);
         JCFieldAccess Select(JCExpression selected, Name selector);
         JCIdent Ident(Name idname);
@@ -3169,6 +3345,9 @@
         public void visitBinary(JCBinary that)               { visitTree(that); }
         public void visitTypeCast(JCTypeCast that)           { visitTree(that); }
         public void visitTypeTest(JCInstanceOf that)         { visitTree(that); }
+        public void visitPatternTest(JCMatches that)         { visitTree(that); }
+        public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
+        public void visitLiteralPattern(JCLiteralPattern that) { visitTree(that); }
         public void visitIndexed(JCArrayAccess that)         { visitTree(that); }
         public void visitSelect(JCFieldAccess that)          { visitTree(that); }
         public void visitReference(JCMemberReference that)   { visitTree(that); }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Fri Oct 05 19:50:15 2018 +0200
@@ -235,6 +235,23 @@
         printExprs(trees, ", ");
     }
 
+
+    /** Derived visitor method: print pattern.
+     */
+
+    public void printPattern(JCTree tree) throws IOException {
+        printExpr(tree);
+    }
+
+    public <T extends JCTree> void printPatterns(List<T> trees) throws IOException {
+        if (trees.nonEmpty()) {
+            printPattern(trees.head);
+            for (List<T> l = trees.tail; l.nonEmpty(); l = l.tail) {
+                print(", ");
+                printPattern(l.head);
+            }
+        }
+    }
     /** Derived visitor method: print list of statements, each on a separate line.
      */
     public void printStats(List<? extends JCTree> trees) throws IOException {
@@ -878,6 +895,29 @@
         }
     }
 
+    public void visitBindingPattern(JCBindingPattern patt) {
+        try {
+            if (patt.vartype == null) {
+                print("var ");
+                print(patt.name);
+            } else {
+                printExpr(patt.vartype);
+                print(" ");
+                print(patt.name);
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public void visitLiteralPattern(JCLiteralPattern patt) {
+        try {
+            print(patt.value);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitSynchronized(JCSynchronized tree) {
         try {
             print("synchronized ");
@@ -1280,6 +1320,18 @@
         }
     }
 
+    public void visitPatternTest(JCMatches tree) {
+        try {
+            open(prec, TreeInfo.ordPrec);
+            printExpr(tree.expr, TreeInfo.ordPrec);
+            print(" matches ");
+            printPattern(tree.pattern);
+            close(prec, TreeInfo.ordPrec);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitIndexed(JCArrayAccess tree) {
         try {
             printExpr(tree.indexed, TreeInfo.postfixPrec);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Oct 05 19:50:15 2018 +0200
@@ -26,7 +26,6 @@
 package com.sun.tools.javac.tree;
 
 import com.sun.source.tree.*;
-import com.sun.source.tree.Tree.Kind;
 import com.sun.tools.javac.tree.JCTree.*;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -147,7 +146,7 @@
     @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitCase(CaseTree node, P p) {
         JCCase t = (JCCase) node;
-        List<JCExpression> pats = copy(t.pats, p);
+        List<JCPattern> pats = copy(t.pats, p);
         List<JCStatement> stats = copy(t.stats, p);
         JCTree body = copy(t.body, p);
         return M.at(t.pos).Case(t.caseKind, pats, stats, body);
@@ -481,6 +480,29 @@
     }
 
     @DefinedBy(Api.COMPILER_TREE)
+    public JCTree visitMatches(MatchesTree node, P p) {
+        JCMatches t = (JCMatches) node;
+        JCExpression expr = copy(t.expr, p);
+        JCPattern pattern = copy(t.pattern, p);
+        return M.at(t.pos).PatternTest(expr, pattern);
+    }
+
+
+    @DefinedBy(Api.COMPILER_TREE)
+    public JCTree visitBindingPattern(BindingPatternTree node, P p) {
+        JCBindingPattern t = (JCBindingPattern) node;
+        JCExpression vartype = copy(t.vartype, p);
+        return M.at(t.pos).BindingPattern(t.name, vartype);
+    }
+
+    @DefinedBy(Api.COMPILER_TREE)
+    public JCTree visitLiteralPattern(LiteralPatternTree node, P p) {
+        JCLiteralPattern t = (JCLiteralPattern)node;
+        JCExpression value = copy(t.value, p);
+        return M.at(t.pos).LiteralPattern(value);
+    }
+    
+    @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitUnary(UnaryTree node, P p) {
         JCUnary t = (JCUnary) node;
         JCExpression arg = copy(t.arg, p);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Fri Oct 05 19:50:15 2018 +0200
@@ -454,6 +454,8 @@
                 return getStartPos(((JCArrayTypeTree) tree).elemtype);
             case TYPETEST:
                 return getStartPos(((JCInstanceOf) tree).expr);
+            case PATTERNTEST:
+                return getStartPos(((JCMatches) tree).expr);
             case ANNOTATED_TYPE: {
                 JCAnnotatedType node = (JCAnnotatedType) tree;
                 if (node.annotations.nonEmpty()) {
@@ -572,6 +574,8 @@
                 return getEndPos(((JCTypeCast) tree).expr, endPosTable);
             case TYPETEST:
                 return getEndPos(((JCInstanceOf) tree).clazz, endPosTable);
+            case PATTERNTEST:
+                return getEndPos(((JCMatches) tree).pattern, endPosTable);
             case WHILELOOP:
                 return getEndPos(((JCWhileLoop) tree).body, endPosTable);
             case ANNOTATED_TYPE:
@@ -844,6 +848,8 @@
             if (node.type != null)
                 return node.type.tsym;
             return null;
+        case BINDINGPATTERN:
+            return ((JCBindingPattern) node).symbol;
         default:
             return null;
         }
@@ -1006,7 +1012,8 @@
         case MUL:
         case DIV:
         case MOD: return mulPrec;
-        case TYPETEST: return ordPrec;
+        case TYPETEST:
+        case PATTERNTEST: return ordPrec;
         default: throw new AssertionError();
         }
     }
@@ -1222,4 +1229,5 @@
     public static boolean isPackageInfo(JCCompilationUnit tree) {
         return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE);
     }
+
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Oct 05 19:50:15 2018 +0200
@@ -29,7 +29,6 @@
 
 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.*;
 import com.sun.tools.javac.code.Attribute.UnresolvedClass;
 import com.sun.tools.javac.code.Symbol.*;
@@ -274,7 +273,7 @@
         return tree;
     }
 
-    public JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCExpression> pats,
+    public JCCase Case(@SuppressWarnings("removal") CaseKind caseKind, List<JCPattern> pats,
                        List<JCStatement> stats, JCTree body) {
         JCCase tree = new JCCase(caseKind, pats, stats, body);
         tree.pos = pos;
@@ -442,6 +441,24 @@
         return tree;
     }
 
+    public JCMatches PatternTest(JCExpression expr, JCPattern patt) {
+        JCMatches tree = new JCMatches(expr, patt);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCBindingPattern BindingPattern(Name name, JCExpression vartype) {
+        JCBindingPattern tree = new JCBindingPattern(name, null, vartype);
+        tree.pos = pos;
+        return tree;
+    }
+
+    public JCLiteralPattern LiteralPattern(JCExpression cexp) {
+        JCLiteralPattern tree = new JCLiteralPattern(cexp);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) {
         JCArrayAccess tree = new JCArrayAccess(indexed, index);
         tree.pos = pos;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Oct 05 19:50:15 2018 +0200
@@ -299,6 +299,20 @@
         scan(tree.clazz);
     }
 
+    public void visitPatternTest(JCMatches tree) {
+        scan(tree.expr);
+        scan(tree.pattern);
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        if (tree.vartype != null)
+            scan(tree.vartype);
+    }
+
+    public void visitLiteralPattern(JCLiteralPattern tree) {
+        scan(tree.value);
+    }
+
     public void visitIndexed(JCArrayAccess tree) {
         scan(tree.indexed);
         scan(tree.index);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Oct 05 19:50:15 2018 +0200
@@ -355,6 +355,23 @@
         result = tree;
     }
 
+    public void visitPatternTest(JCMatches tree) {
+        tree.expr = translate(tree.expr);
+        tree.pattern = translate(tree.pattern);
+        result = tree;
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        if (tree.vartype != null) {
+            tree.vartype = translate(tree.vartype);
+        }
+        result = tree;
+    }
+
+    public void visitLiteralPattern(JCLiteralPattern tree) {
+        result = tree;
+    }
+
     public void visitIndexed(JCArrayAccess tree) {
         tree.indexed = translate(tree.indexed);
         tree.index = translate(tree.index);
--- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Fri Oct 05 19:50:15 2018 +0200
@@ -212,6 +212,7 @@
         LONG(TokenKind.LONG, XEXPR1|XDECL1),  //  long
         SHORT(TokenKind.SHORT, XEXPR1|XDECL1),  //  short
         VOID(TokenKind.VOID, XEXPR1|XDECL1),  //  void
+        VAR(TokenKind.VAR, XEXPR1|XDECL1|XTERM),  //  var
 
         // Modifiers keywords
         ABSTRACT(TokenKind.ABSTRACT, XDECL1),  //  abstract
@@ -254,6 +255,7 @@
         THROW(TokenKind.THROW, XSTMT1|XSTART),  //  throw
         TRY(TokenKind.TRY, XSTMT1|XSTART),  //  try
         WHILE(TokenKind.WHILE, XSTMT1|XSTART),  //  while
+        MATCH(TokenKind.MATCH, XSTMT1|XSTART),  //  match
 
         // Statement keywords that we shouldn't see -- inside braces
         CASE(TokenKind.CASE, XSTMT|XSTART),  //  case
@@ -315,6 +317,7 @@
         LTLTEQ(TokenKind.LTLTEQ, XEXPR),  //  <<=
         GTGTEQ(TokenKind.GTGTEQ, XEXPR),  //  >>=
         GTGTGTEQ(TokenKind.GTGTGTEQ, XEXPR),  //  >>>=
+        MATCHES(TokenKind.MATCHES, XEXPR),
 
         // combined/processed kinds
         UNMATCHED(XERRO),
@@ -665,6 +668,7 @@
                         case BRACES:
                         case SEMI:
                             return Completeness.COMPLETE;
+                        case VAR:
                         case IDENTIFIER:
                             return isBracesNeeded
                                     ? Completeness.DEFINITELY_INCOMPLETE
--- a/test/langtools/jdk/jshell/CompletenessTest.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/test/langtools/jdk/jshell/CompletenessTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -80,6 +80,7 @@
         "i >= 0 && Character.isWhitespace(s.charAt(i))",
         "int.class",
         "String.class",
+        "var",
     };
 
     static final String[] complete_with_semi = new String[] {
@@ -122,6 +123,7 @@
         "int[] m = {1, 2}, n = null",
         "int[] m = {1, 2}, n",
         "int[] m = {1, 2}, n = {3, 4}",
+        "int var",
     };
 
     static final String[] considered_incomplete = new String[] {
@@ -186,6 +188,8 @@
         "int[] m = {1, 2},",
         "int[] m = {1, 2}, n = {3, 4},",
         "Map<String,",
+        "if (o __matches var",
+        "Map<String,",
         "switch (x) {",
         "var v = switch (x) {",
         "var v = switch (x) { case ",
--- a/test/langtools/tools/javac/api/TestGetElementReferenceData.java	Fri Oct 05 10:26:52 2018 -0700
+++ b/test/langtools/tools/javac/api/TestGetElementReferenceData.java	Fri Oct 05 19:50:15 2018 +0200
@@ -35,6 +35,8 @@
         java.util.List< /*getElement:INTERFACE:java.util.List*/ String> l;
         utility/*getElement:METHOD:test.TestGetElementReferenceData.Base.utility()*/();
         target(TestGetElementReferenceData :: test/*getElement:METHOD:test.TestGetElementReferenceData.test()*/);
+        Object o = null;
+        if (o __matches String/*getElement:CLASS:java.lang.String*/ str/*getElement:LOCAL_VARIABLE:str*/) ;
     }
     private static void target(Runnable r) { r.run(); }
     public static class Base {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/MatchBindingExists.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.match.binding.exists
+// key: compiler.err.match.binding.exists.with.different.type
+//TODO: the following error is extraneous?
+// key: compiler.err.already.defined
+
+class X {
+    public static void main(String [] args) {
+        String s = "Hello";
+        Integer i = 42;
+        Object o1 = s, o2 = i;
+
+        if (o1 __matches String k && o2 __matches Integer k) {}
+        if (o1 __matches String k || o2 __matches Integer k) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.pattern.binding.may.not.be.assigned
+
+class ResourceMayNotBeAssigned {
+    void m(Object o) {
+        if (o __matches String s) {
+            s = "";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternDominated.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.pattern.dominated
+class PatternDominated {
+    void test(Object o) {
+        switch (o) {
+            case Integer i: //fall-through
+            case 42: break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,118 @@
+/*
+ * @test
+ * @summary Basic tests for bindings from __matches
+ * @compile BindingsTest1.java
+ * @run main BindingsTest1
+ */
+
+public class BindingsTest1 {
+    public static boolean Ktrue() { return true; }
+    public static void main(String[] args) {
+        Object o1 = "hello";
+        Integer i = 42;
+        Object o2 = i;
+        Object o3 = "there";
+
+
+        // Test for (e matches P).T = { binding variables in P }
+        if (o1 __matches String s) {
+            s.length();
+        }
+
+        // Test for e1 && e2.T = union(e1.T, e2.T)
+        if (o1 __matches String s && o2 __matches Integer in) {
+            s.length();
+            in.intValue();
+        }
+        // Test for e1 && e2.F = intersect(e1.F, e2.F)
+        if (!(o1 __matches String s) && !(o1 __matches String s)) {
+
+        } else {
+            s.length();
+        }
+
+        // test for e1&&e2 - include e1.T in e2
+        if (o1 __matches String s && s.length()>0) {
+            System.out.print("done");
+        }
+
+        // Test for (e1 || e2).T = intersect(e1.T, e2.T)
+        if (o1 __matches String s || o3 __matches String s){
+            System.out.println(s); // ?
+        }
+
+        // Test for (e1 || e2).F = union(e1.F, e2.F)
+        if (!(o1 __matches String s) || !(o3 __matches Integer in)){
+        } else {
+            s.length();
+            i.intValue();
+        }
+
+        // Test for e1||e2 - include e1.F in e2
+
+        if (!(o1 __matches String s) || s.length()>0) {
+            System.out.println("done");
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e2.T, e3.T)
+        if (Ktrue() ? o2 __matches Integer x : o2 __matches Integer x) {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.T, e3.T)
+        if (o1 __matches String s ? true : o1 __matches String s) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+        if (!(o1 __matches String s) ? (o1 __matches String s) : true) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+        if (Ktrue() ? !(o2 __matches Integer x) : !(o2 __matches Integer x)){
+        } else {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+        if (o1 __matches String s ? true : !(o1 __matches String s)){
+        } else {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+        if (!(o1 __matches String s) ? !(o1 __matches String s) : true){
+        } else {
+            s.length();
+        }
+
+        // Test for e1 ? e2: e3 - include e1.T in e2
+        if (o1 __matches String s ? s.length()>0 : false) {
+            System.out.println("done");
+        }
+
+        // Test for e1 ? e2 : e3 - include e1.F in e3
+        if (!(o1 __matches String s) ? false : s.length()>0){
+            System.out.println("done");
+        }
+
+        // Test for (!e).T = e.F
+
+        if (!(!(o1 __matches String s) || !(o3 __matches Integer in))){
+            s.length();
+            i.intValue();
+        }
+
+        // Test for (!e).F = e.T
+        if (!(o1 __matches String s)) {
+
+        } else {
+            s.length();
+        }
+
+
+
+        System.out.println("BindingsTest1 complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest2.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,116 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Ensure that scopes arising from conditionalExpressions are handled corrected.
+ * @compile/fail/ref=BindingsTest2.out -XDrawDiagnostics BindingsTest2.java
+ */
+public class BindingsTest2 {
+    public static boolean Ktrue() { return true; }
+    public static void main(String[] args) {
+        Object o1 = "hello";
+        Integer in = 42;
+        Object o2 = in;
+        Object o3 = "there";
+
+
+        if (Ktrue() ? o2 __matches Integer x : o2 __matches String x) {
+            x.intValue();
+        }
+        if (Ktrue() ? o2 __matches Integer x : true) {
+            x.intValue();
+        }
+
+        if (o1 __matches String s ? true : true) {
+            s.length();
+        }
+        if (o1 __matches String s ? true : o2 __matches Integer s) {
+            s.length();
+        }
+        if (o1 __matches String s ? true : o2 __matches Integer i) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+        if (!(o1 __matches String s) ? true : true) {
+            s.length();
+        }
+        if (!(o1 __matches String s) ? (o2 __matches Integer s) : true) {
+            s.length();
+        }
+        if (!(o1 __matches String s) ? (o2 __matches Integer i) : true) {
+            s.length();
+            i.intValue();
+        }
+        if (!(o1 __matches String s) ? (o1 __matches String s2) : true) {
+            s.length();
+            s2.length();
+        }
+
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+        if (Ktrue() ? !(o2 __matches Integer x) : !(o1 __matches String x)){
+        } else {
+            x.intValue();
+        }
+        if (Ktrue() ? !(o2 __matches Integer x) : !(o1 __matches String s)){
+        } else {
+            x.intValue();
+        }
+        if (Ktrue() ? !(o2 __matches Integer x) : !(o2 __matches Integer x1)){
+        } else {
+            x.intValue();
+            x1.intValue();
+        }
+        if (Ktrue() ? !(o2 __matches Integer x) : false){
+        } else {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+        if (o1 __matches String s ? true : !(o2 __matches Integer s)){
+        } else {
+            s.length();
+        }
+        if (o1 __matches String s ? true : !(o2 __matches Integer i)){
+        } else {
+            s.length();
+            i.intValue();
+        }
+        if (o1 __matches String s ? true : !(o2 __matches String s1)){
+        } else {
+            s.length();
+            s1.length();
+        }
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+        if (!(o1 __matches String s) ? !(o1 __matches String s1) : true){
+        } else {
+            s.length();
+            s1.length();
+        }
+        if (!(o1 __matches String s) ? !(o2 __matches Integer s) : true){
+        } else {
+            s.length();
+        }
+        if (!(o1 __matches String s) ? !(o2 __matches Integer i) : true){
+        } else {
+            s.length();
+            i.intValue();
+        }
+
+        // Test for e1 ? e2: e3 - include e1.T in e2
+        if (o1 __matches String s ? false : s.length()>0) {
+            System.out.println("done");
+        }
+        if (o1 __matches String s ? false : s.intValue!=0) {
+            System.out.println("done");
+        }
+
+        // Test for e1 ? e2 : e3 - include e1.F in e3
+        if (!(o1 __matches String s) ? s.length()>0 : false){
+            System.out.println("done");
+        }
+        if (!(o1 __matches String s) ? s.intValue>0 : false){
+            System.out.println("done");
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest2.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,37 @@
+BindingsTest2.java:15:21: compiler.err.match.binding.exists.with.different.type
+BindingsTest2.java:16:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:19:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:23:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:25:35: compiler.err.match.binding.exists.with.different.type
+BindingsTest2.java:26:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:29:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:34:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:36:38: compiler.err.match.binding.exists.with.different.type
+BindingsTest2.java:37:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:40:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:41:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:44:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:45:13: compiler.err.cant.resolve.location: kindname.variable, s2, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:50:21: compiler.err.match.binding.exists.with.different.type
+BindingsTest2.java:52:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:56:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:60:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:61:13: compiler.err.cant.resolve.location: kindname.variable, x1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:65:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:69:35: compiler.err.match.binding.exists.with.different.type
+BindingsTest2.java:71:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:75:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:76:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:80:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:81:13: compiler.err.cant.resolve.location: kindname.variable, s1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:86:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:87:13: compiler.err.cant.resolve.location: kindname.variable, s1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:89:38: compiler.err.match.binding.exists.with.different.type
+BindingsTest2.java:91:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:95:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:96:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:100:45: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:103:45: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:108:40: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:111:40: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+36 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BreakInsideMatch.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * @test
+ * @summary testing break inside match clauses
+ * @compile BreakInsideMatch.java
+ * @run main BreakInsideMatch
+ */
+
+public class BreakInsideMatch {
+    static int i = 42;
+
+    public static void test(Object o) {
+        switch (o) {
+            case String s:
+                i++;
+                break;
+            case Integer in:
+                i = 0;
+                break;
+            default:
+                i = 100;
+                break;
+        }
+        System.out.println(i);
+    }
+
+    public static void main(String[] args) {
+
+        System.out.println("< Tests started");
+
+        test("Hello");
+        test(42);
+        test(42.0);
+
+
+        System.out.println("> Tests completed");
+
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/CastConversionMatch.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Match which involves a cast conversion
+ * @compile CastConversionMatch.java
+ * @run main CastConversionMatch
+ */
+
+public class CastConversionMatch {
+    public static void main(String [] args) {
+        Object o = 42;
+        if (o __matches int s) {
+            System.out.println("Okay");
+        } else {
+            throw new AssertionError("broken");
+        }
+        switch (o) {
+            case int i: {
+                System.out.println("Okay;");
+                break;
+            }
+            default: throw new AssertionError("broken");
+        }
+        System.out.println(">Test complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ConstantPatternTest1.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,440 @@
+/*
+ * @test
+ * @summary Basic tests for constant patterns
+ * @compile ConstantPatternTest1.java
+ * @run main ConstantPatternTest1
+ */
+
+public class ConstantPatternTest1 {
+    static int counter = 0;
+
+    public static void message() {
+        System.out.println("Test "+ counter);
+        counter++;
+    }
+
+    public static void fortyTwoTester(Object o) {
+        switch (o) {
+            case true: System.out.println("Boolean - wat no 42?"); break;
+            case 42f: System.out.println("42 float");break;
+            case '4': System.out.println("an f char"); break;
+            case 42.0: System.out.println("42.0"); break;
+            case 42: System.out.println("42"); break;
+            case "42": System.out.println("42 string"); break;
+            default: System.out.println("Something else"); break;
+        }
+    }
+    public static double valueOfD(){
+        return 41.0;
+    }
+
+    public static void main(String[] args) {
+
+        int i = 41;
+        i++;
+        final int constantInt = 42;
+
+
+        // Simple literal constant pattern
+        if (i __matches 42) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        // Simple constant expression pattern
+        if (i __matches 41+1) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        // Constant expression pattern using a final local
+        if (i __matches constantInt) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        //--- Tests for match statement
+
+        // Simple literal constant pattern
+        switch (i){
+            case 42: {
+                message();
+            }
+        }
+
+        // Simple constant expression pattern
+        switch (i){
+            case 41+1: {
+                message();
+            }
+        }
+
+        // Constant expression pattern using a final local
+        switch (i){
+            case constantInt: {
+                message();
+            }
+        }
+
+        // Multiple constant pattern clauses
+
+        switch (i){
+            case 41: {
+                throw new AssertionError("Broken");
+            }
+            case 42: {
+                message();
+                break;
+            }
+        }
+
+        switch (i){
+            case 42: {
+                message();
+                break;
+            }
+            case 41: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        switch (i){
+            case 42: {
+                message();
+                break;
+            }
+            case 41: {
+                throw new AssertionError("Broken");
+            }
+            default: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        switch (i){
+            case 41: {
+                throw new AssertionError("Broken");
+            }
+            case 42: {
+                message();
+                break;
+            }
+            default: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        // Multiple constant expression pattern clauses
+
+        switch (i){
+            case 41-1: {
+                throw new AssertionError("Broken");
+            }
+            case 42: {
+                message();
+                break;
+            }
+        }
+
+
+//--- DOUBLE TYPED CONSTANT EXPRESSIONS
+
+        double d = valueOfD();
+        d++;
+        final double constant = 42.0;
+        Object o = d;
+
+        //--- Tests for matches expression
+
+
+        // Simple literal constant pattern
+        if (d __matches 42.0) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        // Simple constant expression pattern
+        if (d __matches 41.0+1.0) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        // Constant expression pattern using a final local
+        if (d __matches constant) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        //--- Tests for match statement
+
+        // Simple literal constant pattern
+        switch (d) {
+            case 42.0: {
+                message();
+            }
+        }
+
+        // Simple constant expression pattern
+        switch (d) {
+            case 41.0+1.0: {
+                message();
+                break;
+            }
+        }
+
+        // Constant expression pattern using a final local
+        switch (d) {
+            case constant: {
+                message();
+                break;
+            }
+        }
+
+        // Multiple constant pattern clauses
+
+        switch (d) {
+            case 41.0: {
+                throw new AssertionError("Broken");
+            }
+            case 42.0: {
+                message();
+                break;
+            }
+        }
+
+        switch (d) {
+            case 42.0: {
+                message();
+                break;
+            }
+            case 41.0: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        switch (d) {
+            case 42.0: {
+                message();
+                break;
+            }
+            case 41.0: {
+                throw new AssertionError("Broken");
+            }
+            default: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        switch (d) {
+            case 41.0: {
+                throw new AssertionError("Broken");
+            }
+            case 42.0: {
+                message();
+                break;
+            }
+            default: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        // Multiple constant expression pattern clauses
+
+        switch (d) {
+            case 41.0-1.0: {
+                throw new AssertionError("Broken");
+            }
+            case 42.0: {
+                message();
+            }
+        }
+
+//--- STRING TYPED CONSTANT EXPRESSIONS ----
+
+        String s = "Hello";
+        final String hello = "Hello";
+
+        // Simple literal constant pattern
+        if (s __matches "Hello") {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        // Simple constant expression pattern
+        if (s __matches "Hell"+"o") {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        // Constant expression pattern using a final local
+        if (s __matches hello) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        //--- Tests for match statement
+
+        // Simple literal constant pattern
+        switch (s) {
+            case "Hello": {
+                message();
+            }
+        }
+
+        // Simple constant expression pattern
+        switch (s) {
+            case "Hell"+"o": {
+                message();
+            }
+        }
+
+        // Constant expression pattern using a final local
+        switch (s) {
+            case hello: {
+                message();
+            }
+        }
+
+        // Multiple constant pattern clauses
+
+        switch (s) {
+            case "Hi": {
+                throw new AssertionError("Broken");
+            }
+            case "Hello": {
+                message();
+                break;
+            }
+        }
+
+        switch (s) {
+            case "Hello": {
+                message();
+                break;
+            }
+            case "Hi": {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        switch (s) {
+            case "Hello": {
+                message();
+                break;
+            }
+            case "Hi": {
+                throw new AssertionError("Broken");
+            }
+            default: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        switch (s) {
+            case "Hi": {
+                throw new AssertionError("Broken");
+            }
+            case "Hello": {
+                message();
+                break;
+            }
+            default: {
+                throw new AssertionError("Broken");
+            }
+        }
+
+        // Multiple constant expression pattern clauses
+
+        switch (s) {
+            case "Hello"+"-": {
+                throw new AssertionError("Broken");
+            }
+            case "Hello": {
+                message();
+                break;
+            }
+        }
+
+        // Constant expression and a var pattern of the same type
+
+
+        switch(s){
+            case "Hello ": {
+                throw new AssertionError("Broken");
+            }
+            case String s1: {
+                message();
+            }
+        }
+
+        switch(s){
+            case "Hello": {
+                message();
+                break;
+            }
+            case String s1: {
+                throw new AssertionError("Broken");
+            }
+        }
+// ----- Constant expression patterns and reference typed expressions
+
+        Object obj = "Hello";
+
+        if (obj __matches "Hello") {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+        if (obj __matches null) {
+            throw new AssertionError("Broken");
+        }
+        obj = 42;
+        if (obj __matches 42) {
+            message();
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        if (obj __matches var x) {
+            if (obj __matches 42) {
+                message();
+            } else {
+                throw new AssertionError("Broken");
+            }
+        } else {
+            throw new AssertionError("Broken");
+        }
+
+        if (obj __matches 42) {
+            if (obj __matches var x) {
+                message();
+            }
+        }
+        if (obj __matches null) {
+            throw new AssertionError("Broken");
+        }
+        if (null __matches "Hello") {
+            throw new AssertionError("Broken");
+        }
+
+
+        fortyTwoTester(42);
+        fortyTwoTester(42.0);
+        fortyTwoTester("42");
+        fortyTwoTester(42L);
+        fortyTwoTester(true);
+        fortyTwoTester('4');
+        fortyTwoTester('x');
+        fortyTwoTester(0x2a);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DefaultClauseMustBeLast.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Ensure that in a matching switch statement, the default clause must be the last.
+ * @compile/fail/ref=DefaultClauseMustBeLast.out -XDrawDiagnostics DefaultClauseMustBeLast.java
+ */
+public class DefaultClauseMustBeLast {
+    public static void main(String[] args) {
+        Object o = (Long)42L;
+        switch (o) {
+            default: System.out.println("default"); break;
+            case Long l: System.out.println("It's a long"); break;
+        }
+        switch (o) {
+            case Long l: System.out.println("It's a long"); break;
+            default : System.out.println("default"); break;
+            case Double d: System.out.println("It's a double"); break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DefaultClauseMustBeLast.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,3 @@
+DefaultClauseMustBeLast.java:11:13: compiler.err.pattern.dominated
+DefaultClauseMustBeLast.java:16:13: compiler.err.pattern.dominated
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,30 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Basic pattern bindings scope test
+ * @compile/fail/ref=DuplicateBindingTest.out -XDrawDiagnostics DuplicateBindingTest.java
+ */
+
+public class DuplicateBindingTest {
+
+    int f;
+
+    public static void main(String[] args) {
+
+        if (args != null) {
+            int s;
+            if (args[0] __matches String s) { // NOT OK. Redef same scope.
+            }
+            int k;
+            switch(args[0]) {
+                case String k: // NOT OK: Redef outer scope.
+                    break;
+                case var args: // NOT OK: Redef outer scope.
+                    break;
+                case Integer f: // OK to redef field, but BAD type.
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,5 @@
+DuplicateBindingTest.java:15:35: compiler.err.already.defined: kindname.variable, s, kindname.method, main(java.lang.String[])
+DuplicateBindingTest.java:19:22: compiler.err.already.defined: kindname.variable, k, kindname.method, main(java.lang.String[])
+DuplicateBindingTest.java:21:22: compiler.err.already.defined: kindname.variable, args, kindname.method, main(java.lang.String[])
+DuplicateBindingTest.java:18:19: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateConstantPatternTests.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Checking for duplicate constant patterns test
+ * @compile/fail/ref=DuplicateConstantPatternTests.out -XDrawDiagnostics DuplicateConstantPatternTests.java
+ */
+
+public class DuplicateConstantPatternTests {
+
+    public static void main(String[] args) {
+        int i = 47;
+        switch (i) {
+            case 45: throw new AssertionError("broken");
+            case 45: throw new AssertionError("broken");
+        }
+
+        switch (i) {
+            case 45: throw new AssertionError("broken");
+            case 44+1: throw new AssertionError("broken");
+        }
+
+        switch (i) {
+            case 45: throw new AssertionError("broken");
+            case 46-1: throw new AssertionError("broken");
+            default: System.out.println("Default");
+        }
+
+        Object o = "hello";
+        switch (o) {
+            case null: throw new AssertionError("broken");
+            case null: throw new AssertionError("broken");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateConstantPatternTests.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,5 @@
+DuplicateConstantPatternTests.java:13:13: compiler.err.duplicate.case.label
+DuplicateConstantPatternTests.java:18:13: compiler.err.duplicate.case.label
+DuplicateConstantPatternTests.java:23:13: compiler.err.duplicate.case.label
+DuplicateConstantPatternTests.java:30:13: compiler.err.duplicate.case.label
+4 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+   @bug 8187420
+ * @summary Error message mentions relevant types transposed
+ * @compile/fail/ref=EnsureTypesOrderTest.out -XDrawDiagnostics EnsureTypesOrderTest.java
+ */
+public class EnsureTypesOrderTest {
+    public static void main(String [] args) { 
+        if (args __matches String s) { 
+            System.out.println("Broken"); 
+        } 
+    } 
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,2 @@
+EnsureTypesOrderTest.java:9:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String[], java.lang.String)
+1 error
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ErasureDominationTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8187428
+ * @summary javac fails to reject dominated pattern with the same erased type
+ * @compile/fail/ref=ErasureDominationTest.out -XDrawDiagnostics ErasureDominationTest.java
+ */
+import java.util.ArrayList;
+
+public class ErasureDominationTest {
+    public static void main(String [] args) {
+        Object o = new ArrayList<ErasureDominationTest>();
+        switch (o) {
+            case ArrayList<Integer> ai:
+                System.out.println("ArrayList<Integer>");
+                break;
+            case ArrayList<String> as:
+                System.out.println("ArrayList<String>");
+                break;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ErasureDominationTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,4 @@
+ErasureDominationTest.java:16:13: compiler.err.pattern.dominated
+- compiler.note.unchecked.filename: ErasureDominationTest.java
+- compiler.note.unchecked.recompile
+1 error
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ExamplesFromProposal.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,210 @@
+/*
+ * @test
+ * @summary All example code from "Pattern Matching for Java" document, released April 2017 (with switch renamed as match)
+ * @compile ExamplesFromProposal.java
+ * @run main ExamplesFromProposal
+ */
+
+interface Node {
+}
+
+class IntNode implements Node {
+    int value;
+
+    IntNode(int value) {
+        this.value = value;
+    }
+}
+
+class NegNode implements Node {
+    Node node;
+
+    NegNode(Node node) {
+        this.node = node;
+    }
+}
+
+class MulNode implements Node {
+    Node left, right;
+
+    MulNode(Node left, Node right) {
+        this.left = left;
+        this.right = right;
+    }
+}
+
+class AddNode implements Node {
+    Node left, right;
+
+    AddNode(Node left, Node right) {
+        this.left = left;
+        this.right = right;
+    }
+}
+
+public class ExamplesFromProposal {
+
+    public static Object getSomething() {
+        return new Long(42);
+    }
+
+    public static int eval(Node n) {
+        switch (n) {
+            case IntNode in: return in.value;
+            case NegNode nn: return -eval(nn.node);
+            case AddNode an: return eval(an.left) + eval(an.right);
+            case MulNode mn: return eval(mn.left) * eval(mn.right);
+        };
+        // should never happen
+        throw new AssertionError("broken");
+    }
+
+    public static String toString(Node n) {
+        switch (n) {
+            case IntNode in: return String.valueOf(in.value);
+            case NegNode nn: return "-"+eval(nn.node);
+            case AddNode an: return eval(an.left) + " + " + eval(an.right);
+            case MulNode mn: return eval(mn.left) + " * " + eval(mn.right);
+        };
+        // should never happen
+        throw new AssertionError("broken");
+    }
+
+    public static Node simplify(Node n) {
+        switch (n) {
+            case IntNode in:
+                return n;
+
+            case NegNode nn:
+                return new NegNode(simplify(nn.node));
+
+            case AddNode ad: switch (simplify(ad.left)) {
+                case IntNode intn:
+                    if (intn.value == 0)
+                        return simplify(ad.right);
+                    else
+                        return new AddNode(intn, simplify(ad.right));
+                default:
+                    return new AddNode(simplify(ad.left), simplify(ad.right));
+            }
+
+            case MulNode mn:
+                return new MulNode(simplify(mn.left), simplify(mn.right));
+        }
+        //should never happen
+        throw new AssertionError("broken");
+    }
+
+    public static void testNode(Node n, int expected) {
+        if (eval(n) != expected)
+            throw new AssertionError("broken");
+    }
+
+    public static void main(String[] args) {
+        Object x = new Integer(42);
+
+        if (x __matches Integer i) {
+            // can use i here
+            System.out.println(i.intValue());
+        }
+
+        Object obj = getSomething();
+
+        String formatted = "unknown";
+        if (obj __matches Integer i) {
+            formatted = String.format("int %d", i);
+        }
+        else if (obj __matches Byte b) {
+            formatted = String.format("byte %d", b);
+        }
+        else if (obj __matches Long l) {
+            formatted = String.format("long %d", l);
+        }
+        else if (obj __matches Double d) {
+            formatted = String.format("double %f", d);
+        }
+        else if (obj __matches String s) {
+            formatted = String.format("String %s", s);
+        }
+        System.out.println(formatted);
+
+        formatted="";
+        switch (obj) {
+            case Integer i: formatted = String.format("int %d", i); break;
+            case Byte b:    formatted = String.format("byte %d", b); break;
+            case Long l:    formatted = String.format("long %d", l); break;
+            case Double d:  formatted = String.format("double %f", d); break;
+            case String s:  formatted = String.format("String %s", s); break;
+            default:        formatted = String.format("Something else "+ obj.toString()); break;
+        }
+        System.out.println(formatted);
+
+        // Rewritten from an expression switch
+        String s="";
+        short srt = 100;
+        int num = (int)srt;
+
+        switch (num) {
+            case 0: s = "zero"; break;
+            case 1: s = "one"; break;
+        //    case int i: s = "some other integer";
+            default: s = "not an Integer"; break;
+        }
+        System.out.println(s);
+
+
+        Node zero = new IntNode(0);
+        Node one = new IntNode(1);
+        Node ft = new IntNode(42);
+
+        Node temp = new AddNode(zero,ft);
+
+        testNode(temp,42);
+
+
+
+        if (toString(simplify(temp)).equals(toString(ft)))
+            System.out.println("Simplify worked!");
+        else
+            throw new AssertionError("broken");
+
+
+        if (toString(simplify(new AddNode(zero,temp))).equals(toString(ft)))
+            System.out.println("Simplify worked!");
+        else
+            throw new AssertionError("broken");
+
+
+        temp = new AddNode(zero,ft);
+        temp = new AddNode(one,temp);
+        temp = new AddNode(zero,temp);
+
+        Node fortythree = new AddNode(one,ft);
+
+        if (toString(simplify(temp)).equals(toString(fortythree)))
+            System.out.println("Simplify worked!");
+        else
+            throw new AssertionError("broken");
+
+
+        x = "Hello";
+
+        if (x __matches String s1) {
+            System.out.println(s1);
+        }
+        if (x __matches String s1 && s1.length() > 0) {
+            System.out.println(s1);
+        }
+        if (x __matches String s1) {
+            System.out.println(s1 + " is a string");
+        } else {
+            System.out.println("not a string");
+        }
+
+        if (!(x __matches String s1)) {
+            System.out.println("not a string");
+        } else {
+            System.out.println(s1 + " is a string");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/FlowAnalysisAndConstantPatterns.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Stress test flow analysis with constant patterns
+ * @compile/fail/ref=FlowAnalysisAndConstantPatterns.out -XDrawDiagnostics FlowAnalysisAndConstantPatterns.java
+ */
+public class FlowAnalysisAndConstantPatterns {
+    public static int getInt(){
+        return 43;
+    }
+    public static void main(String[] args) {
+        int i = getInt();
+        switch (i) {
+            case int j: System.out.println("it's an int!"); break;
+            case 42: System.out.println("42!"); break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/FlowAnalysisAndConstantPatterns.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,2 @@
+FlowAnalysisAndConstantPatterns.java:14:13: compiler.err.pattern.dominated
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/FlowAnalysisAndConstantPatterns2.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,35 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Stress test flow analysis with constant patterns
+ * @compile/fail/ref=FlowAnalysisAndConstantPatterns2.out -XDrawDiagnostics FlowAnalysisAndConstantPatterns2.java
+ */
+public class FlowAnalysisAndConstantPatterns2 {
+    public static int getInt(){
+        return 42;
+    }
+    public static void main(String[] args) {
+
+        int i = getInt();
+        switch (i) {
+            case 42+1: System.out.println("42+1!");
+            case 43: System.out.println("43!");
+        }
+
+        switch (i) {
+            case 43: System.out.println("43!");
+            case 42+1: System.out.println("42+1!");
+        }
+
+        switch (i) {
+            case 43: System.out.println("43!");
+            case 42+1: System.out.println("42+1!");
+            case int j: System.out.println("it's an int!");
+        }
+
+        switch (i) {
+            case 43: System.out.println("43!");
+            case int j: System.out.println("it's an int!");
+            case 42+1: System.out.println("42+1!");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/FlowAnalysisAndConstantPatterns2.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,5 @@
+FlowAnalysisAndConstantPatterns2.java:15:13: compiler.err.duplicate.case.label
+FlowAnalysisAndConstantPatterns2.java:20:13: compiler.err.duplicate.case.label
+FlowAnalysisAndConstantPatterns2.java:25:13: compiler.err.duplicate.case.label
+FlowAnalysisAndConstantPatterns2.java:32:13: compiler.err.duplicate.case.label
+4 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/FlowAnalysisTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,20 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Stress test flow analysis with patterns
+ * @compile/fail/ref=FlowAnalysisTest.out -XDrawDiagnostics FlowAnalysisTest.java
+ */
+
+class FlowAnalysisTest {
+    void foo(Object object) {
+        
+        switch (object) {
+            case Object o: break;
+            case String s: break;
+        }
+        switch (object) {
+            case var o: break;
+            case String s: break;
+            case "Hello" : break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/FlowAnalysisTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,4 @@
+FlowAnalysisTest.java:12:13: compiler.err.pattern.dominated
+FlowAnalysisTest.java:16:13: compiler.err.pattern.dominated
+FlowAnalysisTest.java:17:13: compiler.err.pattern.dominated
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,20 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Ensure that in type test patterns, the predicate is not trivially provable false.
+ * @compile/fail/ref=ImpossibleTypeTest.out -XDrawDiagnostics ImpossibleTypeTest.java
+ */
+public class ImpossibleTypeTest {
+
+    public static void main(String[] args) {
+
+        int in = 42;
+        Integer i = 42;
+
+        if (i __matches String s ) {
+            System.out.println("Broken");
+        }
+        if (i __matches Undefined u ) {
+            System.out.println("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,3 @@
+ImpossibleTypeTest.java:13:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.String)
+ImpossibleTypeTest.java:16:25: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, ImpossibleTypeTest, null)
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Basic pattern bindings scope test
+ * @compile/fail/ref=MatchBindingScopeTest.out -XDrawDiagnostics MatchBindingScopeTest.java
+ */
+public class MatchBindingScopeTest {
+
+    static Integer i = 42;
+    static String s = "Hello";
+    static Object o1 = s;
+    static Object o2 = i;
+
+    public static void main(String[] args) {
+    
+        if (o1 __matches String j && j.length() == 5) { // OK
+            System.out.println(j); // OK
+        } else {
+            System.out.println(j); // NOT OK
+        }
+
+        // NOT OK, name reused.
+        if (o1 __matches String j && o2 __matches Integer j) {
+        }
+
+        if (o1 __matches String j && j.length() == 5 && o2 __matches Integer k && k == 42) { // OK
+            System.out.println(j); // OK
+            System.out.println(k); // OK
+        } else {
+            System.out.println(j); // NOT OK
+            System.out.println(k); // NOT OK
+        }
+
+        if (o1 __matches String j || j.length() == 5) { // NOT OK
+            System.out.println(j); // NOT OK
+        }
+
+        if (o1 __matches String j || o2 __matches Integer j) { // NOT OK, types differ
+            System.out.println(j); // NOT OK
+        } else {
+            System.out.println(j); // NOT OK.
+        }
+
+        while (o1 __matches String j && j.length() == 5) { // OK
+            System.out.println(j); // OK
+        }
+
+        while (o1 __matches String j || true) {
+            System.out.println(j); // Not OK
+        }
+
+        for (; o1 __matches String j; j.length()) { // OK
+            System.out.println(j); // OK
+        }
+
+        for (; o1 __matches String j || true; j.length()) { // NOT OK
+            System.out.println(j); // Not OK
+        }
+
+        switch (o1) {
+            case String x:
+                    x.length(); // OK.
+                    break;
+            default:
+                    x.length(); // NOT OK.
+                    break;
+        }
+
+        int x = o1 __matches String j ?
+                      j.length() : // OK.
+                      j.length();  // NOT OK.
+
+        x = !(o1 __matches String j) ?
+                      j.length() : // NOT OK.
+                      j.length();  // OK.
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,17 @@
+MatchBindingScopeTest.java:18:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:22:51: compiler.err.already.defined: kindname.variable, j, kindname.method, main(java.lang.String[])
+MatchBindingScopeTest.java:22:35: compiler.err.match.binding.exists
+MatchBindingScopeTest.java:29:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:30:32: compiler.err.cant.resolve.location: kindname.variable, k, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:33:38: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:34:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:37:35: compiler.err.match.binding.exists.with.different.type
+MatchBindingScopeTest.java:38:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:40:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:48:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:55:47: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:56:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:64:21: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:70:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:73:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+16 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchStmtTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic positive test for match statement
+ * @compile MatchStmtTest.java
+ * @run main MatchStmtTest
+ */
+
+public class MatchStmtTest {
+
+    static Integer i = 42;
+    static String output = "";
+
+    public static void main(String[] args) {
+
+        String s = "Hello";
+        Object o = s;
+
+        match(s);
+        match(i);
+
+        if (i != 152) {
+            throw new AssertionError("Broken");
+        }
+        if (!output.equals("String Integer"))
+            throw new AssertionError("Broken");
+
+    }
+    private static void match (Object o) {
+        switch (o) {
+            case String j:
+                i += 10;
+                output += "String ";
+                System.out.println("String length = " + j.length());
+                break;
+            case Integer k:
+                i += 100;
+                output += "Integer";
+                System.out.println("Int value = " + k);
+                break;
+            default:
+                i += 1000;
+                System.out.println("Broken !!!");
+                break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchesToken.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,27 @@
+/**
+ * @test
+ * @compile MatchesToken.java
+ */
+public class MatchesToken {
+    public void test(Object o) {
+        final int __matches = 1;
+        boolean b1 = __matches __matches __matches;
+        boolean b2 = o __matches __matches;
+        boolean b3 = __matches __matches Integer i;
+        boolean b4 = (__matches __matches __matches) __matches true;
+    }
+
+    private void test() {
+        I1 i1 = (int __matches) -> {};
+        I2 i2 = (int __matches, int other) -> {};
+    }
+
+    interface I1 {
+        public void m(int i);
+    }
+
+    interface I2 {
+        public void m(int i1, int i2);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/NestingMatchAndMatches.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,120 @@
+/*
+ * @test
+ * @summary testing various permutations of matches insides match etc.
+ * @compile NestingMatchAndMatches.java
+ * @run main NestingMatchAndMatches
+ */
+public class NestingMatchAndMatches {
+
+    public static void main(String[] args) {
+
+        Object o = "Hello";
+
+        //Nested matches
+        if ((o __matches String s) __matches boolean b) {
+            System.out.println("String!");
+        } else {
+            throw new AssertionError("broken");
+        }
+        if ((o __matches String s) __matches false) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("String ");
+        }
+
+        if ((o __matches String s) __matches true) {
+            System.out.println("String!");
+        } else {
+            throw new AssertionError("broken");
+        }
+
+        boolean b = (o __matches String s) ? (s __matches "Hello") : false;
+
+        if (b) {
+            System.out.println("yes!");
+        } else {
+            throw new AssertionError("broken");
+        }
+
+        //matches inside a match
+        switch (o) {
+            case String s:
+                if (s __matches String t) {
+                    System.out.println(s+"-"+t);
+                }
+        }
+        switch (o) {
+            case String s:
+                if (o __matches Integer t) {
+                    System.out.println(s+"-"+t);
+                    throw new AssertionError("broken");
+                } else {
+                    System.out.println(s);
+                }
+        }
+
+        //match inside a match
+        Object o2 = o;
+
+        switch (o) {
+            case String s:
+                switch (o2) {
+                    case String t:
+                        System.out.println(s+"-"+t);
+                        break;
+                }
+                break;
+        }
+        switch (o) {
+            case String s:
+                switch (o2) {
+                    case String t:
+                        System.out.println(s+"-"+t);
+                        break;
+                    default:
+                        throw new AssertionError("broken");
+                }
+                break;
+        }
+
+        switch (o) {
+            case String s:
+                switch (o2) {
+                    case Integer in:
+                        throw new AssertionError("broken");
+                    case String t:
+                        System.out.println(s+"-"+t);
+                        break;
+                }
+                break;
+        }
+        switch (o) {
+            case String s:
+                switch (o2) {
+                    case Integer in:
+                        throw new AssertionError("broken");
+                    case String t:
+                        System.out.println(s+"-"+t);
+                        break;
+                    default:
+                        throw new AssertionError("broken");
+                }
+                break;
+        }
+        //matches inside a match inside a match
+
+        switch (o) {
+            case String s:
+                switch (o2) {
+                    case String t:
+                        if (t __matches String u) {
+                            System.out.println(s+"-"+t+"--"+u);
+                        } else {
+                            throw new AssertionError("broken");
+                        }
+                }
+                break;
+        }
+        System.out.println("> Test completed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/NullPatternTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,24 @@
+/*
+ * @test
+ * @summary Basic positive test for match statement
+ * @compile NullPatternTest.java
+ * @run main NullPatternTest
+ */
+
+public class NullPatternTest {
+    public static void main(String[] args) {
+        Object o = "Hello world";
+        switch (o) {
+            case null: throw new AssertionError("broken");
+            case String s : System.out.println("String"); break;
+            default: throw new AssertionError("broken");
+        }
+
+        o = null;
+
+        switch (o) {
+            case null: System.out.println("null"); break;
+            default: throw new AssertionError("broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/NullsInPatterns.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Testing pattern matching against the null constant
+ * @run main NullsInPatterns
+ */
+import java.util.List;
+
+public class NullsInPatterns {
+    
+    public static void main(String[] args) {
+        if (null __matches List t) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List type pattern");
+        }
+        if (null __matches List<Integer> l) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List<Integer> type pattern");
+        }
+        if (null __matches List<?> l) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List<?> type pattern");
+        }
+        if (null __matches var x) {
+            System.out.println("null matches var type pattern");
+        } else {
+            throw new AssertionError("broken");
+        }
+        if (null __matches null) {
+            System.out.println("null matches null constant pattern");
+        } else {
+            throw new AssertionError("broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Check proper positions.
+ * @build PatternMatchPosTest
+ * @compile/ref=PatternMatchPosTest.out -processor PatternMatchPosTest -Xlint:unchecked PatternMatchPosTest.java
+ */
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.IfTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreeScanner;
+import com.sun.source.util.Trees;
+
+@SupportedAnnotationTypes("*")
+public class PatternMatchPosTest extends AbstractProcessor {
+
+    int round;
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (round++ != 0)
+            return false;
+
+        try {
+            TypeElement data = processingEnv.getElementUtils().getTypeElement("PatternMatchPosTestData");
+            Trees trees = Trees.instance(processingEnv);
+            SourcePositions sp = trees.getSourcePositions();
+            TreePath dataPath = trees.getPath(data);
+            String text = dataPath.getCompilationUnit().getSourceFile().getCharContent(true).toString();
+            
+            new TreeScanner<Void, Void>() {
+                boolean print;
+                @Override
+                public Void visitIf(IfTree node, Void p) {
+                    boolean prevPrint = print;
+                    try {
+                        print = true;
+                        scan(node.getCondition(), p);
+                    } finally {
+                        print = prevPrint;
+                    }
+                    scan(node.getThenStatement(), p);
+                    scan(node.getElseStatement(), p);
+                    return null;
+                }
+
+                @Override
+                public Void visitCase(CaseTree node, Void p) {
+                    boolean prevPrint = print;
+                    try {
+                        print = true;
+                        scan(node.getPatterns(), p);
+                    } finally {
+                        print = prevPrint;
+                    }
+                    scan(node.getStatements(), p);
+                    return null;
+                }
+                @Override
+                public Void scan(Tree tree, Void p) {
+                    if (tree == null)
+                        return null;
+                    if (print) {
+                        int start = (int) sp.getStartPosition(dataPath.getCompilationUnit(), tree);
+                        int end = (int) sp.getEndPosition(dataPath.getCompilationUnit(), tree);
+                        System.out.println(text.substring(start, end));
+                    }
+                    return super.scan(tree, p);
+                }
+            }.scan(dataPath.getLeaf(), null);
+            return false;
+        } catch (IOException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latestSupported();
+    }
+
+}
+
+class PatternMatchPosTestData {
+    void data(Object o) {
+        if (o __matches 1) { }
+        if (o __matches var s) { }
+        if (o __matches String s) { }
+        switch (o) {
+            case 1: break;
+            case String s: break;
+            case var s: break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,19 @@
+(o __matches 1)
+o __matches 1
+o
+1
+1
+(o __matches var s)
+o __matches var s
+o
+var s
+(o __matches String s)
+o __matches String s
+o
+String s
+String
+1
+1
+String s
+String
+var s
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchTest1.java	Fri Oct 05 19:50:15 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
+ * @summary Basic pattern switch test
+ * @run main PatternMatchTest1
+ */
+public class PatternMatchTest1 {
+
+    public static void main(String[] args) {
+
+        Integer i = 42;
+        String s = "Hello";
+        Object o = i;
+
+        switch (o) {
+            case var j: {
+                System.out.println("Matches a var!");
+                i++;
+                break;
+            }
+            default:
+                throw new AssertionError("Broken");
+        }
+
+        switch (o) {
+            case String j:
+                throw new AssertionError("Broken");
+            default:
+                System.out.println("Good");
+                i++;
+                break;
+        }
+        if (i != 44) {
+            throw new AssertionError("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchTest2.java	Fri Oct 05 19:50:15 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
+ * @summary Basic pattern switch test
+ * @run main PatternMatchTest2
+ */
+public class PatternMatchTest2 {
+
+    public static void main(String[] args) {
+
+        Integer i = 42;
+        String s = "Hello";
+        Object o = i;
+
+        switch (o) {
+            case Integer j: {
+                System.out.println("Matches a var!");
+                i++;
+                break;
+            }
+            default:
+                throw new AssertionError("Broken");
+        }
+
+        switch (o) {
+            case String j:
+                throw new AssertionError("Broken");
+            default:
+                System.out.println("Good");
+                i++;
+                break;
+        }
+        if (i != 44) {
+            throw new AssertionError("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternTypeTest1.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic pattern test
+ * @run main PatternTypeTest1
+ */
+public class PatternTypeTest1 {
+
+    public static void main(String[] args) {
+
+        Integer i = 42;
+        String s = "Hello";
+        Object o = i;
+
+        if (o __matches var j) {
+            System.out.println("Match all");
+        } else {
+            throw new AssertionError("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternTypeTest2.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic pattern test
+ * @run main PatternTypeTest2
+ */
+public class PatternTypeTest2 {
+
+    public static void main(String[] args) {
+
+        Integer i = 42;
+        String s = "Hello";
+        Object o = i;
+
+        if (o __matches Integer j) {
+            System.out.println("It's an Integer");
+        } else {
+            throw new AssertionError("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,24 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Ensure that in type test patterns, the predicate is not trivially provable false.
+ * @compile/fail/ref=PatternVariablesAreFinal.out -XDrawDiagnostics PatternVariablesAreFinal.java
+ */
+public class PatternVariablesAreFinal {
+    public static void main(String[] args) {
+        Object o = 32;
+        if (o __matches String s) {
+            s = "hello again";
+            System.out.println(s);
+        }
+        switch (o) {
+            case Integer i: i++; break;
+        }
+        int i = 42;
+        i++;
+        switch (o) {
+            case String s: break;
+            case Integer s: s = null; break;
+        }
+        System.out.println("test complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,4 @@
+PatternVariablesAreFinal.java:10:13: compiler.err.pattern.binding.may.not.be.assigned: s
+PatternVariablesAreFinal.java:14:29: compiler.err.pattern.binding.may.not.be.assigned: i
+PatternVariablesAreFinal.java:20:29: compiler.err.pattern.binding.may.not.be.assigned: s
+3 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal2.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,15 @@
+/*
+ * @test
+ * @summary Pattern variables are final so should be allowed to be referenced in an inner class
+ * @run main PatternVariablesAreFinal2
+ */
+public class PatternVariablesAreFinal2 {
+    public static void main(String[] args) {
+        Object o = "42";
+        if (o __matches String s) {
+            new Object() {
+                void run() { System.err.println(s); }
+            }.run();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PrimitiveSelectorTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test match behavior with primitive selector
+ * @compile PrimitiveSelectorTest.java
+ * @run main PrimitiveSelectorTest
+ */
+
+public class PrimitiveSelectorTest {
+    public static void main(String [] args) {
+        boolean worked;
+        double d = 0.0;
+        switch (d) {
+            case double d2:
+                worked = true;
+                break;
+            default:
+                worked = false;
+                break;
+		}
+        if (!worked)
+            throw new AssertionError("Unexpected control flow");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/SwitchExpressionWithPatterns.java	Fri Oct 05 19:50:15 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
+ * @summary Basic test for patterns in switch expression
+ * @compile --enable-preview -source 12 SwitchExpressionWithPatterns.java
+ * @run main/othervm --enable-preview SwitchExpressionWithPatterns
+ */
+
+import java.util.List;
+import java.util.function.ToIntFunction;
+
+public class SwitchExpressionWithPatterns {
+
+    public static void main(String[] args) {
+        List<ToIntFunction<Object>> tests = List.of(
+            SwitchExpressionWithPatterns::test1,
+            SwitchExpressionWithPatterns::test2,
+            SwitchExpressionWithPatterns::test3,
+            SwitchExpressionWithPatterns::test4
+        );
+        for (ToIntFunction<Object> f : tests) {
+            assertEquals(2, f.applyAsInt(41));
+            assertEquals(1, f.applyAsInt((Integer) 42));
+            assertEquals(3, f.applyAsInt((long) 0));
+            assertEquals(3, f.applyAsInt((float) 0));
+            assertEquals(4, f.applyAsInt((byte) 13));
+        }
+    }
+
+    private static int test1(Object in) {
+        int check = 0;
+        return switch (in) {
+            case 41: check++; //fall-through
+            case Integer i: check++; break check;
+            case Long l, Float f: break 3;
+            default: break 4;
+        };
+
+    }
+
+    private static int test2(Object in) {
+        int check = 0;
+        return switch (in) {
+            case 41 -> 2;
+            case Integer j -> { break 1; }
+            case Long l, Float f -> 3;
+            default -> { break 4; }
+        };
+    }
+
+    private static int test3(Object in) {
+        int check = 0;
+        switch (in) {
+            case 41: check++; //fall-through
+            case Integer j: check++; break;
+            case Long l, Float f: check = 3; break;
+            default: check = 4; break;
+        }
+        return check;
+    }
+
+    private static int test4(Object in) {
+        int check = 0;
+        switch (in) {
+            case 41 -> check = 2;
+            case Integer j -> { check = 1; }
+            case Long l, Float f -> check = 3;
+            default -> { check = 4; }
+        };
+        return check;
+    }
+
+    private static void assertEquals(int expected, int actual) {
+        if (expected != actual)
+            throw new AssertionError("Expected: " + expected + ", actual: " + actual);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/SwitchFallThrough1.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic test for fall through in switch
+ * @compile SwitchFallThrough1.java
+ * @run main SwitchFallThrough1
+ */
+public class SwitchFallThrough1 {
+
+    public static void main(String[] args) {
+        int check;
+        Object i = 42;
+
+        check = 0;
+
+        switch (i) {
+            case 41: check++; //fall-through
+            case Integer j: check++; break;
+        }
+
+        if (check != 1) {
+            throw new AssertionError("Incorrect check value: " + check);
+        }
+
+        check = 0;
+
+        switch (i) {
+            case 42: check++; //fall-through
+            case Integer j: check++; break;
+        }
+
+        if (check != 2) {
+            throw new AssertionError("Incorrect check value: " + check);
+        }
+
+        check = 0;
+
+        switch (i) {
+            case Integer j: check++; break;
+            case String  j: check = 45; break; //legal?
+        }
+
+        if (check != 1) {
+            throw new AssertionError("Incorrect check value: " + check);
+        }
+
+        check = 0;
+
+        switch (i) {
+            case 41: check++;
+            case Integer j: check++;
+            case "": check++; break;
+        }
+
+        if (check != 2) {
+            throw new AssertionError("Incorrect check value: " + check);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/SwitchFallThrough2.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Basic test for fall through in switch
+ * @compile/fail/ref=SwitchFallThrough2.out -XDrawDiagnostics -XDshould-stop.at=FLOW SwitchFallThrough2.java
+ */
+public class SwitchFallThrough2 {
+
+    public static void main(String[] args) {
+        Object i = 42;
+
+        switch (i) {
+            case Integer j: System.err.println(j); //fall-through
+            case 41: System.err.println(j); break;
+        }
+
+        switch (i) {
+            case 41: System.err.println(j); //fall-through
+            case Integer j: System.err.println(j); break;
+        }
+
+        switch (i) {
+            case Integer j: System.err.println(j); //fall-through
+            case String j: System.err.println(j); break;
+        }
+
+        switch (i) {
+            case Integer j:
+            case Integer j: break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/SwitchFallThrough2.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,8 @@
+SwitchFallThrough2.java:36:41: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, SwitchFallThrough2, null)
+SwitchFallThrough2.java:40:41: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, SwitchFallThrough2, null)
+SwitchFallThrough2.java:41:48: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, SwitchFallThrough2, null)
+SwitchFallThrough2.java:46:18: compiler.err.match.binding.exists.with.different.type
+SwitchFallThrough2.java:46:47: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, SwitchFallThrough2, null)
+SwitchFallThrough2.java:36:13: compiler.err.pattern.dominated
+SwitchFallThrough2.java:51:13: compiler.err.pattern.dominated
+7 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,23 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8187429
+ * @summary Missing unchecked conversion warning
+ * @compile/fail/ref=UncheckedWarningOnMatchesTest.out -Xlint:unchecked -Werror -XDrawDiagnostics UncheckedWarningOnMatchesTest.java
+ */
+import java.util.ArrayList;
+
+public class UncheckedWarningOnMatchesTest {
+
+    public static void main(String [] args) {
+
+        Object o = new ArrayList<UncheckedWarningOnMatchesTest>();
+        if (o __matches ArrayList<Integer> ai) {  // unchecked conversion
+            System.out.println("Blah");
+        }
+        switch (o) {
+            case ArrayList<Integer> ai:  // unchecked conversion
+                System.out.println("ArrayList<Integer>");
+                break;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,5 @@
+UncheckedWarningOnMatchesTest.java:14:13: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), java.lang.Object, java.util.ArrayList<java.lang.Integer>
+UncheckedWarningOnMatchesTest.java:17:16: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), java.lang.Object, java.util.ArrayList<java.lang.Integer>
+- compiler.err.warnings.and.werror
+1 error
+2 warnings
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UnreachableCasesTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,31 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Ensure that unreachable cases of a pattern switch are diagnosed.
+ * @compile/fail/ref=UnreachableCasesTest.out -XDrawDiagnostics UnreachableCasesTest.java
+ */
+
+public class UnreachableCasesTest {
+
+    class X {}
+    class Y extends X {}
+    class Z extends Y {}
+
+    public static void main(String [] args) {
+
+        switch (10) {
+            case Integer i:
+                System.out.println("i = " + i);
+                break;
+            default:
+                System.out.println("Unreachable");
+                break;
+        }
+
+        Y y = null;
+        switch (y) {
+            case Z z1: break;
+            case Y y1: break;
+            case X x1: break;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UnreachableCasesTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,2 @@
+UnreachableCasesTest.java:28:13: compiler.err.pattern.dominated
+1 error
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UnreachableStatementInMatchClause.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,20 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Ensure that unreachable statements in match clauses are detected corrected.
+ * @compile/fail/ref=UnreachableStatementInMatchClause.out -XDrawDiagnostics UnreachableStatementInMatchClause.java
+ */
+public class UnreachableStatementInMatchClause {
+    public static void main(String[] args) {
+        Object o = "Hello world";
+        switch (o) {
+            case String s:
+                System.out.println(s);
+                break;
+                throw new AssertionError("oops");
+            default:
+                System.out.println("hmm");
+                break;
+                throw new AssertionError("oops once more");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UnreachableStatementInMatchClause.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,3 @@
+UnreachableStatementInMatchClause.java:13:17: compiler.err.unreachable.stmt
+UnreachableStatementInMatchClause.java:17:17: compiler.err.unreachable.stmt
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/VoidTest.java	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,11 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Ensure that void expressions passed to switch statement are rejected
+ * @compile/fail/ref=VoidTest.out -XDrawDiagnostics VoidTest.java
+ */
+public class VoidTest {
+    public static void test() {
+        switch (test()) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/VoidTest.out	Fri Oct 05 19:50:15 2018 +0200
@@ -0,0 +1,2 @@
+VoidTest.java:8:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: void, int)
+1 error