changeset 53705:bc7ce655824b amber-demo-II

Automatic merge with patterns-stage-1
author mcimadamore
date Thu, 29 Nov 2018 08:16:17 +0100
parents cf8bb0debfad 8927cb6ca12c
children 4b7f11a2072c
files
diffstat 55 files changed, 2450 insertions(+), 82 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	Thu Nov 29 08:16:17 2018 +0100
@@ -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.  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 binding pattern tree
+ */
+public interface BindingPatternTree extends PatternTree {
+
+    /**
+     * Returns the type of the bind variable.
+     * @return the type
+     */
+    Tree getType();
+
+    /**
+     * A binding variable name.
+     * @return something
+     */
+    Name getBinding();
+
+}
+
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java	Thu Nov 29 08:16:17 2018 +0100
@@ -51,4 +51,10 @@
      * @return the type
      */
     Tree getType();
+
+    /**
+     * Returns the tested pattern.
+     * @return the tested pattern
+     */
+    PatternTree getPattern();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,35 @@
+/*
+ * 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/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Thu Nov 29 08:16:17 2018 +0100
@@ -220,6 +220,11 @@
         PARENTHESIZED(ParenthesizedTree.class),
 
         /**
+         * Used for instances of {@link BindingPatternTree}.
+         */
+        BINDING_PATTERN(BindingPatternTree.class),
+
+        /**
          * Used for instances of {@link PrimitiveTypeTree}.
          */
         PRIMITIVE_TYPE(PrimitiveTypeTree.class),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Thu Nov 29 08:16:17 2018 +0100
@@ -258,6 +258,14 @@
     R visitLiteral(LiteralTree 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 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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Thu Nov 29 08:16:17 2018 +0100
@@ -566,6 +566,18 @@
      * @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 visitArrayAccess(ArrayAccessTree node, P p) {
         return defaultAction(node, p);
     }
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Thu Nov 29 08:16:17 2018 +0100
@@ -677,7 +677,11 @@
     @Override
     public R visitInstanceOf(InstanceOfTree node, P p) {
         R r = scan(node.getExpression(), p);
-        r = scanAndReduce(node.getType(), p, r);
+        if (node.getPattern() != null) {
+            r = scanAndReduce(node.getPattern(), p, r);
+        } else {
+            r = scanAndReduce(node.getType(), p, r);
+        }
         return r;
     }
 
@@ -689,6 +693,18 @@
      * @return the result of scanning
      */
     @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  {@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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Thu Nov 29 08:16:17 2018 +0100
@@ -319,6 +319,16 @@
      */
     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;
+
+    /**
+     * A flag to indicate a match binding variable whose scope extends after the current statement.
+     */
+    public static final long MATCH_BINDING_TO_OUTER = 1L<<59;
+
     /** Modifier masks.
      */
     public static final int
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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;
@@ -75,6 +76,8 @@
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
 import com.sun.tools.javac.comp.Analyzer.AnalyzerMode;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
 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));
             }
@@ -1315,28 +1320,76 @@
     public void visitDoLoop(JCDoWhileLoop tree) {
         attribStat(tree.body, env.dup(tree));
         attribExpr(tree.cond, env, syms.booleanType);
+        if (!breaksOutOf(tree, tree.body)) {
+            List<BindingSymbol> bindings = getMatchBindings(types, log, tree.cond, false);
+
+            bindings.forEach(env.info.scope::enter);
+            bindings.forEach(BindingSymbol::preserveBinding);
+        }
         result = null;
     }
 
     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();
+        }
+        if (!breaksOutOf(tree, tree.body)) {
+            List<BindingSymbol> bindings = getMatchBindings(types, log, tree.cond, false);
+
+            bindings.forEach(env.info.scope::enter);
+            bindings.forEach(BindingSymbol::preserveBinding);
+        }
         result = null;
     }
 
+    private boolean breaksOutOf(JCTree loop, JCTree body) {
+        //TODO: should correctly reflect liveness:
+        boolean[] breaksOut = new boolean[1];
+        new TreeScanner() {
+            @Override
+            public void visitBreak(JCBreak tree) {
+                breaksOut[0] |= tree.target == loop;
+                super.visitBreak(tree);
+            }
+        }.scan(body);
+
+        return breaksOut[0];
+    }
+
     public void visitForLoop(JCForLoop tree) {
         Env<AttrContext> loopEnv =
             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();
+            }
+            if (!breaksOutOf(tree, tree.body)) {
+                List<BindingSymbol> bindings = getMatchBindings(types, log, tree.cond, false);
+
+                bindings.forEach(env.info.scope::enter);
+                bindings.forEach(BindingSymbol::preserveBinding);
+            }
             result = null;
         }
         finally {
-            loopEnv.info.scope.leave();
+            loopEnv.info.scope.leave(); // all injected match bindings vanish here.
         }
     }
 
@@ -1688,8 +1741,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()),
@@ -1844,15 +1915,77 @@
         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
