Fix for KT-9022: Wrong result when use break in if condition

#KT-9022 Fixed
This commit is contained in:
Michael Bogdanov
2015-11-11 13:17:18 +03:00
parent 20ca8cd435
commit 3f995935d3
6 changed files with 125 additions and 33 deletions
@@ -1229,7 +1229,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private StackValue generateBreakOrContinueExpression(
@NotNull KtExpressionWithLabel expression,
boolean isBreak,
@NotNull Label afterBreakContinueLabel
final @NotNull Label afterBreakContinueLabel
) {
assert expression instanceof KtContinueExpression || expression instanceof KtBreakExpression;
@@ -1248,10 +1248,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (labelElement == null ||
loopBlockStackElement.targetLabel != null &&
labelElement.getReferencedName().equals(loopBlockStackElement.targetLabel.getReferencedName())) {
Label label = isBreak ? loopBlockStackElement.breakLabel : loopBlockStackElement.continueLabel;
PseudoInsnsKt.fixStackAndJump(v, label);
v.mark(afterBreakContinueLabel);
return StackValue.none();
final Label label = isBreak ? loopBlockStackElement.breakLabel : loopBlockStackElement.continueLabel;
return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter adapter) {
PseudoInsnsKt.fixStackAndJump(v, label);
v.mark(afterBreakContinueLabel);
return Unit.INSTANCE;
}
}
);
}
}
else {
@@ -1859,33 +1865,37 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@Override
public StackValue visitReturnExpression(@NotNull KtReturnExpression expression, StackValue receiver) {
KtExpression returnedExpression = expression.getReturnedExpression();
CallableMemberDescriptor descriptor = getContext().getContextDescriptor();
NonLocalReturnInfo nonLocalReturn = getNonLocalReturnInfo(descriptor, expression);
boolean isNonLocalReturn = nonLocalReturn != null;
if (isNonLocalReturn && !state.isInlineEnabled()) {
state.getDiagnostics().report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression));
genThrow(v, "java/lang/UnsupportedOperationException",
"Non-local returns are not allowed with inlining disabled");
return StackValue.none();
}
public StackValue visitReturnExpression(@NotNull final KtReturnExpression expression, StackValue receiver) {
return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter adapter) {
KtExpression returnedExpression = expression.getReturnedExpression();
CallableMemberDescriptor descriptor = getContext().getContextDescriptor();
NonLocalReturnInfo nonLocalReturn = getNonLocalReturnInfo(descriptor, expression);
boolean isNonLocalReturn = nonLocalReturn != null;
if (isNonLocalReturn && !state.isInlineEnabled()) {
state.getDiagnostics().report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression));
genThrow(v, "java/lang/UnsupportedOperationException",
"Non-local returns are not allowed with inlining disabled");
return Unit.INSTANCE;
}
Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : this.returnType;
if (returnedExpression != null) {
gen(returnedExpression, returnType);
}
Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : ExpressionCodegen.this.returnType;
if (returnedExpression != null) {
gen(returnedExpression, returnType);
}
Label afterReturnLabel = new Label();
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel);
Label afterReturnLabel = new Label();
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel);
if (isNonLocalReturn) {
InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName);
}
v.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
v.mark(afterReturnLabel);
return StackValue.none();
if (isNonLocalReturn) {
InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName);
}
v.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
v.mark(afterReturnLabel);
return Unit.INSTANCE;
}
});
}
public void generateFinallyBlocksIfNeeded(Type returnType, @NotNull Label afterReturnLabel) {
@@ -3571,10 +3581,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@Override
public StackValue visitThrowExpression(@NotNull KtThrowExpression expression, StackValue receiver) {
gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
v.athrow();
return StackValue.none();
public StackValue visitThrowExpression(@NotNull final KtThrowExpression expression, StackValue receiver) {
return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter adapter) {
gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
v.athrow();
return Unit.INSTANCE;
}
});
}
@Override
@@ -0,0 +1,9 @@
fun box(): String {
var cycle = true;
while (true) {
if (true && break) {
return "fail"
}
}
return "OK"
}
@@ -0,0 +1,9 @@
fun box(): String {
var cycle = true;
while (true) {
if (true || break) {
return "OK"
}
}
return "fail"
}
@@ -0,0 +1,26 @@
fun testOr(b: Boolean): Boolean {
return b || return !b;
}
fun testOr(): Boolean {
return true || return false;
}
fun testAnd(b: Boolean): Boolean {
return b && return !b;
}
fun testAnd(): Boolean {
return true && return false;
}
fun box(): String {
if (testOr(false) != true) return "fail 1"
if (testOr(true) != true) return "fail 2"
if (testAnd(false) != false) return "fail 3"
if (testAnd(true) != false) return "fail 4"
if (testOr() != true) return "fail 5"
if (testAnd() != false) return "fail 6"
return "OK"
}
@@ -0,0 +1,9 @@
fun box(): String {
var cycle = true;
while (true) {
if (true || throw java.lang.RuntimeException()) {
return "OK"
}
}
return "fail"
}
@@ -2368,6 +2368,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt9022Return.kt")
public void testKt9022Return() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/kt9022Return.kt");
doTest(fileName);
}
@TestMetadata("kt9022Throw.kt")
public void testKt9022Throw() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/kt9022Throw.kt");
doTest(fileName);
}
@TestMetadata("kt910.kt")
public void testKt910() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/kt910.kt");
@@ -2436,6 +2448,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("kt9022And.kt")
public void testKt9022And() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022And.kt");
doTest(fileName);
}
@TestMetadata("kt9022Or.kt")
public void testKt9022Or() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/kt9022Or.kt");
doTest(fileName);
}
@TestMetadata("popSizes.kt")
public void testPopSizes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/breakContinueInExpressions/popSizes.kt");