8214114: Switch expressions with try-catch statements
authorjlahoda
Tue, 11 Dec 2018 09:10:24 +0100
changeset 52936 9745e4e36dd1
parent 52935 4aa8fe00ace9
child 52937 d2206a60da32
8214114: Switch expressions with try-catch statements Summary: When switch expression contains try-catch, move the stack values into locals before the executing the switch expression, and back when it is done. Reviewed-by: mcimadamore, vromero
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java
test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java
test/langtools/tools/javac/switchexpr/TryCatch.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Dec 11 08:05:38 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Dec 11 09:10:24 2018 +0100
@@ -1121,7 +1121,7 @@
 
     public void visitVarDef(JCVariableDecl tree) {
         // Local variables have not been entered yet, so we need to do it now:
-        if (env.info.scope.owner.kind == MTH) {
+        if (env.info.scope.owner.kind == MTH || env.info.scope.owner.kind == VAR) {
             if (tree.sym != null) {
                 // parameters have already been entered
                 env.info.scope.enter(tree.sym);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Dec 11 08:05:38 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Dec 11 09:10:24 2018 +0100
@@ -1633,7 +1633,7 @@
         protected boolean trackable(VarSymbol sym) {
             return
                 sym.pos >= startPos &&
-                ((sym.owner.kind == MTH ||
+                ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
                 isFinalUninitializedField(sym)));
         }
 
@@ -2009,7 +2009,7 @@
             lint = lint.augment(tree.sym);
             try{
                 boolean track = trackable(tree.sym);
-                if (track && tree.sym.owner.kind == MTH) {
+                if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) {
                     newVar(tree);
                 }
                 if (tree.init != null) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Dec 11 08:05:38 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Dec 11 09:10:24 2018 +0100
@@ -25,8 +25,6 @@
 
 package com.sun.tools.javac.jvm;
 
-import java.util.function.BiConsumer;
-
 import com.sun.tools.javac.tree.TreeInfo.PosKind;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -166,6 +164,7 @@
     boolean inCondSwitchExpression;
     Chain switchExpressionTrueChain;
     Chain switchExpressionFalseChain;
+    List<LocalItem> stackBeforeSwitchExpression;
 
     /** Generate code to load an integer constant.
      *  @param n     The integer to be loaded.
@@ -1178,13 +1177,59 @@
     }
 
     private void doHandleSwitchExpression(JCSwitchExpression tree) {
-        int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
+        List<LocalItem> prevStackBeforeSwitchExpression = stackBeforeSwitchExpression;
+        int limit = code.nextreg;
         try {
-            handleSwitch(tree, tree.selector, tree.cases);
+            stackBeforeSwitchExpression = List.nil();
+            if (hasTry(tree)) {
+                //if the switch expression contains try-catch, the catch handlers need to have
+                //an empty stack. So stash whole stack to local variables, and restore it before
+                //breaks:
+                while (code.state.stacksize > 0) {
+                    Type type = code.state.peek();
+                    Name varName = names.fromString(target.syntheticNameChar() +
+                                                    "stack" +
+                                                    target.syntheticNameChar() +
+                                                    tree.pos +
+                                                    target.syntheticNameChar() +
+                                                    code.state.stacksize);
+                    VarSymbol var = new VarSymbol(Flags.SYNTHETIC, varName, type,
+                                                  this.env.enclMethod.sym);
+                    LocalItem item = items.new LocalItem(type, code.newLocal(var));
+                    stackBeforeSwitchExpression = stackBeforeSwitchExpression.prepend(item);
+                    item.store();
+                }
+            }
+            int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
+            try {
+                handleSwitch(tree, tree.selector, tree.cases);
+            } finally {
+                code.setLetExprStackPos(prevLetExprStart);
+            }
         } finally {
-            code.setLetExprStackPos(prevLetExprStart);
+            stackBeforeSwitchExpression = prevStackBeforeSwitchExpression;
+            code.endScopes(limit);
         }
     }
+    //where:
+        private boolean hasTry(JCSwitchExpression tree) {
+            boolean[] hasTry = new boolean[1];
+            new TreeScanner() {
+                @Override
+                public void visitTry(JCTry tree) {
+                    hasTry[0] = true;
+                }
+
+                @Override
+                public void visitClassDef(JCClassDecl tree) {
+                }
+
+                @Override
+                public void visitLambda(JCLambda tree) {
+                }
+            }.scan(tree);
+            return hasTry[0];
+        }
 
     private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases) {
         int limit = code.nextreg;
@@ -1659,14 +1704,17 @@
     }
 
     public void visitBreak(JCBreak tree) {
-        int tmpPos = code.pendingStatPos;
         Assert.check(code.isStatementStart());
-        Env<GenContext> targetEnv = unwind(tree.target, env);
-        code.pendingStatPos = tmpPos;
+        final Env<GenContext> targetEnv;
         if (tree.isValueBreak()) {
+            //restore stack as it was before the switch expression:
+            for (LocalItem li : stackBeforeSwitchExpression) {
+                li.load();
+            }
             if (inCondSwitchExpression) {
                 CondItem value = genCond(tree.value, CRT_FLOW_TARGET);
                 Chain falseJumps = value.jumpFalse();
+                targetEnv = unwindBreak(tree);
                 code.resolve(value.trueJumps);
                 Chain trueJumps = code.branch(goto_);
                 if (switchExpressionTrueChain == null) {
@@ -1684,13 +1732,22 @@
             } else {
                 genExpr(tree.value, pt).load();
                 code.state.forceStackTop(tree.target.type);
+                targetEnv = unwindBreak(tree);
                 targetEnv.info.addExit(code.branch(goto_));
             }
         } else {
+            targetEnv = unwindBreak(tree);
             targetEnv.info.addExit(code.branch(goto_));
         }
         endFinalizerGaps(env, targetEnv);
     }
+    //where:
+        private Env<GenContext> unwindBreak(JCBreak tree) {
+            int tmpPos = code.pendingStatPos;
+            Env<GenContext> targetEnv = unwind(tree.target, env);
+            code.pendingStatPos = tmpPos;
+            return targetEnv;
+        }
 
     public void visitContinue(JCContinue tree) {
         int tmpPos = code.pendingStatPos;
@@ -2138,7 +2195,7 @@
                 res = items.makeMemberItem(sym, true);
             }
             result = res;
-        } else if (sym.kind == VAR && sym.owner.kind == MTH) {
+        } else if (sym.kind == VAR && (sym.owner.kind == MTH || sym.owner.kind == VAR)) {
             result = items.makeLocalItem((VarSymbol)sym);
         } else if (isInvokeDynamic(sym)) {
             result = items.makeDynamicItem(sym);
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java	Tue Dec 11 08:05:38 2018 +0800
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java	Tue Dec 11 09:10:24 2018 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8206986 8214529
+ * @bug 8206986 8214114 8214529
  * @summary Verify various corner cases with nested switch expressions.
  * @compile --enable-preview -source 12 ExpressionSwitchBugs.java
  * @run main/othervm --enable-preview ExpressionSwitchBugs
@@ -33,6 +33,7 @@
     public static void main(String... args) {
         new ExpressionSwitchBugs().testNested();
         new ExpressionSwitchBugs().testAnonymousClasses();
+        new ExpressionSwitchBugs().testFields();
     }
 
     private void testNested() {
@@ -84,6 +85,33 @@
         }
     }
 
+    private void testFields() {
+        check(3, field);
+        check(3, ExpressionSwitchBugs.staticField);
+    }
+
+    private final int value = 2;
+    private final int field = id(switch(value) {
+        case 0 -> -1;
+        case 2 -> {
+            int temp = 0;
+            temp += 3;
+            break temp;
+        }
+        default -> throw new IllegalStateException();
+    });
+
+    private static final int staticValue = 2;
+    private static final int staticField = new ExpressionSwitchBugs().id(switch(staticValue) {
+        case 0 -> -1;
+        case 2 -> {
+            int temp = 0;
+            temp += 3;
+            break temp;
+        }
+        default -> throw new IllegalStateException();
+    });
+
     private int id(int i) {
         return i;
     }
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java	Tue Dec 11 08:05:38 2018 +0800
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java	Tue Dec 11 09:10:24 2018 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8214031
+ * @bug 8214031 8214114
  * @summary Verify switch expressions embedded in various statements work properly.
  * @compile --enable-preview -source 12 ExpressionSwitchEmbedding.java
  * @run main/othervm --enable-preview ExpressionSwitchEmbedding
@@ -66,6 +66,50 @@
         {
             int i = 6;
             int o = 0;
+            while (switch (i) {
+                case 1: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 0; break true; }
+                case 2: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 1; break true; }
+                case 3, 4:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        if (i == 2 || i == 4) {
+                            try {
+                                break switch (i) {
+                                    case 2 -> throw new ResultException(true);
+                                    case 4 -> false;
+                                    default -> throw new IllegalStateException();
+                                };
+                            } catch (ResultException ex) {
+                                break ex.result;
+                            }
+                        } else {
+                            break true;
+                        }
+                    }
+                default:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        break switch (i) {
+                            case -1 -> false;
+                            case 3 -> true;
+                            default -> true;
+                        };
+                    }
+                    throw new AssertionError();
+            }) {
+                o++;
+            }
+            if (o != 6 && i >= 0) {
+                throw new IllegalStateException();
+            }
+        }
+        {
+            int i = 6;
+            int o = 0;
             if (switch (i) {
                 case 1: i = 0; break true;
                 case 2: i = 1; break true;
@@ -92,6 +136,50 @@
             }
         }
         {
+            int i = 6;
+            int o = 0;
+            if (switch (i) {
+                case 1: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 0; break true; }
+                case 2: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 1; break true; }
+                case 3, 4:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        if (i == 2 || i == 4) {
+                            try {
+                                break switch (i) {
+                                    case 2 -> throw new ResultException(true);
+                                    case 4 -> false;
+                                    default -> throw new IllegalStateException();
+                                };
+                            } catch (ResultException ex) {
+                                break ex.result;
+                            }
+                        } else {
+                            break true;
+                        }
+                    }
+                default:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        break switch (i) {
+                            case -1 -> false;
+                            case 3 -> true;
+                            default -> true;
+                        };
+                    }
+                    throw new AssertionError();
+            }) {
+                o++;
+            }
+            if (o != 1 && i != 5) {
+                throw new IllegalStateException();
+            }
+        }
+        {
             int o = 0;
             for (int i = 6; (switch (i) {
                 case 1: i = 0; break true;
@@ -119,6 +207,49 @@
             }
         }
         {
+            int o = 0;
+            for (int i = 6; (switch (i) {
+                case 1: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 0; break true; }
+                case 2: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 1; break true; }
+                case 3, 4:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        if (i == 2 || i == 4) {
+                            try {
+                                break switch (i) {
+                                    case 2 -> throw new ResultException(true);
+                                    case 4 -> false;
+                                    default -> throw new IllegalStateException();
+                                };
+                            } catch (ResultException ex) {
+                                break ex.result;
+                            }
+                        } else {
+                            break true;
+                        }
+                    }
+                default:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        break switch (i) {
+                            case -1 -> false;
+                            case 3 -> true;
+                            default -> true;
+                        };
+                    }
+                    throw new AssertionError();
+            }); ) {
+                o++;
+            }
+            if (o != 6) {
+                throw new IllegalStateException();
+            }
+        }
+        {
             int i = 6;
             int o = 0;
             do {
@@ -146,6 +277,60 @@
                 throw new IllegalStateException();
             }
         }
+        {
+            int i = 6;
+            int o = 0;
+            do {
+                o++;
+            } while (switch (i) {
+                case 1: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 0; break true; }
+                case 2: try { new ExpressionSwitchEmbedding().throwException(); } catch (Throwable t) { i = 1; break true; }
+                case 3, 4:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        if (i == 2 || i == 4) {
+                            try {
+                                break switch (i) {
+                                    case 2 -> throw new ResultException(true);
+                                    case 4 -> false;
+                                    default -> throw new IllegalStateException();
+                                };
+                            } catch (ResultException ex) {
+                                break ex.result;
+                            }
+                        } else {
+                            break true;
+                        }
+                    }
+                default:
+                    try {
+                        new ExpressionSwitchEmbedding().throwException();
+                    } catch (Throwable t) {
+                        i--;
+                        break switch (i) {
+                            case -1 -> false;
+                            case 3 -> true;
+                            default -> true;
+                        };
+                    }
+                    throw new AssertionError();
+            });
+            if (o != 6 && i >= 0) {
+                throw new IllegalStateException();
+            }
+        }
     }
 
+    private void throwException() {
+        throw new RuntimeException();
+    }
+
+    private static final class ResultException extends RuntimeException {
+        public final boolean result;
+        public ResultException(boolean result) {
+            this.result = result;
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/TryCatch.java	Tue Dec 11 09:10:24 2018 +0100
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8214114
+ * @summary Verify try-catch inside a switch expression works properly.
+ * @compile --enable-preview -source 12 TryCatch.java
+ * @run main/othervm --enable-preview TryCatch
+ */
+public class TryCatch {
+    public static void main(String[] args) {
+        {
+            int val = 3;
+            for (int p : new int[] {0, 1, 2}) {
+                int res = 1 + new TryCatch().id(switch(p) {
+                    case 0 -> switch (p + 1) {
+                        case 1:
+                            try {
+                                new TryCatch().throwException();
+                                break -1;
+                            } catch(Throwable ex) {
+                                break val;
+                            }
+                        default: break -1;
+                    };
+                    case 1 -> {
+                        try {
+                            break new TryCatch().id(switch (p + 1) {
+                                case 2:
+                                    try {
+                                        new TryCatch().throwException();
+                                        break -1;
+                                    } catch(Throwable ex) {
+                                        throw ex;
+                                    }
+                                default: break -1;
+                            });
+                        } catch(Throwable ex) {
+                            break val;
+                        }
+                    }
+                    default -> {
+                        try {
+                            new TryCatch().throwException();
+                            break -1;
+                        } catch(Throwable ex) {
+                            break val;
+                        }
+                    }
+                } - 1);
+                if (res != 3) {
+                    throw new AssertionError("Unexpected result: " + res);
+                }
+            }
+        }
+        {
+            int val = 3;
+            for (int p : new int[] {0, 1, 2}) {
+                int x;
+                int res = new TryCatch().id(val == 3 && switch(p) {
+                    case 0 -> switch (p + 1) {
+                        case 1:
+                            try {
+                                new TryCatch().throwException();
+                                break false;
+                            } catch(Throwable ex) {
+                                break true;
+                            }
+                        default: break false;
+                    };
+                    case 1 -> {
+                        try {
+                            break new TryCatch().id(switch (p + 1) {
+                                case 2:
+                                    try {
+                                        new TryCatch().throwException();
+                                        break false;
+                                    } catch(Throwable ex) {
+                                        throw ex;
+                                    }
+                                default: break false;
+                            });
+                        } catch(Throwable ex) {
+                            break true;
+                        }
+                    }
+                    default -> {
+                        try {
+                            new TryCatch().throwException();
+                            break false;
+                        } catch(Throwable ex) {
+                            break true;
+                        }
+                    }
+                } && (x = 1) == 1 && x == 1 ? val : -1);
+                if (res != 3) {
+                    throw new AssertionError("Unexpected result: " + res);
+                }
+            }
+        }
+        {
+            int val = 3;
+            for (E e : new E[] {E.A, E.B, E.C}) {
+                int res = 1 + new TryCatch().id(switch(e) {
+                    case A -> switch (e.next()) {
+                        case B:
+                            try {
+                                new TryCatch().throwException();
+                                break -1;
+                            } catch(Throwable ex) {
+                                break val;
+                            }
+                        default: break -1;
+                    };
+                    case B -> {
+                        try {
+                            break new TryCatch().id(switch (e.next()) {
+                                case C:
+                                    try {
+                                        new TryCatch().throwException();
+                                        break -1;
+                                    } catch(Throwable ex) {
+                                        throw ex;
+                                    }
+                                default: break -1;
+                            });
+                        } catch(Throwable ex) {
+                            break val;
+                        }
+                    }
+                    default -> {
+                        try {
+                            new TryCatch().throwException();
+                            break -1;
+                        } catch(Throwable ex) {
+                            break val;
+                        }
+                    }
+                } - 1);
+                if (res != 3) {
+                    throw new AssertionError("Unexpected result: " + res);
+                }
+            }
+        }
+        {
+            int val = 3;
+            for (E e : new E[] {E.A, E.B, E.C}) {
+                int x;
+                int res = new TryCatch().id(val == 3 && switch(e) {
+                    case A -> switch (e.next()) {
+                        case B:
+                            try {
+                                new TryCatch().throwException();
+                                break false;
+                            } catch(Throwable ex) {
+                                break true;
+                            }
+                        default: break false;
+                    };
+                    case B -> {
+                        try {
+                            break new TryCatch().id(switch (e.next()) {
+                                case C:
+                                    try {
+                                        new TryCatch().throwException();
+                                        break false;
+                                    } catch(Throwable ex) {
+                                        throw ex;
+                                    }
+                                default: break false;
+                            });
+                        } catch(Throwable ex) {
+                            break true;
+                        }
+                    }
+                    default -> {
+                        try {
+                            new TryCatch().throwException();
+                            break false;
+                        } catch(Throwable ex) {
+                            break true;
+                        }
+                    }
+                } && (x = 1) == 1 && x == 1 ? val : -1);
+                if (res != 3) {
+                    throw new AssertionError("Unexpected result: " + res);
+                }
+            }
+        }
+        {
+            int val = 3;
+            for (String s : new String[] {"", "a", "b"}) {
+                int res = 1 + new TryCatch().id(switch(s) {
+                    case "" -> switch (s + "c") {
+                        case "c":
+                            try {
+                                new TryCatch().throwException();
+                                break -1;
+                            } catch(Throwable ex) {
+                                break val;
+                            }
+                        default: break -1;
+                    };
+                    case "a" -> {
+                        try {
+                            break new TryCatch().id(switch (s + "c") {
+                                case "ac":
+                                    try {
+                                        new TryCatch().throwException();
+                                        break -1;
+                                    } catch(Throwable ex) {
+                                        throw ex;
+                                    }
+                                default: break -1;
+                            });
+                        } catch(Throwable ex) {
+                            break val;
+                        }
+                    }
+                    default -> {
+                        try {
+                            new TryCatch().throwException();
+                            break -1;
+                        } catch(Throwable ex) {
+                            break val;
+                        }
+                    }
+                } - 1);
+                if (res != 3) {
+                    throw new AssertionError("Unexpected result: " + res);
+                }
+            }
+        }
+        {
+            int val = 3;
+            for (String s : new String[] {"", "a", "b"}) {
+                int x;
+                int res = new TryCatch().id(val == 3 && switch(s) {
+                    case "" -> switch (s + "c") {
+                        case "c":
+                            try {
+                                new TryCatch().throwException();
+                                break false;
+                            } catch(Throwable ex) {
+                                break true;
+                            }
+                        default: break false;
+                    };
+                    case "a" -> {
+                        try {
+                            break new TryCatch().id(switch (s + "c") {
+                                case "ac":
+                                    try {
+                                        new TryCatch().throwException();
+                                        break false;
+                                    } catch(Throwable ex) {
+                                        throw ex;
+                                    }
+                                default: break false;
+                            });
+                        } catch(Throwable ex) {
+                            break true;
+                        }
+                    }
+                    default -> {
+                        try {
+                            new TryCatch().throwException();
+                            break false;
+                        } catch(Throwable ex) {
+                            break true;
+                        }
+                    }
+                } && (x = 1) == 1 && x == 1 ? val : -1);
+                if (res != 3) {
+                    throw new AssertionError("Unexpected result: " + res);
+                }
+            }
+        }
+
+        {
+            int res = new FieldHolder().intTest;
+
+            if (res != 3) {
+                throw new AssertionError("Unexpected result: " + res);
+            }
+        }
+        {
+            int res = FieldHolder.intStaticTest;
+
+            if (res != 3) {
+                throw new AssertionError("Unexpected result: " + res);
+            }
+        }
+        {
+            boolean res = new FieldHolder().booleanTest;
+
+            if (!res) {
+                throw new AssertionError("Unexpected result: " + res);
+            }
+        }
+        {
+            boolean res = FieldHolder.booleanStaticTest;
+
+            if (!res) {
+                throw new AssertionError("Unexpected result: " + res);
+            }
+        }
+    }
+
+    static class FieldHolder {
+        private final int intTest = switch (0) {
+            case -1: break -1;
+            default:
+                try {
+                    break new TryCatch().id(switch (2) {
+                        case 2:
+                            try {
+                                new TryCatch().throwException();
+                                break -1;
+                            } catch(Throwable ex) {
+                                throw ex;
+                            }
+                        default: break -1;
+                    });
+                } catch(Throwable ex) {
+                    break 3;
+                }
+        };
+        private static final int intStaticTest = switch (0) {
+            case -1: break -1;
+            default:
+                try {
+                    break new TryCatch().id(switch (2) {
+                        case 2:
+                            try {
+                                new TryCatch().throwException();
+                                break -1;
+                            } catch(Throwable ex) {
+                                throw ex;
+                            }
+                        default: break -1;
+                    });
+                } catch(Throwable ex) {
+                    break 3;
+                }
+        };
+        private final boolean booleanTest = switch (0) {
+            case -1: break false;
+            default:
+                try {
+                    break new TryCatch().id(switch (2) {
+                        case 2:
+                            try {
+                                new TryCatch().throwException();
+                                break false;
+                            } catch(Throwable ex) {
+                                throw ex;
+                            }
+                        default: break false;
+                    });
+                } catch(Throwable ex) {
+                    break true;
+                }
+        };
+        private static final boolean booleanStaticTest = switch (0) {
+            case -1: break false;
+            default:
+                try {
+                    break new TryCatch().id(switch (2) {
+                        case 2:
+                            try {
+                                new TryCatch().throwException();
+                                break false;
+                            } catch(Throwable ex) {
+                                throw ex;
+                            }
+                        default: break false;
+                    });
+                } catch(Throwable ex) {
+                    break true;
+                }
+        };
+    }
+
+    private int id(int i) {
+        return i;
+    }
+
+    private boolean id(boolean b) {
+        return b;
+    }
+
+    private void throwException() {
+        throw new RuntimeException();
+    }
+    enum E {
+        A, B, C;
+        public E next() {
+            return values()[(ordinal() + 1) % values().length];
+        }
+    }
+}