+
+        List<BindingSymbol> thenBindings = getMatchBindings(types, log, tree.cond, true);
+        Env<AttrContext> thenEnv = bindingEnv(env, thenBindings);
+
+        try {
+            attribStat(tree.thenpart, thenEnv);
+        } finally {
+            thenEnv.info.scope.leave();
+        }
+
+        preFlow(tree.thenpart);
+        boolean aliveAfterThen = flow.aliveAfter(env, tree.thenpart, make);
+        boolean aliveAfterElse;
+        List<BindingSymbol> elseBindings = List.nil();
+
+        if (tree.elsepart != null) {
+            elseBindings = getMatchBindings(types, log, tree.cond, false);
+
+            Env<AttrContext> elseEnv = bindingEnv(env, elseBindings);
+            try {
+                attribStat(tree.elsepart, elseEnv);
+            } finally {
+                elseEnv.info.scope.leave();
+            }
+            preFlow(tree.elsepart);
+            aliveAfterElse = flow.aliveAfter(env, tree.elsepart, make);
+        } else {
+            aliveAfterElse = true;
+        }
+
         chk.checkEmptyIf(tree);
+
+        List<BindingSymbol> afterIfBindings = List.nil();
+
+        if (aliveAfterThen && !aliveAfterElse) {
+            afterIfBindings = thenBindings;
+        } else if (aliveAfterElse && !aliveAfterThen) {
+            afterIfBindings = elseBindings;
+        }
+
+        afterIfBindings.forEach(env.info.scope::enter);
+        afterIfBindings.forEach(BindingSymbol::preserveBinding);
+
         result = null;
     }
 
+        void preFlow(JCTree tree) {
+            new PostAttrAnalyzer() {
+                @Override
+                public void scan(JCTree tree) {
+                    if (tree == null ||
+                            (tree.type != null &&
+                            tree.type == Type.stuckType)) {
+                        //don't touch stuck expressions!
+                        return;
+                    }
+                    super.scan(tree);
+                }
+            }.scan(tree);
+        }
+
     public void visitExec(JCExpressionStatement tree) {
         //a fresh environment is required for 292 inference to work properly ---
         //see Infer.instantiatePolymorphicSignatureInstance()
@@ -3582,7 +3715,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);
@@ -3648,19 +3801,43 @@
     public void visitTypeTest(JCInstanceOf tree) {
         Type exprtype = chk.checkNullOrRefType(
                 tree.expr.pos(), attribExpr(tree.expr, env));
-        Type clazztype = attribType(tree.clazz, env);
-        if (!clazztype.hasTag(TYPEVAR)) {
-            clazztype = chk.checkClassOrArrayType(tree.clazz.pos(), clazztype);
-        }
-        if (!clazztype.isErroneous() && !types.isReifiable(clazztype)) {
-            log.error(tree.clazz.pos(), Errors.IllegalGenericTypeForInstof);
-            clazztype = types.createErrorType(clazztype);
-        }
-        chk.validate(tree.clazz, env, false);
+        Type clazztype;
+        if (tree.pattern.getTag() == BINDINGPATTERN) {
+            attribTree(tree.pattern, env, unknownExprInfo);
+            clazztype = tree.pattern.type;
+            if (!clazztype.hasTag(TYPEVAR)) {
+                clazztype = chk.checkClassOrArrayType(tree.pattern.pos(), clazztype);
+            }
+        } else {
+            clazztype = attribType(tree.pattern, env);
+            if (!clazztype.hasTag(TYPEVAR)) {
+                clazztype = chk.checkClassOrArrayType(tree.pattern.pos(), clazztype);
+            }
+            if (!clazztype.isErroneous() && !types.isReifiable(clazztype)) {
+                log.error(tree.pattern.pos(), Errors.IllegalGenericTypeForInstof);
+                clazztype = types.createErrorType(clazztype);
+            }
+            chk.validate(tree.pattern, env, false);
+        }
         chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
         result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo);
     }
 
+    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 visitIndexed(JCArrayAccess tree) {
         Type owntype = types.createErrorType(tree.type);
         Type atype = attribExpr(tree.indexed, env);
@@ -5051,8 +5228,8 @@
             super.visitTypeCast(tree);
         }
         public void visitTypeTest(JCInstanceOf tree) {
-            if (tree.clazz != null && tree.clazz.type != null)
-                validateAnnotatedType(tree.clazz, tree.clazz.type);
+            if (tree.pattern != null && !(tree.pattern instanceof JCPattern) && tree.pattern.type != null)
+                validateAnnotatedType(tree.pattern, tree.pattern.type);
             super.visitTypeTest(tree);
         }
         public void visitNewClass(JCNewClass tree) {
@@ -5313,6 +5490,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,
@@ -5379,4 +5566,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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java	Thu Nov 29 08:16:17 2018 +0100
@@ -60,8 +60,9 @@
         FLOW(5),
         TRANSTYPES(6),
         UNLAMBDA(7),
-        LOWER(8),
-        GENERATE(9);
+        TRANSPATTERNS(8),
+        LOWER(9),
+        GENERATE(10);
 
         CompileState(int value) {
             this.value = value;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Nov 29 08:16:17 2018 +0100
@@ -255,6 +255,23 @@
         }
     }
 
