changeset 57669:9e414f680603

8236670: Conflicting bindings accepted in some cases Reviewed-by: mcimadamore
author jlahoda
date Tue, 14 Jan 2020 11:10:07 +0100
parents e27b546887e7
children 247b7fe0c11d
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java test/langtools/tools/javac/patterns/BindingsExistTest.out test/langtools/tools/javac/patterns/BindingsTest1.java test/langtools/tools/javac/patterns/ConditionalTest.java test/langtools/tools/javac/patterns/DuplicateBindingTest.java test/langtools/tools/javac/patterns/DuplicateBindingTest.out test/langtools/tools/javac/patterns/MatchBindingScopeTest.out
diffstat 13 files changed, 462 insertions(+), 224 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -228,7 +228,8 @@
     public static final long EFFECTIVELY_FINAL = 1L<<41;
 
     /**
-     * Flag that marks non-override equivalent methods with the same signature.
+     * Flag that marks non-override equivalent methods with the same signature,
+     * or a conflicting match binding (BindingSymbol).
      */
     public static final long CLASH = 1L<<42;
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -1785,6 +1785,29 @@
 
     }
 
+    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;
+        }
+    }
+
     /** A class for method symbols.
      */
     public static class MethodSymbol extends Symbol implements ExecutableElement {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -49,7 +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.comp.MatchBindingsComputer.MatchBindings;
 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;
@@ -642,6 +642,8 @@
      */
     Type result;
 
+    MatchBindings matchBindings = MatchBindingsComputer.EMPTY;
+
     /** Visitor method: attribute a tree, catching any completion failure
      *  exceptions. Return the tree's type.
      *
@@ -660,6 +662,8 @@
             } else {
                 tree.accept(this);
             }
+            matchBindings = matchBindingsComputer.finishBindings(tree,
+                                                                 matchBindings);
             if (tree == breakTree &&
                     resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
                 breakTreeFound(copyEnv(env));
@@ -1418,18 +1422,18 @@
         attribExpr(tree.cond, env, syms.booleanType);
         if (!breaksOutOf(tree, tree.body)) {
             //include condition's body when false after the while, if cannot get out of the loop
-            List<BindingSymbol> bindings = matchBindingsComputer.getMatchBindings(tree.cond, false);
-
-            bindings.forEach(env.info.scope::enter);
-            bindings.forEach(BindingSymbol::preserveBinding);
+            MatchBindings condBindings = matchBindings;
+            condBindings.bindingsWhenFalse.forEach(env.info.scope::enter);
+            condBindings.bindingsWhenFalse.forEach(BindingSymbol::preserveBinding);
         }
         result = null;
     }
 
     public void visitWhileLoop(JCWhileLoop tree) {
         attribExpr(tree.cond, env, syms.booleanType);
+        MatchBindings condBindings = matchBindings;
         // include condition's bindings when true in the body:
-        Env<AttrContext> whileEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
+        Env<AttrContext> whileEnv = bindingEnv(env, condBindings.bindingsWhenTrue);
         try {
             attribStat(tree.body, whileEnv.dup(tree));
         } finally {
@@ -1437,11 +1441,8 @@
         }
         if (!breaksOutOf(tree, tree.body)) {
             //include condition's bindings when false after the while, if cannot get out of the loop
-            List<BindingSymbol> bindings =
-                    matchBindingsComputer.getMatchBindings(tree.cond, false);
-
-            bindings.forEach(env.info.scope::enter);
-            bindings.forEach(BindingSymbol::preserveBinding);
+            condBindings.bindingsWhenFalse.forEach(env.info.scope::enter);
+            condBindings.bindingsWhenFalse.forEach(BindingSymbol::preserveBinding);
         }
         result = null;
     }
@@ -1454,15 +1455,15 @@
     public void visitForLoop(JCForLoop tree) {
         Env<AttrContext> loopEnv =
             env.dup(env.tree, env.info.dup(env.info.scope.dup()));
+        MatchBindings condBindings = MatchBindingsComputer.EMPTY;
         try {
             attribStats(tree.init, loopEnv);
-            List<BindingSymbol> matchBindings = List.nil();
             if (tree.cond != null) {
                 attribExpr(tree.cond, loopEnv, syms.booleanType);
                 // include condition's bindings when true in the body and step:
-                matchBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
-            }
-            Env<AttrContext> bodyEnv = bindingEnv(loopEnv, matchBindings);
+                condBindings = matchBindings;
+            }
+            Env<AttrContext> bodyEnv = bindingEnv(loopEnv, condBindings.bindingsWhenTrue);
             try {
                 bodyEnv.tree = tree; // before, we were not in loop!
                 attribStats(tree.step, bodyEnv);
@@ -1477,11 +1478,8 @@
         }
         if (!breaksOutOf(tree, tree.body)) {
             //include condition's body when false after the while, if cannot get out of the loop
-            List<BindingSymbol> bindings =
-                    matchBindingsComputer.getMatchBindings(tree.cond, false);
-
-            bindings.forEach(env.info.scope::enter);
-            bindings.forEach(BindingSymbol::preserveBinding);
+            condBindings.bindingsWhenFalse.forEach(env.info.scope::enter);
+            condBindings.bindingsWhenFalse.forEach(BindingSymbol::preserveBinding);
         }
     }
 
@@ -1818,6 +1816,7 @@
 
     public void visitConditional(JCConditional tree) {
         Type condtype = attribExpr(tree.cond, env, syms.booleanType);
+        MatchBindings condBindings = matchBindings;
 
         tree.polyKind = (!allowPoly ||
                 pt().hasTag(NONE) && pt() != Type.recoveryType && pt() != Infer.anyPoly ||
@@ -1841,21 +1840,25 @@
         // include x's bindings when false in z
 
         Type truetype;
-        Env<AttrContext> trueEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
+        Env<AttrContext> trueEnv = bindingEnv(env, condBindings.bindingsWhenTrue);
         try {
             truetype = attribTree(tree.truepart, trueEnv, condInfo);
         } finally {
             trueEnv.info.scope.leave();
         }
 
+        MatchBindings trueBindings = matchBindings;
+
         Type falsetype;
-        Env<AttrContext> falseEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, false));
+        Env<AttrContext> falseEnv = bindingEnv(env, condBindings.bindingsWhenFalse);
         try {
             falsetype = attribTree(tree.falsepart, falseEnv, condInfo);
         } finally {
             falseEnv.info.scope.leave();
         }
 
+        MatchBindings falseBindings = matchBindings;
+
         Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
                 condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
                          List.of(truetype, falsetype)) : pt();
@@ -1867,6 +1870,7 @@
             owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype);
         }
         result = check(tree, owntype, KindSelector.VAL, resultInfo);
+        matchBindings = matchBindingsComputer.conditional(tree, condBindings, trueBindings, falseBindings);
     }
     //where
         private boolean isBooleanOrNumeric(Env<AttrContext> env, JCExpression tree) {
@@ -2022,8 +2026,8 @@
         // include x's bindings when true in y
         // include x's bindings when false in z
 
-        List<BindingSymbol> thenBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
-        Env<AttrContext> thenEnv = bindingEnv(env, thenBindings);
+        MatchBindings condBindings = matchBindings;
+        Env<AttrContext> thenEnv = bindingEnv(env, condBindings.bindingsWhenTrue);
 
         try {
             attribStat(tree.thenpart, thenEnv);
@@ -2034,10 +2038,9 @@
         preFlow(tree.thenpart);
         boolean aliveAfterThen = flow.aliveAfter(env, tree.thenpart, make);
         boolean aliveAfterElse;
-        List<BindingSymbol> elseBindings = matchBindingsComputer.getMatchBindings(tree.cond, false);
 
         if (tree.elsepart != null) {
-            Env<AttrContext> elseEnv = bindingEnv(env, elseBindings);
+            Env<AttrContext> elseEnv = bindingEnv(env, condBindings.bindingsWhenFalse);
             try {
                 attribStat(tree.elsepart, elseEnv);
             } finally {
@@ -2054,9 +2057,9 @@
         List<BindingSymbol> afterIfBindings = List.nil();
 
         if (aliveAfterThen && !aliveAfterElse) {
-            afterIfBindings = thenBindings;
+            afterIfBindings = condBindings.bindingsWhenTrue;
         } else if (aliveAfterElse && !aliveAfterThen) {
-            afterIfBindings = elseBindings;
+            afterIfBindings = condBindings.bindingsWhenFalse;
         }
 
         afterIfBindings.forEach(env.info.scope::enter);
@@ -3767,6 +3770,7 @@
             }
         }
         result = check(tree, owntype, KindSelector.VAL, resultInfo);
+        matchBindings = matchBindingsComputer.unary(tree, matchBindings);
     }
 
     public void visitBinary(JCBinary tree) {
@@ -3778,19 +3782,20 @@
         // x || y
         // include x's bindings when false in y
 
-        List<BindingSymbol> matchBindings;
+        MatchBindings lhsBindings = matchBindings;
+        List<BindingSymbol> propagatedBindings;
         switch (tree.getTag()) {
             case AND:
-                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true);
+                propagatedBindings = lhsBindings.bindingsWhenTrue;
                 break;
             case OR:
-                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false);
+                propagatedBindings = lhsBindings.bindingsWhenFalse;
                 break;
             default:
-                matchBindings = List.nil();
+                propagatedBindings = List.nil();
                 break;
         }
-        Env<AttrContext> rhsEnv = bindingEnv(env, matchBindings);
+        Env<AttrContext> rhsEnv = bindingEnv(env, propagatedBindings);
         Type right;
         try {
             right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, rhsEnv));
@@ -3798,6 +3803,8 @@
             rhsEnv.info.scope.leave();
         }
 
+        matchBindings = matchBindingsComputer.binary(tree, lhsBindings, matchBindings);
+
         // Find operator.
         Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
         Type owntype = types.createErrorType(tree.type);
@@ -3918,6 +3925,7 @@
         annotate.queueScanTreeAndTypeAnnotate(tree.vartype, env, v, tree.pos());
         annotate.flush();
         result = tree.type;
+        matchBindings = new MatchBindings(List.of(tree.symbol), List.nil());
     }
 
     public void visitIndexed(JCArrayAccess tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -3604,7 +3604,10 @@
                 } else if ((sym.flags() & MATCH_BINDING) != 0 &&
                            (byName.flags() & MATCH_BINDING) != 0 &&
                            (byName.flags() & MATCH_BINDING_TO_OUTER) == 0) {
-                    //this error will be reported separatelly in MatchBindingsComputer
+                    if (!sym.type.isErroneous()) {
+                        log.error(pos, Errors.MatchBindingExists);
+                        sym.flags_field |= CLASH;
+                    }
                     return false;
                 } else {
                     duplicateError(pos, byName);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2020, 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
@@ -25,31 +25,26 @@
 
 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.code.Symbol.BindingSymbol;
 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.JCTree.Tag;
 import com.sun.tools.javac.tree.TreeScanner;
 import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Name;
+
+import static com.sun.tools.javac.code.Flags.CLASH;
 
 
 public class MatchBindingsComputer extends TreeScanner {
+    public static final MatchBindings EMPTY = new MatchBindings(List.nil(), List.nil());
+
     protected static final Context.Key<MatchBindingsComputer> matchBindingsComputerKey = new Context.Key<>();
 
     private final Log log;
-    private final Types types;
-    boolean whenTrue;
-    List<BindingSymbol> bindings;
 
     public static MatchBindingsComputer instance(Context context) {
         MatchBindingsComputer instance = context.get(matchBindingsComputerKey);
@@ -60,106 +55,99 @@
 
     protected MatchBindingsComputer(Context context) {
         this.log = Log.instance(context);
-        this.types = Types.instance(context);
     }
 
-    public List<BindingSymbol> getMatchBindings(JCTree expression, boolean whenTrue) {
-        this.whenTrue = whenTrue;
-        this.bindings = List.nil();
-        scan(expression);
-        return bindings;
-    }
+    public MatchBindings conditional(JCTree tree, MatchBindings condBindings, MatchBindings trueBindings, MatchBindings falseBindings) {
+        if (condBindings == EMPTY &&
+            trueBindings == EMPTY &&
+            falseBindings == EMPTY) {
+            return EMPTY;
+        }
 
-    @Override
-    public void visitBindingPattern(JCBindingPattern tree) {
-        bindings = whenTrue ? List.of(tree.symbol) : List.nil();
-    }
+        DiagnosticPosition pos = tree.pos();
+         //A pattern variable is introduced both by a when true, and by c when true:
+        List<BindingSymbol> xTzT = intersection(pos, condBindings.bindingsWhenTrue, falseBindings.bindingsWhenTrue);
+         //A pattern variable is introduced both by a when false, and by b when true:
+        List<BindingSymbol> xFyT = intersection(pos, condBindings.bindingsWhenFalse, trueBindings.bindingsWhenTrue);
+         //A pattern variable is introduced both by b when true, and by c when true:
+        List<BindingSymbol> yTzT = intersection(pos, trueBindings.bindingsWhenTrue, falseBindings.bindingsWhenTrue);
+         //A pattern variable is introduced both by a when true, and by c when false:
+        List<BindingSymbol> xTzF = intersection(pos, condBindings.bindingsWhenTrue, falseBindings.bindingsWhenFalse);
+         //A pattern variable is introduced both by a when false, and by b when false:
+        List<BindingSymbol> xFyF = intersection(pos, condBindings.bindingsWhenFalse, trueBindings.bindingsWhenFalse);
+         //A pattern variable is introduced both by b when false, and by c when false:
+        List<BindingSymbol> yFzF = intersection(pos, trueBindings.bindingsWhenFalse, falseBindings.bindingsWhenFalse);
 
-    @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) {
+        //error recovery:
         /* 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));
+        List<BindingSymbol> bindingsWhenTrue = union(pos, yTzT, xTzT, xFyT);
+        List<BindingSymbol> bindingsWhenFalse = union(pos, yFzF, xTzF, xFyF);
+        return new MatchBindings(bindingsWhenTrue, bindingsWhenFalse);
+    }
+
+    public MatchBindings unary(JCTree tree, MatchBindings bindings) {
+        if (bindings == EMPTY || !tree.hasTag(Tag.NOT)) return bindings;
+        return new MatchBindings(bindings.bindingsWhenFalse, bindings.bindingsWhenTrue);
+    }
+
+    public MatchBindings binary(JCTree tree, MatchBindings lhsBindings, MatchBindings rhsBindings) {
+        switch (tree.getTag()) {
+            case AND: {
+                // e.T = union(x.T, y.T)
+                // e.F = intersection(x.F, y.F) (error recovery)
+                List<BindingSymbol> bindingsWhenTrue =
+                        union(tree.pos(), lhsBindings.bindingsWhenTrue, rhsBindings.bindingsWhenTrue);
+                List<BindingSymbol> bindingsWhenFalse = //error recovery
+                        intersection(tree.pos(), lhsBindings.bindingsWhenFalse, rhsBindings.bindingsWhenFalse);
+                return new MatchBindings(bindingsWhenTrue, bindingsWhenFalse);
+            }
+            case OR: {
+                // e.T = intersection(x.T, y.T) (error recovery)
+                // e.F = union(x.F, y.F)
+                List<BindingSymbol> bindingsWhenTrue = //error recovery
+                        intersection(tree.pos(), lhsBindings.bindingsWhenTrue, rhsBindings.bindingsWhenTrue);
+                List<Symbol.BindingSymbol> bindingsWhenFalse =
+                        union(tree.pos(), lhsBindings.bindingsWhenFalse, rhsBindings.bindingsWhenFalse);
+                return new MatchBindings(bindingsWhenTrue, bindingsWhenFalse);
+            }
+        }
+        return EMPTY;
+    }
+
+    public MatchBindings finishBindings(JCTree tree, MatchBindings matchBindings) {
+        switch (tree.getTag()) {
+            case NOT: case AND: case OR: case BINDINGPATTERN:
+            case PARENS: case TYPETEST:
+            case CONDEXPR: //error recovery:
+                return matchBindings;
+            default:
+                return MatchBindingsComputer.EMPTY;
         }
     }
 
-    private List<BindingSymbol> intersection(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> rhsBindings) {
+    public static class MatchBindings {
+
+        public final List<BindingSymbol> bindingsWhenTrue;
+        public final List<BindingSymbol> bindingsWhenFalse;
+
+        public MatchBindings(List<BindingSymbol> bindingsWhenTrue, List<BindingSymbol> bindingsWhenFalse) {
+            this.bindingsWhenTrue = bindingsWhenTrue;
+            this.bindingsWhenFalse = bindingsWhenFalse;
+        }
+
+    }
+    private List<BindingSymbol> intersection(DiagnosticPosition pos, List<BindingSymbol> lhsBindings, List<BindingSymbol> rhsBindings) {
         // It is an error if, for intersection(a,b), if a and b contain the same variable name (may be eventually relaxed to merge variables of same type)
         List<BindingSymbol> list = List.nil();
         for (BindingSymbol v1 : lhsBindings) {
             for (BindingSymbol v2 : rhsBindings) {
-                if (v1.name == v2.name) {
-                    log.error(tree.pos(), Errors.MatchBindingExists);
+                if (v1.name == v2.name &&
+                    (v1.flags() & CLASH) == 0 &&
+                    (v2.flags() & CLASH) == 0) {
+                    log.error(pos, Errors.MatchBindingExists);
                     list = list.append(v2);
                 }
             }
@@ -168,14 +156,16 @@
     }
 
     @SafeVarargs
-    private final List<BindingSymbol> union(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> ... rhsBindings_s) {
+    private final List<BindingSymbol> union(DiagnosticPosition pos, 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);
+                    if (ov.name == v.name &&
+                        (ov.flags() & CLASH) == 0 &&
+                        (v.flags() & CLASH) == 0) {
+                        log.error(pos, Errors.MatchBindingExists);
                     }
                 }
                 list = list.append(v);
@@ -183,34 +173,4 @@
         }
         return list;
     }
-
-    @Override
-    public void scan(JCTree tree) {
-        bindings = List.nil();
-        super.scan(tree);
-    }
-
-    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;
-        }
-    }
-
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2020, 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
@@ -26,11 +26,12 @@
 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.BindingSymbol;
 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;
@@ -42,7 +43,6 @@
 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;
@@ -51,7 +51,6 @@
 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;
@@ -59,18 +58,18 @@
 
 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.comp.MatchBindingsComputer.BindingSymbol;
 import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.JCBlock;
 import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
+import com.sun.tools.javac.tree.JCTree.JCLambda;
 import com.sun.tools.javac.tree.JCTree.JCStatement;
 import com.sun.tools.javac.tree.JCTree.LetExpr;
 import com.sun.tools.javac.util.List;
+import java.util.HashMap;
 
 /**
  * This pass translates pattern-matching constructs, such as instanceof <pattern>.
@@ -93,11 +92,15 @@
     private final ConstFold constFold;
     private final Names names;
     private final Target target;
-    private final MatchBindingsComputer matchBindingsComputer;
     private TreeMaker make;
 
     BindingContext bindingContext = new BindingContext() {
         @Override
+        VarSymbol bindingDeclared(BindingSymbol varSymbol) {
+            return null;
+        }
+
+        @Override
         VarSymbol getBindingFor(BindingSymbol varSymbol) {
             return null;
         }
@@ -140,7 +143,6 @@
         constFold = ConstFold.instance(context);
         names = Names.instance(context);
         target = Target.instance(context);
-        matchBindingsComputer = MatchBindingsComputer.instance(context);
         debugTransPatterns = Options.instance(context).isSet("debug.patterns");
     }
 
@@ -164,8 +166,8 @@
 
             result = makeTypeTest(make.Ident(temp), make.Type(castTargetType));
 
-            VarSymbol bindingVar = bindingContext.getBindingFor(patt.symbol);
-            if (bindingVar != null) {
+            VarSymbol bindingVar = bindingContext.bindingDeclared(patt.symbol);
+            if (bindingVar != null) { //TODO: cannot be null here?
                 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,
@@ -180,20 +182,7 @@
 
     @Override
     public void visitBinary(JCBinary tree) {
-        List<BindingSymbol> matchBindings;
-        switch (tree.getTag()) {
-            case AND:
-                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true);
-                break;
-            case OR:
-                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false);
-                break;
-            default:
-                matchBindings = List.nil();
-                break;
-        }
-
-        bindingContext = new BasicBindingContext(matchBindings);
+        bindingContext = new BasicBindingContext();
         try {
             super.visitBinary(tree);
             result = bindingContext.decorateExpression(tree);
@@ -204,9 +193,7 @@
 
     @Override
     public void visitConditional(JCConditional tree) {
-        bindingContext = new BasicBindingContext(
-                matchBindingsComputer.getMatchBindings(tree.cond, true)
-                        .appendList(matchBindingsComputer.getMatchBindings(tree.cond, false)));
+        bindingContext = new BasicBindingContext();
         try {
             super.visitConditional(tree);
             result = bindingContext.decorateExpression(tree);
@@ -217,7 +204,7 @@
 
     @Override
     public void visitIf(JCIf tree) {
-        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        bindingContext = new BasicBindingContext();
         try {
             super.visitIf(tree);
             result = bindingContext.decorateStatement(tree);
@@ -228,7 +215,7 @@
 
     @Override
     public void visitForLoop(JCForLoop tree) {
-        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        bindingContext = new BasicBindingContext();
         try {
             super.visitForLoop(tree);
             result = bindingContext.decorateStatement(tree);
@@ -239,7 +226,7 @@
 
     @Override
     public void visitWhileLoop(JCWhileLoop tree) {
-        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        bindingContext = new BasicBindingContext();
         try {
             super.visitWhileLoop(tree);
             result = bindingContext.decorateStatement(tree);
@@ -250,7 +237,7 @@
 
     @Override
     public void visitDoLoop(JCDoWhileLoop tree) {
-        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        bindingContext = new BasicBindingContext();
         try {
             super.visitDoLoop(tree);
             result = bindingContext.decorateStatement(tree);
@@ -286,7 +273,7 @@
     @Override
     public void visitBlock(JCBlock tree) {
         ListBuffer<JCStatement> statements = new ListBuffer<>();
-        bindingContext = new BasicBindingContext(List.nil()) {
+        bindingContext = new BindingDeclarationFenceBindingContext() {
             boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
                 //{
                 //    if (E instanceof T N) {
@@ -319,6 +306,17 @@
         }
     }
 
+    @Override
+    public void visitLambda(JCLambda tree) {
+        BindingContext prevContent = bindingContext;
+        try {
+            bindingContext = new BindingDeclarationFenceBindingContext();
+            super.visitLambda(tree);
+        } finally {
+            bindingContext = prevContent;
+        }
+    }
+
     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
         try {
             this.make = make;
@@ -360,11 +358,8 @@
         return result;
     }
 
-    private List<BindingSymbol> getMatchBindings(JCExpression cond) {
-        return matchBindingsComputer.getMatchBindings(cond, true)
-                        .appendList(matchBindingsComputer.getMatchBindings(cond, false));
-    }
     abstract class BindingContext {
+        abstract VarSymbol bindingDeclared(BindingSymbol varSymbol);
         abstract VarSymbol getBindingFor(BindingSymbol varSymbol);
         abstract JCStatement decorateStatement(JCStatement stat);
         abstract JCExpression decorateExpression(JCExpression expr);
@@ -373,20 +368,23 @@
     }
 
     class BasicBindingContext extends BindingContext {
-        List<BindingSymbol> matchBindings;
         Map<BindingSymbol, VarSymbol> hoistedVarMap;
         BindingContext parent;
 
-        public BasicBindingContext(List<BindingSymbol> matchBindings) {
-            this.matchBindings = matchBindings;
+        public BasicBindingContext() {
             this.parent = bindingContext;
-            this.hoistedVarMap = matchBindings.stream()
-                    .filter(v -> parent.getBindingFor(v) == null)
-                    .collect(Collectors.toMap(v -> v, v -> {
-                        VarSymbol res = new VarSymbol(v.flags(), v.name, v.type, v.owner);
-                        res.setTypeAttributes(v.getRawTypeAttributes());
-                        return res;
-                    }));
+            this.hoistedVarMap = new HashMap<>();
+        }
+
+        @Override
+        VarSymbol bindingDeclared(BindingSymbol varSymbol) {
+            VarSymbol res = parent.bindingDeclared(varSymbol);
+            if (res == null) {
+                res = new VarSymbol(varSymbol.flags(), varSymbol.name, varSymbol.type, varSymbol.owner);
+                res.setTypeAttributes(varSymbol.getRawTypeAttributes());
+                hoistedVarMap.put(varSymbol, res);
+            }
+            return res;
         }
 
         @Override
@@ -454,4 +452,13 @@
             return make.at(pos).VarDef(varSymbol, null);
         }
     }
+
+    private class BindingDeclarationFenceBindingContext extends BasicBindingContext {
+
+        @Override
+        VarSymbol bindingDeclared(BindingSymbol varSymbol) {
+            return null;
+        }
+
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -38,7 +38,6 @@
 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;
--- a/test/langtools/tools/javac/patterns/BindingsExistTest.out	Tue Jan 14 10:55:11 2020 +0530
+++ b/test/langtools/tools/javac/patterns/BindingsExistTest.out	Tue Jan 14 11:10:07 2020 +0100
@@ -1,4 +1,4 @@
-BindingsExistTest.java:9:36: compiler.err.match.binding.exists
+BindingsExistTest.java:9:61: compiler.err.match.binding.exists
 BindingsExistTest.java:11:36: compiler.err.match.binding.exists
 BindingsExistTest.java:16:35: compiler.err.already.defined: kindname.variable, k, kindname.method, t(java.lang.Object,java.lang.Object)
 BindingsExistTest.java:19:34: compiler.err.already.defined: kindname.variable, s2, kindname.method, t(java.lang.Object,java.lang.Object)
--- a/test/langtools/tools/javac/patterns/BindingsTest1.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/test/langtools/tools/javac/patterns/BindingsTest1.java	Tue Jan 14 11:10:07 2020 +0100
@@ -188,6 +188,41 @@
         boolean result = (o1 instanceof String a1) ? (o1 instanceof String a2) : (!(o1 instanceof String a3));
         boolean result2 = (o1 instanceof String a1) ? (o1 instanceof String a2) : (!(switch (0) { default -> false; }));
 
+        //binding in an expression lambda:
+        if (!((VoidPredicate) () -> o1 instanceof String str && !str.isEmpty()).get()) {
+            throw new AssertionError();
+        }
+
+        //binding in an block lambda:
+        if (!((VoidPredicate) () -> o1 instanceof String str && !str.isEmpty()).get()) {
+            throw new AssertionError();
+        }
+
+        //binding in an anonymous class:
+        if (!new VoidPredicate() { public boolean get() { return o1 instanceof String str && !str.isEmpty();} }.get()) {
+            throw new AssertionError();
+        }
+
+        if (!switch (i) {
+            default:
+                if (!(o1 instanceof String str)) {
+                    yield false;
+                }
+                if (str.isEmpty()) {
+                    yield true;
+                }
+                yield true;
+            }) {
+            throw new AssertionError();
+        }
+
         System.out.println("BindingsTest1 complete");
     }
+
+    interface VoidPredicate {
+        public boolean get();
+    }
+    static boolean id(boolean b) {
+        return b;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ConditionalTest.java	Tue Jan 14 11:10:07 2020 +0100
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8236670
+ * @summary Verify proper scope of binding related to loops and breaks.
+ * @library /tools/lib /tools/javac/lib
+ * @modules
+ *      java.base/jdk.internal
+ *      jdk.compiler/com.sun.tools.javac.api
+ *      jdk.compiler/com.sun.tools.javac.file
+ *      jdk.compiler/com.sun.tools.javac.main
+ *      jdk.compiler/com.sun.tools.javac.util
+ * @build toolbox.ToolBox toolbox.JavacTask
+ * @build combo.ComboTestHelper
+ * @compile --enable-preview -source ${jdk.version} ConditionalTest.java
+ * @run main/othervm --enable-preview ConditionalTest
+ */
+
+import combo.ComboInstance;
+import combo.ComboParameter;
+import combo.ComboTask;
+import combo.ComboTestHelper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import toolbox.ToolBox;
+
+public class ConditionalTest extends ComboInstance<ConditionalTest> {
+    protected ToolBox tb;
+
+    ConditionalTest() {
+        super();
+        tb = new ToolBox();
+    }
+
+    public static void main(String... args) throws Exception {
+        new ComboTestHelper<ConditionalTest>()
+                .withDimension("COND", (x, cond) -> x.cond = cond, Pattern.values())
+                .withDimension("TRUE", (x, trueSec) -> x.trueSec = trueSec, Pattern.values())
+                .withDimension("FALSE", (x, falseSec) -> x.falseSec = falseSec, Pattern.values())
+                .run(ConditionalTest::new);
+    }
+
+    private Pattern cond;
+    private Pattern trueSec;
+    private Pattern falseSec;
+
+    private static final String MAIN_TEMPLATE =
+            """
+            public class Test {
+                public static boolean doTest(Object o, boolean b) {
+                    return #{COND} ? #{TRUE} : #{FALSE}
+                }
+            }
+            """;
+
+    @Override
+    protected void doWork() throws Throwable {
+        Path base = Paths.get(".");
+
+        ComboTask task = newCompilationTask()
+                .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) {
+                        case "COND" -> cond;
+                        case "TRUE" -> trueSec;
+                        case "FALSE" -> falseSec;
+                        default -> throw new UnsupportedOperationException(pname);
+                    })
+                .withOption("--enable-preview")
+                .withOption("-source")
+                .withOption(String.valueOf(Runtime.version().feature()));
+
+        task.analyze(result -> {
+            boolean shouldPass;
+            if (cond == Pattern.TRUE && (trueSec == Pattern.TRUE || trueSec == Pattern.FALSE)) { //6 cases covered
+                shouldPass = false; //already in scope in true section
+            } else if (cond == Pattern.FALSE && (falseSec == Pattern.TRUE || falseSec == Pattern.FALSE)) { //6 cases covered
+                shouldPass = false; //already in scope in false section
+            } else if (cond == Pattern.TRUE && falseSec == Pattern.TRUE) {
+                shouldPass = false; //JLS 6.3.1.4
+            } else if (cond == Pattern.FALSE && trueSec == Pattern.TRUE) {
+                shouldPass = false; //JLS 6.3.1.4
+            } else if (trueSec == Pattern.TRUE && falseSec == Pattern.TRUE) {
+                shouldPass = false; //JLS 6.3.1.4
+            } else if (trueSec == Pattern.TRUE && falseSec == Pattern.TRUE) {
+                shouldPass = false; //JLS 6.3.1.4
+            } else if (cond == Pattern.TRUE && falseSec == Pattern.FALSE) {
+                shouldPass = false; //JLS 6.3.1.4
+            } else if (cond == Pattern.FALSE && trueSec == Pattern.FALSE) {
+                shouldPass = false; //JLS 6.3.1.4
+            } else if (trueSec == Pattern.FALSE && falseSec == Pattern.FALSE) {
+                shouldPass = false; //JLS 6.3.1.4
+            } else {
+                shouldPass = true;
+            }
+
+            if (!shouldPass) {
+                result.containsKey("Blabla");
+            }
+        });
+    }
+
+    public enum Pattern implements ComboParameter {
+        NONE("b"),
+        TRUE("o instanceof String s"),
+        FALSE("!(o instanceof String s)");
+        private final String code;
+
+        private Pattern(String code) {
+            this.code = code;
+        }
+
+        @Override
+        public String expand(String optParameter) {
+            return code;
+        }
+    }
+
+}
--- a/test/langtools/tools/javac/patterns/DuplicateBindingTest.java	Tue Jan 14 10:55:11 2020 +0530
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.java	Tue Jan 14 11:10:07 2020 +0100
@@ -9,7 +9,7 @@
 
     int f;
 
