8214114: Switch expressions with try-catch statements
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
This commit is contained in:
parent
e048289d95
commit
655c5d7f35
src/jdk.compiler/share/classes/com/sun/tools/javac
test/langtools/tools/javac/switchexpr
@ -1121,7 +1121,7 @@ public class Attr extends JCTree.Visitor {
|
||||
|
||||
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);
|
||||
|
@ -1633,7 +1633,7 @@ public class Flow {
|
||||
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 @@ public class Flow {
|
||||
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) {
|
||||
|
@ -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 @@ public class Gen extends JCTree.Visitor {
|
||||
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 @@ public class Gen extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
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 class Gen extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
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 @@ public class Gen extends JCTree.Visitor {
|
||||
} 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 @@ public class Gen extends JCTree.Visitor {
|
||||
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);
|
||||
|
@ -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 class ExpressionSwitchBugs {
|
||||
public static void main(String... args) {
|
||||
new ExpressionSwitchBugs().testNested();
|
||||
new ExpressionSwitchBugs().testAnonymousClasses();
|
||||
new ExpressionSwitchBugs().testFields();
|
||||
}
|
||||
|
||||
private void testNested() {
|
||||
@ -84,6 +85,33 @@ public class ExpressionSwitchBugs {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
@ -63,6 +63,50 @@ public class ExpressionSwitchEmbedding {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
{
|
||||
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;
|
||||
@ -91,6 +135,50 @@ public class ExpressionSwitchEmbedding {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
{
|
||||
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) {
|
||||
@ -118,6 +206,49 @@ public class ExpressionSwitchEmbedding {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
{
|
||||
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;
|
||||
@ -146,6 +277,60 @@ public class ExpressionSwitchEmbedding {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
423
test/langtools/tools/javac/switchexpr/TryCatch.java
Normal file
423
test/langtools/tools/javac/switchexpr/TryCatch.java
Normal file
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user