+    public boolean aliveAfter(Env<AttrContext> env, JCTree 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 {
+            SnippetAliveAnalyzer analyzer = new SnippetAliveAnalyzer();
+
+            analyzer.analyzeTree(env, that, make);
+            return analyzer.isAlive();
+        } finally {
+            log.popDiagnosticHandler(diagHandler);
+        }
+    }
+
     /**
      * Definite assignment scan mode
      */
@@ -517,7 +534,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;
@@ -1434,6 +1451,19 @@
     }
 
     /**
+     * Determine if alive after the given tree.
+     */
+    class SnippetAliveAnalyzer 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 {
@@ -1630,7 +1660,7 @@
          */
         protected boolean trackable(VarSymbol sym) {
             return
-                sym.pos >= startPos &&
+                sym.pos >= startPos && ((sym.flags() & MATCH_BINDING) == 0) &&
                 ((sym.owner.kind == MTH ||
                 isFinalUninitializedField(sym)));
         }
@@ -2564,6 +2594,11 @@
             // Do nothing for modules
         }
 
+        // TODO: 2017-02-02 JUST TO ALLOW THINGS TO CONTINUE
+        public void visitTypeTestPattern(JCBindingPattern tree) {
+            // Do nothing
+        }
+
     /**************************************************************************
      * main method
      *************************************************************************/
@@ -2764,6 +2799,11 @@
             // Do nothing for modules
         }
 
+        // TODO: 2017-02-02 JUST TO ALLOW THINGS TO CONTINUE
+        public void visitTypeTestPattern(JCBindingPattern tree) {
+            // Do nothing
+        }
+
     /**************************************************************************
      * main method
      *************************************************************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,239 @@
+/*
+ * 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.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 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 void preserveBinding() {
+            flags_field |= Flags.MATCH_BINDING_TO_OUTER;
+        }
+
+        public boolean isPreserved() {
+            return (flags_field & Flags.MATCH_BINDING_TO_OUTER) != 0;
+        }
+    }
+
+    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;
+        }
+
+        @Override
+        public void preserveBinding() {
+            aliases.stream().forEach(BindingSymbol::preserveBinding);
+        }
+
+        public boolean isPreserved() {
+            return aliases.stream().allMatch(BindingSymbol::isPreserved);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,445 @@
+/*
+ * 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.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+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.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+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.Map.Entry;
+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 com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+
+/**
+ * This pass translates pattern-matching constructs, such as instanceof <pattern>.
+ */
+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;
+        }
+
+        @Override
+        boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+            return false;
+        }
+    };
+
+    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");
+    }
+
+    @Override
+    public void visitTypeTest(JCInstanceOf tree) {
+        if (tree.pattern.hasTag(Tag.BINDINGPATTERN)) {
+            JCBindingPattern patt = (JCBindingPattern)tree.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);
+        } else {
+            super.visitTypeTest(tree);
+        }
+    }
+
+    @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 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 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);
+        }
+    }
+
+    @Override
+    public void visitBlock(JCBlock tree) {
+        ListBuffer<JCStatement> statements = new ListBuffer<>();
+        bindingContext = new BasicBindingContext(List.nil()) {
+            boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+                hoistedVarMap.put(binding, var.sym);
+                statements.append(var);
+                return true;
+            }
+        };
+        try {
+            for (List<JCStatement> l = tree.stats; l.nonEmpty(); l = l.tail) {
+                statements.append(translate(l.head));
+            }
+
+            tree.stats = statements.toList();
+            result = tree;
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    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();
+        abstract boolean tryPrepend(BindingSymbol binding, JCVariableDecl var);
+    }
+
+    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 (Entry<BindingSymbol, VarSymbol> e : hoistedVarMap.entrySet()) {
+                JCVariableDecl decl = makeHoistedVarDecl(stat.pos, e.getValue());
+                if (!e.getKey().isPreserved() ||
+                    !parent.tryPrepend(e.getKey(), decl)) {
+                    stats.add(decl);
+                }
+            }
+            if (stats.nonEmpty()) {
+                stats.add(stat);
+                stat = make.at(stat.pos).Block(0, stats.toList());
+            }
+            return stat;
+        }
+
+        @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;
+        }
+
+        @Override
+        boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+            return false;
+        }
+
+        private JCVariableDecl makeHoistedVarDecl(int pos, VarSymbol varSymbol) {
+            return make.at(pos).VarDef(varSymbol, makeDefaultValue(pos, varSymbol.erasure(types)));
+        }
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Thu Nov 29 08:16:17 2018 +0100
@@ -567,6 +567,13 @@
         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 &&