-    public static void main(String[] args) {
+    public static boolean main(String[] args) {
 
         if (args != null) {
             int s;
@@ -18,5 +18,45 @@
             if (args[0] instanceof String f) { // OK to redef field.
             }
         }
+
+        Object o1 = "";
+        Object o2 = "";
+
+        if (o1 instanceof String s && o2 instanceof String s) {} //error - already in scope on RHS (in scope due to LHS when true)
+        if (o1 instanceof String s && !(o2 instanceof String s)) {} //error - already in scope on RHS (in scope due to LHS when true)
+        if (!(o1 instanceof String s) && !(o2 instanceof String s)) {} //error - the same binding variable on LHS and RHS when false
+        if (!(o1 instanceof String s) && (o2 instanceof String s)) {} //ok
+
+        if (!(o1 instanceof String s) || o2 instanceof String s) {} //error - already in scope on RHS (in scope due to LHS when false)
+        if (!(o1 instanceof String s) || !(o2 instanceof String s)) {} //error - already in scope on RHS (in scope due to LHS when false)
+        if (o1 instanceof String s || o2 instanceof String s) {} //error - the same binding variable on LHS and RHS when true
+        if (o1 instanceof String s || !(o2 instanceof String s)) {} //ok
+
+        if (o1 instanceof String s ? o2 instanceof String s : true) {} //error - already in scope in the true section (due to condition when true)
+        if (o1 instanceof String s ? true : o2 instanceof String s) {} //error - the same binding variable in condition when true and false section when true
+        if (!(o1 instanceof String s) ? o2 instanceof String s : true) {} //error - the same binding variable in condition when false and true section when true
+        if (args.length == 1 ? o2 instanceof String s : o2 instanceof String s) {} //error - the same binding variable in true section when true and false section when true
+        if (o1 instanceof String s ? true : !(o2 instanceof String s)) {} //error - the same binding variable in condition when true and false section when false
+        if (!(o1 instanceof String s) ? !(o2 instanceof String s) : true) {} //error - the same binding variable in condition when false and true section when false
+        if (args.length == 1 ? !(o2 instanceof String s) : !(o2 instanceof String s)) {} //error - the same binding variable in true section when false and false section when false
+
+        //verify that errors are reported to clashes in expression in non-conditional statements:
+        boolean b = o1 instanceof String s && o2 instanceof String s;
+        b = o1 instanceof String s && o2 instanceof String s;
+        b &= o1 instanceof String s && o2 instanceof String s;
+        assert o1 instanceof String s && o2 instanceof String s;
+        testMethod(o1 instanceof String s && o2 instanceof String s, false);
+        b = switch (args.length) { default -> o1 instanceof String s && o2 instanceof String s; };
+        b = switch (args.length) { default -> { yield o1 instanceof String s && o2 instanceof String s; } };
+        if (true) return o1 instanceof String s && o2 instanceof String s;
+
+        //verify the bindings don't go through method invocation parameters or outside a lambda:
+        b = ((VoidPredicate) () -> o1 instanceof String s).get() && s.isEmpty();
+        testMethod(o1 instanceof String s, s.isEmpty());
+    }
+
+    static void testMethod(boolean b1, boolean b2) {}
+    interface VoidPredicate {
+        public boolean get();
     }
 }