@@ -777,7 +784,7 @@
 
     public void visitTypeTest(JCInstanceOf tree) {
         tree.expr = translate(tree.expr, null);
-        tree.clazz = translate(tree.clazz, null);
+        tree.pattern = translate(tree.pattern, null);
         result = tree;
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Thu Nov 29 08:16:17 2018 +0100
@@ -577,7 +577,7 @@
     @Override
     public void visitTypeTest(JCInstanceOf tree) {
         JCInstanceOf that = (JCInstanceOf) parameter;
-        result = scan(tree.expr, that.expr) && scan(tree.clazz, that.clazz);
+        result = scan(tree.expr, that.expr) && scan(tree.pattern, that.pattern);
     }
 
     @Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Thu Nov 29 08:16:17 2018 +0100
@@ -459,7 +459,7 @@
         public void visitTypeTest(JCInstanceOf tree) {
             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
             sr.mergeWith(csp(tree.expr));
-            sr.mergeWith(csp(tree.clazz));
+            sr.mergeWith(csp(tree.pattern));
             result = sr;
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Thu Nov 29 08:16:17 2018 +0100
@@ -2024,7 +2024,7 @@
     public void visitTypeTest(JCInstanceOf tree) {
         genExpr(tree.expr, tree.expr.type).load();
         setTypeAnnotationPositions(tree.pos);
-        code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type));
+        code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
         result = items.makeStackItem(syms.booleanType);
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Thu Nov 29 08:16:17 2018 +0100
@@ -1561,6 +1561,12 @@
                 compileStates.put(env, CompileState.UNLAMBDA);
             }
 
+            if (shouldStop(CompileState.TRANSPATTERNS))
+                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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Thu Nov 29 08:16:17 2018 +0100
@@ -886,6 +886,7 @@
 
     /*  Expression2Rest = {infixop Expression3}
      *                  | Expression3 instanceof Type
+     *                  | Expression3 instanceof Pattern
      *  infixop         = "||"
      *                  | "&&"
      *                  | "|"
@@ -908,13 +909,24 @@
         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();
+                int patternPos = token.pos;
+                JCTree pattern = parseType();
+                if (token.kind == IDENTIFIER) {
+                    pattern = toP(F.at(patternPos).BindingPattern(ident(), pattern));
+                }
+                odStack[top] = F.at(pos).TypeTest(odStack[top], pattern);
+            } 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 +943,6 @@
         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);
-            }
-        }
         /** If tree is a concatenation of string literals, replace it
          *  by a single literal representing the concatenated string.
          */
@@ -2542,25 +2541,25 @@
             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
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Nov 29 08:16:17 2018 +0100
@@ -543,6 +543,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
 
@@ -3332,6 +3336,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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Thu Nov 29 08:16:17 2018 +0100
@@ -38,6 +38,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;
@@ -235,6 +236,10 @@
          */
         TYPETEST,
 
+        /** Patterns.
+         */
+        BINDINGPATTERN,
+
         /** Indexed array expressions, of type Indexed.
          */
         INDEXED,
@@ -2117,10 +2122,10 @@
      */
     public static class JCInstanceOf extends JCExpression implements InstanceOfTree {
         public JCExpression expr;
-        public JCTree clazz;
-        protected JCInstanceOf(JCExpression expr, JCTree clazz) {
+        public JCTree pattern;
+        protected JCInstanceOf(JCExpression expr, JCTree pattern) {
             this.expr = expr;
-            this.clazz = clazz;
+            this.pattern = pattern;
         }
         @Override
         public void accept(Visitor v) { v.visitTypeTest(this); }
@@ -2128,7 +2133,13 @@
         @DefinedBy(Api.COMPILER_TREE)
         public Kind getKind() { return Kind.INSTANCE_OF; }
         @DefinedBy(Api.COMPILER_TREE)
-        public JCTree getType() { return clazz; }
+        public JCTree getType() { return pattern instanceof JCPattern ? pattern.hasTag(BINDINGPATTERN) ? ((JCBindingPattern) pattern).vartype : null : pattern; }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCPattern getPattern() {
+            return pattern instanceof JCPattern ? (JCPattern) pattern : null;
+        }
+
         @DefinedBy(Api.COMPILER_TREE)
         public JCExpression getExpression() { return expr; }
         @Override @DefinedBy(Api.COMPILER_TREE)
@@ -2142,6 +2153,60 @@
     }
 
     /**
+     * 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 JCTree vartype;
+
+        protected JCBindingPattern(Name name, BindingSymbol symbol, JCTree 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;
+        }
+    }
+
+    /**
      * An array selection
      */
     public static class JCArrayAccess extends JCExpression implements ArrayAccessTree {
@@ -3112,6 +3177,7 @@
         JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs);
         JCTypeCast TypeCast(JCTree expr, JCExpression type);
         JCInstanceOf TypeTest(JCExpression expr, JCTree clazz);
+        JCBindingPattern BindingPattern(Name name, JCTree vartype);
         JCArrayAccess Indexed(JCExpression indexed, JCExpression index);
         JCFieldAccess Select(JCExpression selected, Name selector);
         JCIdent Ident(Name idname);
@@ -3175,6 +3241,7 @@
         public void visitBinary(JCBinary that)               { visitTree(that); }
         public void visitTypeCast(JCTypeCast that)           { visitTree(that); }
         public void visitTypeTest(JCInstanceOf that)         { visitTree(that); }
+        public void visitBindingPattern(JCBindingPattern 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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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,21 @@
         }
     }
 
+    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 visitSynchronized(JCSynchronized tree) {
         try {
             print("synchronized ");
@@ -1273,7 +1305,11 @@
             open(prec, TreeInfo.ordPrec);
             printExpr(tree.expr, TreeInfo.ordPrec);
             print(" instanceof ");
-            printExpr(tree.clazz, TreeInfo.ordPrec + 1);
+            if (tree.pattern instanceof JCPattern) {
+                printPattern(tree.pattern);
+            } else {
+                printExpr(tree.getType(), TreeInfo.ordPrec + 1);
+            }
             close(prec, TreeInfo.ordPrec);
         } catch (IOException e) {
             throw new UncheckedIOException(e);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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;
@@ -476,8 +475,15 @@
     public JCTree visitInstanceOf(InstanceOfTree node, P p) {
         JCInstanceOf t = (JCInstanceOf) node;
         JCExpression expr = copy(t.expr, p);
-        JCTree clazz = copy(t.clazz, p);
-        return M.at(t.pos).TypeTest(expr, clazz);
+        JCTree pattern = copy(t.pattern, p);
+        return M.at(t.pos).TypeTest(expr, pattern);
+    }
+
+    @DefinedBy(Api.COMPILER_TREE)
+    public JCTree visitBindingPattern(BindingPatternTree node, P p) {
+        JCBindingPattern t = (JCBindingPattern) node;
+        JCTree vartype = copy(t.vartype, p);
+        return M.at(t.pos).BindingPattern(t.name, vartype);
     }
 
     @DefinedBy(Api.COMPILER_TREE)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Thu Nov 29 08:16:17 2018 +0100
@@ -574,7 +574,7 @@
             case TYPECAST:
                 return getEndPos(((JCTypeCast) tree).expr, endPosTable);
             case TYPETEST:
-                return getEndPos(((JCInstanceOf) tree).clazz, endPosTable);
+                return getEndPos(((JCInstanceOf) tree).pattern, endPosTable);
             case WHILELOOP:
                 return getEndPos(((JCWhileLoop) tree).body, endPosTable);
             case ANNOTATED_TYPE:
@@ -847,6 +847,8 @@
             if (node.type != null)
                 return node.type.tsym;
             return null;
+        case BINDINGPATTERN:
+            return ((JCBindingPattern) node).symbol;
         default:
             return null;
         }
@@ -1225,4 +1227,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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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.*;
@@ -459,6 +458,12 @@
         return tree;
     }
 