--- a/test/langtools/tools/javac/patterns/DuplicateBindingTest.out	Tue Jan 14 10:55:11 2020 +0530
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.out	Tue Jan 14 11:10:07 2020 +0100
@@ -1,4 +1,27 @@
 DuplicateBindingTest.java:16:43: compiler.err.already.defined: kindname.variable, s, kindname.method, main(java.lang.String[])
+DuplicateBindingTest.java:25:60: compiler.err.match.binding.exists
+DuplicateBindingTest.java:26:62: compiler.err.match.binding.exists
+DuplicateBindingTest.java:27:39: compiler.err.match.binding.exists
+DuplicateBindingTest.java:30:63: compiler.err.match.binding.exists
+DuplicateBindingTest.java:31:65: compiler.err.match.binding.exists
+DuplicateBindingTest.java:32:36: compiler.err.match.binding.exists
+DuplicateBindingTest.java:35:59: compiler.err.match.binding.exists
+DuplicateBindingTest.java:36:36: compiler.err.match.binding.exists
+DuplicateBindingTest.java:37:39: compiler.err.match.binding.exists
+DuplicateBindingTest.java:38:30: compiler.err.match.binding.exists
+DuplicateBindingTest.java:39:36: compiler.err.match.binding.exists
+DuplicateBindingTest.java:40:39: compiler.err.match.binding.exists
+DuplicateBindingTest.java:41:30: compiler.err.match.binding.exists
+DuplicateBindingTest.java:44:68: compiler.err.match.binding.exists
+DuplicateBindingTest.java:45:60: compiler.err.match.binding.exists
+DuplicateBindingTest.java:46:61: compiler.err.match.binding.exists
+DuplicateBindingTest.java:47:63: compiler.err.match.binding.exists
+DuplicateBindingTest.java:48:67: compiler.err.match.binding.exists
+DuplicateBindingTest.java:49:94: compiler.err.match.binding.exists
+DuplicateBindingTest.java:50:102: compiler.err.match.binding.exists
+DuplicateBindingTest.java:51:73: compiler.err.match.binding.exists
+DuplicateBindingTest.java:54:69: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, DuplicateBindingTest, null)
+DuplicateBindingTest.java:55:44: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, DuplicateBindingTest, null)
 - compiler.note.preview.filename: DuplicateBindingTest.java
 - compiler.note.preview.recompile
-1 error
+24 errors
--- a/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out	Tue Jan 14 10:55:11 2020 +0530
+++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out	Tue Jan 14 11:10:07 2020 +0100
@@ -1,5 +1,5 @@
 MatchBindingScopeTest.java:19:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
-MatchBindingScopeTest.java:23:36: compiler.err.match.binding.exists
+MatchBindingScopeTest.java:23:61: compiler.err.match.binding.exists
 MatchBindingScopeTest.java:30:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
 MatchBindingScopeTest.java:31:32: compiler.err.cant.resolve.location: kindname.variable, k, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
 MatchBindingScopeTest.java:34:39: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
@@ -13,4 +13,4 @@
 MatchBindingScopeTest.java:65:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
 - compiler.note.preview.filename: MatchBindingScopeTest.java
 - compiler.note.preview.recompile
-13 errors
+13 errors
\ No newline at end of file