+    public JCBindingPattern BindingPattern(Name name, JCTree vartype) {
+        JCBindingPattern tree = new JCBindingPattern(name, null, vartype);
+        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	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Thu Nov 29 08:16:17 2018 +0100
@@ -296,7 +296,12 @@
 
     public void visitTypeTest(JCInstanceOf tree) {
         scan(tree.expr);
-        scan(tree.clazz);
+        scan(tree.pattern);
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        if (tree.vartype != null)
+            scan(tree.vartype);
     }
 
     public void visitIndexed(JCArrayAccess tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Thu Nov 29 08:16:17 2018 +0100
@@ -351,7 +351,12 @@
 
     public void visitTypeTest(JCInstanceOf tree) {
         tree.expr = translate(tree.expr);
-        tree.clazz = translate(tree.clazz);
+        tree.pattern = translate(tree.pattern);
+        result = tree;
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        tree.vartype = translate(tree.vartype);
         result = tree;
     }
 
--- a/test/langtools/tools/javac/api/TestGetElementReferenceData.java	Wed Nov 28 21:34:22 2018 -0500
+++ b/test/langtools/tools/javac/api/TestGetElementReferenceData.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof 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	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof String k && o2 instanceof Integer k) {}
+        if (o1 instanceof String k || o2 instanceof Integer k) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof String s) {
+            s = "";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,143 @@
+/*
+ * @test
+ * @summary Basic tests for bindings from instanceof
+ * @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 instanceof String s) {
+            s.length();
+        }
+
+        // Test for e1 && e2.T = union(e1.T, e2.T)
+        if (o1 instanceof String s && o2 instanceof Integer in) {
+            s.length();
+            in.intValue();
+        }
+        // Test for e1 && e2.F = intersect(e1.F, e2.F)
+        if (!(o1 instanceof String s) && !(o1 instanceof String s)) {
+
+        } else {
+            s.length();
+        }
+
+        // test for e1&&e2 - include e1.T in e2
+        if (o1 instanceof String s && s.length()>0) {
+            System.out.print("done");
+        }
+
+        // Test for (e1 || e2).T = intersect(e1.T, e2.T)
+        if (o1 instanceof String s || o3 instanceof String s){
+            System.out.println(s); // ?
+        }
+
+        // Test for (e1 || e2).F = union(e1.F, e2.F)
+        if (!(o1 instanceof String s) || !(o3 instanceof Integer in)){
+        } else {
+            s.length();
+            i.intValue();
+        }
+
+        // Test for e1||e2 - include e1.F in e2
+
+        if (!(o1 instanceof String s) || s.length()>0) {
+            System.out.println("done");
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e2.T, e3.T)
+        if (Ktrue() ? o2 instanceof Integer x : o2 instanceof Integer x) {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.T, e3.T)
+        if (o1 instanceof String s ? true : o1 instanceof String s) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+        if (!(o1 instanceof String s) ? (o1 instanceof String s) : true) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o2 instanceof Integer x)){
+        } else {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+        if (o1 instanceof String s ? true : !(o1 instanceof String s)){
+        } else {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+        if (!(o1 instanceof String s) ? !(o1 instanceof String s) : true){
+        } else {
+            s.length();
+        }
+
+        // Test for e1 ? e2: e3 - include e1.T in e2
+        if (o1 instanceof String s ? s.length()>0 : false) {
+            System.out.println("done");
+        }
+
+        // Test for e1 ? e2 : e3 - include e1.F in e3
+        if (!(o1 instanceof String s) ? false : s.length()>0){
+            System.out.println("done");
+        }
+
+        // Test for (!e).T = e.F
+
+        if (!(!(o1 instanceof String s) || !(o3 instanceof Integer in))){
+            s.length();
+            i.intValue();
+        }
+
+        // Test for (!e).F = e.T
+        if (!(o1 instanceof String s)) {
+
+        } else {
+            s.length();
+        }
+
+        L1: {
+            if (o1 instanceof String s) {
+                s.length();
+            } else {
+                break L1;
+            }
+            s.length();
+        }
+
+        L2: {
+            if (!(o1 instanceof String s)) {
+                break L2;
+            } else {
+                s.length();
+            }
+            s.length();
+        }
+
+        L3: {
+            if ((o1 instanceof String s) || (o3 instanceof String s)) {
+                s.length();
+            } else {
+                break L3;
+            }
+            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	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof Integer x : o2 instanceof String x) {
+            x.intValue();
+        }
+        if (Ktrue() ? o2 instanceof Integer x : true) {
+            x.intValue();
+        }
+
+        if (o1 instanceof String s ? true : true) {
+            s.length();
+        }
+        if (o1 instanceof String s ? true : o2 instanceof Integer s) {
+            s.length();
+        }
+        if (o1 instanceof String s ? true : o2 instanceof Integer i) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+        if (!(o1 instanceof String s) ? true : true) {
+            s.length();
+        }
+        if (!(o1 instanceof String s) ? (o2 instanceof Integer s) : true) {
+            s.length();
+        }
+        if (!(o1 instanceof String s) ? (o2 instanceof Integer i) : true) {
+            s.length();
+            i.intValue();
+        }
+        if (!(o1 instanceof String s) ? (o1 instanceof String s2) : true) {
+            s.length();
+            s2.length();
+        }
+
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o1 instanceof String x)){
+        } else {
+            x.intValue();
+        }
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o1 instanceof String s)){
+        } else {
+            x.intValue();
+        }
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o2 instanceof Integer x1)){
+        } else {
+            x.intValue();
+            x1.intValue();
+        }
+        if (Ktrue() ? !(o2 instanceof Integer x) : false){
+        } else {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+        if (o1 instanceof String s ? true : !(o2 instanceof Integer s)){
+        } else {
+            s.length();
+        }
+        if (o1 instanceof String s ? true : !(o2 instanceof Integer i)){
+        } else {
+            s.length();
+            i.intValue();
+        }
+        if (o1 instanceof String s ? true : !(o2 instanceof String s1)){
+        } else {
+            s.length();
+            s1.length();
+        }
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+        if (!(o1 instanceof String s) ? !(o1 instanceof String s1) : true){
+        } else {
+            s.length();
+            s1.length();
+        }
+        if (!(o1 instanceof String s) ? !(o2 instanceof Integer s) : true){
+        } else {
+            s.length();
+        }
+        if (!(o1 instanceof String s) ? !(o2 instanceof Integer i) : true){
+        } else {
+            s.length();
+            i.intValue();
+        }
+
+        // Test for e1 ? e2: e3 - include e1.T in e2
+        if (o1 instanceof String s ? false : s.length()>0) {
+            System.out.println("done");
+        }
+        if (o1 instanceof String s ? false : s.intValue!=0) {
+            System.out.println("done");
+        }
+
+        // Test for e1 ? e2 : e3 - include e1.F in e3
+        if (!(o1 instanceof String s) ? s.length()>0 : false){
+            System.out.println("done");
+        }
+        if (!(o1 instanceof 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	Thu Nov 29 08:16:17 2018 +0100
@@ -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:36: 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:39: 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:36: 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:39: 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:46: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:103:46: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:108:41: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:111:41: 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/CastConversionMatch.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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.
+ *
+ * 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/fail/ref=CastConversionMatch.out -XDrawDiagnostics CastConversionMatch.java
+ */
+
+public class CastConversionMatch {
+    public static void main(String [] args) {
+        Object o = 42;
+        if (o instanceof int s) {
+            System.out.println("Okay");
+        } else {
+            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/CastConversionMatch.out	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,2 @@
+CastConversionMatch.java:33:26: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,21 @@
+/*
+ * @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] instanceof String s) { // NOT OK. Redef same scope.
+            }
+            if (args[0] instanceof String f) { // OK to redef field.
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.out	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,2 @@
+DuplicateBindingTest.java:15:36: compiler.err.already.defined: kindname.variable, s, kindname.method, main(java.lang.String[])
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof String s) {
+            System.out.println("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out	Thu Nov 29 08:16:17 2018 +0100
@@ -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/ExamplesFromProposal.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,191 @@
+/*
+ * @test
+ * @summary All example code from "Pattern Matching for Java" document, released April 2017, adjusted to current state (no switches, etc)
+ * @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) {
+        if (n instanceof IntNode in) return in.value;
+        else if (n instanceof NegNode nn) return -eval(nn.node);
+        else if (n instanceof AddNode an) return eval(an.left) + eval(an.right);
+        else if (n instanceof MulNode mn) return eval(mn.left) * eval(mn.right);
+        else {
+            // should never happen
+            throw new AssertionError("broken");
+        }
+    }
+
+    public static String toString(Node n) {
+        if (n instanceof IntNode in) return String.valueOf(in.value);
+        else if (n instanceof NegNode nn) return "-"+eval(nn.node);
+        else if (n instanceof AddNode an) return eval(an.left) + " + " + eval(an.right);
+        else if (n instanceof MulNode mn) return eval(mn.left) + " * " + eval(mn.right);
+        else {
+            // should never happen
+            throw new AssertionError("broken");
+        }
+    }
+
+    public static Node simplify(Node n) {
+        if (n instanceof IntNode in) {
+            return n;
+        } else if (n instanceof NegNode nn) {
+            return new NegNode(simplify(nn.node));
+        } else if (n instanceof AddNode ad) {
+            n = simplify(ad.left);
+            if (n instanceof IntNode intn) {
+                if (intn.value == 0)
+                    return simplify(ad.right);
+                else
+                    return new AddNode(intn, simplify(ad.right));
+            } else {
+                return new AddNode(simplify(ad.left), simplify(ad.right));
+            }
+        } else if (n instanceof MulNode mn) {
+            return new MulNode(simplify(mn.left), simplify(mn.right));
+        } else {
+            //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 instanceof Integer i) {
+            // can use i here
+            System.out.println(i.intValue());
+        }
+
+        Object obj = getSomething();
+
+        String formatted = "unknown";
+        if (obj instanceof Integer i) {
+            formatted = String.format("int %d", i);
+        }
+        else if (obj instanceof Byte b) {
+            formatted = String.format("byte %d", b);
+        }
+        else if (obj instanceof Long l) {
+            formatted = String.format("long %d", l);
+        }
+        else if (obj instanceof Double d) {
+            formatted = String.format("double %f", d);
+        }
+        else if (obj instanceof String s) {
+            formatted = String.format("String %s", s);
+        }
+        System.out.println(formatted);
+
+        if (obj instanceof Integer i) formatted = String.format("int %d", i);
+        else if (obj instanceof Byte b) formatted = String.format("byte %d", b);
+        else if (obj instanceof Long l) formatted = String.format("long %d", l);
+        else if (obj instanceof Double d) formatted = String.format("double %f", d);
+        else if (obj instanceof String s) formatted = String.format("String %s", s);
+        else formatted = String.format("Something else "+ obj.toString());
+        System.out.println(formatted);
+
+        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 instanceof String s1) {
+            System.out.println(s1);
+        }
+        if (x instanceof String s1 && s1.length() > 0) {
+            System.out.println(s1);
+        }
+        if (x instanceof String s1) {
+            System.out.println(s1 + " is a string");
+        } else {
+            System.out.println("not a string");
+        }
+
+        if (!(x instanceof 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/ImpossibleTypeTest.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof String s ) {
+            System.out.println("Broken");
+        }
+        if (i instanceof Undefined u ) {
+            System.out.println("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out	Thu Nov 29 08:16:17 2018 +0100
@@ -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:26: 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	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,67 @@
+/*
+ * @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 instanceof String j && j.length() == 5) { // OK
+            System.out.println(j); // OK
+        } else {
+            System.out.println(j); // NOT OK
+        }
+
+        // NOT OK, name reused.
+        if (o1 instanceof String j && o2 instanceof Integer j) {
+        }
+
+        if (o1 instanceof String j && j.length() == 5 && o2 instanceof 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 instanceof String j || j.length() == 5) { // NOT OK
+            System.out.println(j); // NOT OK
+        }
+
+        if (o1 instanceof String j || o2 instanceof Integer j) { // NOT OK, types differ
+            System.out.println(j); // NOT OK
+        } else {
+            System.out.println(j); // NOT OK.
+        }
+
+        while (o1 instanceof String j && j.length() == 5) { // OK
+            System.out.println(j); // OK
+        }
+
+        while (o1 instanceof String j || true) {
+            System.out.println(j); // Not OK
+        }
+
+        for (; o1 instanceof String j; j.length()) { // OK
+            System.out.println(j); // OK
+        }
+
+        for (; o1 instanceof String j || true; j.length()) { // NOT OK
+            System.out.println(j); // Not OK
+        }
+
+        int x = o1 instanceof String j ?
+                      j.length() : // OK.
+                      j.length();  // NOT OK.
+
+        x = !(o1 instanceof 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	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,16 @@
+MatchBindingScopeTest.java:18:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:22:53: compiler.err.already.defined: kindname.variable, j, kindname.method, main(java.lang.String[])
+MatchBindingScopeTest.java:22:36: 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:39: 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:36: 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:48: 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:61:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:64:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+15 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/NullsInPatterns.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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 instanceof List t) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List type pattern");
+        }
+        if (null instanceof List<Integer> l) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List<Integer> type pattern");
+        }
+        if (null instanceof List<?> l) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List<?> type pattern");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,109 @@
+/*
+ * 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 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 instanceof String s) { }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.out	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,5 @@
+(o instanceof String s)
+o instanceof String s
+o
+String s
+String
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternTypeTest2.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof 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	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,15 @@
+/*
+ * @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 instanceof String s) {
+            s = "hello again";
+            System.out.println(s);
+        }
+        System.out.println("test complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.out	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,2 @@
+PatternVariablesAreFinal.java:10:13: compiler.err.pattern.binding.may.not.be.assigned: s
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal2.java	Thu Nov 29 08:16:17 2018 +0100
@@ -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 instanceof 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/UncheckedWarningOnMatchesTest.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,18 @@
+/*
+ * @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 instanceof ArrayList<Integer> ai) {  // unchecked conversion
+            System.out.println("Blah");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,4 @@
+UncheckedWarningOnMatchesTest.java:14:13: 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
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/scope/ScopeTest.java	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import tools.javac.combo.JavacTemplateTestBase;
+
+import static java.util.stream.Collectors.toList;
+
+@Test
+public class ScopeTest extends JavacTemplateTestBase {
+
+    private static String st_block(String... statements) {
+        return Arrays.stream(statements).collect(Collectors.joining("", "{", "}"));
+    }
+
+    private static String st_if(String condition, String then, String els) {
+        return "if (" + condition + ") " + then + " else " + els;
+    }
+
+    private static String st_while(String condition, String body) {
+        return "while (" + condition + ") " + body;
+    }
+
+    private static String st_do_while(String body, String condition) {
+        return "do " + body + " while (" + condition + ");";
+    }
+
+    private static String st_for(String init, String condition, String update, String body) {
+        return "for (" + init + "; " + condition + "; " + update + ") " + body;
+    }
+
+    private static String st_s_use() {
+        return "s.length();";
+    }
+
+    private static String st_break() {
+        return "break;";
+    }
+
+    private static String st_return() {
+        return "return;";
+    }
+
+    private static String st_noop() {
+        return ";";
+    }
+
+    private static String expr_empty() {
+        return "";
+    }
+
+    private static String expr_o_match_str() {
+        return "o instanceof String s";
+    }
+
+    private static String expr_not(String expr) {
+        return "!(" + expr + ")";
+    }
+
+    @AfterMethod
+    public void dumpTemplateIfError(ITestResult result) {
+        // Make sure offending template ends up in log file on failure
+        if (!result.isSuccess()) {
+            System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList()));
+        }
+    }
+
+    private void program(String block) {
+        String s = "class C { void m(Object o) " + block + "}";
+        addSourceFile("C.java", new StringTemplate(s));
+    }
+
+    private void assertOK(String block) {
+        reset();
+        program(block);
+        try {
+            compile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        assertCompileSucceeded();
+    }
+
+    private void assertFail(String expectedDiag, String block) {
+        reset();
+        addCompileOptions("--enable-preview", "-source", "12");
+        program(block);
+        try {
+            compile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        assertCompileFailed(expectedDiag);
+    }
+
+    public void testIf() {
+        assertOK(st_block(st_if(expr_o_match_str(), st_s_use(), st_return()), st_s_use()));
+        assertOK(st_block(st_if(expr_not(expr_o_match_str()), st_return(), st_s_use()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_if(expr_o_match_str(), st_s_use(), st_noop()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_if(expr_not(expr_o_match_str()), st_noop(), st_s_use()), st_s_use()));
+    }
+
+    public void testWhile() {
+        assertOK(st_block(st_while(expr_not(expr_o_match_str()), st_noop()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_while(expr_not(expr_o_match_str()), st_break()), st_s_use()));
+    }
+
+    public void testDoWhile() {
+        assertOK(st_block(st_do_while(st_noop(), expr_not(expr_o_match_str())), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_do_while(st_break(), expr_not(expr_o_match_str())), st_s_use()));
+    }
+
+    public void testFor() {
+        assertOK(st_block(st_for(expr_empty(), expr_not(expr_o_match_str()), expr_empty(), st_noop()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_for(expr_empty(), expr_not(expr_o_match_str()), expr_empty(), st_break()), st_s_use()));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/scope/TEST.properties	Thu Nov 29 08:16:17 2018 +0100
@@ -0,0 +1,6 @@
+TestNG.dirs = .
+
+lib.dirs = /lib/combo
+
+modules = \
+        jdk.compiler/com.sun.tools.javac.util