Fix codegen of do-while condition
The condition of a do-while loop can use variables declared in the loop (variables can only be declared inside a block). Previously this behaviour caused crash because after the block was generated, all variables declared inside that block were gone from myFrameMap #KT-3280 Fixed
This commit is contained in:
@@ -55,7 +55,6 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
|||||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
|
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
@@ -421,22 +420,38 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackValue visitDoWhileExpression(JetDoWhileExpression expression, StackValue receiver) {
|
public StackValue visitDoWhileExpression(JetDoWhileExpression expression, StackValue receiver) {
|
||||||
Label condition = new Label();
|
Label continueLabel = new Label();
|
||||||
v.mark(condition);
|
v.mark(continueLabel);
|
||||||
|
|
||||||
Label end = new Label();
|
Label breakLabel = new Label();
|
||||||
|
|
||||||
blockStackElements.push(new LoopBlockStackElement(end, condition, targetLabel(expression)));
|
blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression)));
|
||||||
|
|
||||||
gen(expression.getBody(), Type.VOID_TYPE);
|
JetExpression body = expression.getBody();
|
||||||
|
JetExpression condition = expression.getCondition();
|
||||||
|
StackValue conditionValue;
|
||||||
|
|
||||||
final StackValue conditionValue = gen(expression.getCondition());
|
if (body instanceof JetBlockExpression) {
|
||||||
conditionValue.condJump(condition, false, v);
|
// If body's a block, it can contain variable declarations which may be used in the condition of a do-while loop.
|
||||||
|
// We handle this case separately because otherwise such variable will be out of the frame map after the block ends
|
||||||
|
List<JetElement> doWhileStatements = ((JetBlockExpression) body).getStatements();
|
||||||
|
|
||||||
v.mark(end);
|
List<JetElement> statements = new ArrayList<JetElement>(doWhileStatements.size() + 1);
|
||||||
|
statements.addAll(doWhileStatements);
|
||||||
|
statements.add(condition);
|
||||||
|
|
||||||
|
conditionValue = generateBlock(statements, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gen(body, Type.VOID_TYPE);
|
||||||
|
conditionValue = gen(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
conditionValue.condJump(continueLabel, false, v);
|
||||||
|
v.mark(breakLabel);
|
||||||
|
|
||||||
blockStackElements.pop();
|
blockStackElements.pop();
|
||||||
return StackValue.onStack(Type.VOID_TYPE);
|
return StackValue.none();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
fun box(): String {
|
||||||
|
var x = 0
|
||||||
|
do x++ while (x < 5)
|
||||||
|
if (x != 5) return "Fail 1 $x"
|
||||||
|
|
||||||
|
var y = 0
|
||||||
|
do { y++ } while (y < 5)
|
||||||
|
if (y != 5) return "Fail 2 $y"
|
||||||
|
|
||||||
|
var z = ""
|
||||||
|
do { z += z.length } while (z.length < 5)
|
||||||
|
if (z != "01234") return "Fail 3 $z"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
fun box(): String {
|
||||||
|
var fx = 1
|
||||||
|
var fy = 1
|
||||||
|
|
||||||
|
do {
|
||||||
|
var tmp = fy
|
||||||
|
fy = fx + fy
|
||||||
|
fx = tmp
|
||||||
|
} while (fy < 100)
|
||||||
|
|
||||||
|
return if (fy == 144) "OK" else "Fail $fx $fy"
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
fun foo() {
|
||||||
|
var x = 0
|
||||||
|
do {
|
||||||
|
x++
|
||||||
|
var y = x + 5
|
||||||
|
} while (y < 10)
|
||||||
|
if (x != 5) throw AssertionError("$x")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
var b = false
|
||||||
|
do {
|
||||||
|
var x = "X"
|
||||||
|
var y = "Y"
|
||||||
|
b = true
|
||||||
|
} while (x + y != "XY")
|
||||||
|
if (!b) throw AssertionError()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
foo()
|
||||||
|
bar()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -1012,6 +1012,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/continueToLabelInFor.kt");
|
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/continueToLabelInFor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("doWhile.kt")
|
||||||
|
public void testDoWhile() throws Exception {
|
||||||
|
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/doWhile.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("doWhileFib.kt")
|
||||||
|
public void testDoWhileFib() throws Exception {
|
||||||
|
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/doWhileFib.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("finallyOnEmptyReturn.kt")
|
@TestMetadata("finallyOnEmptyReturn.kt")
|
||||||
public void testFinallyOnEmptyReturn() throws Exception {
|
public void testFinallyOnEmptyReturn() throws Exception {
|
||||||
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/finallyOnEmptyReturn.kt");
|
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/finallyOnEmptyReturn.kt");
|
||||||
@@ -1157,6 +1167,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt3273.kt");
|
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt3273.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt3280.kt")
|
||||||
|
public void testKt3280() throws Exception {
|
||||||
|
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt3280.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt416.kt")
|
@TestMetadata("kt416.kt")
|
||||||
public void testKt416() throws Exception {
|
public void testKt416() throws Exception {
|
||||||
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt416.kt");
|
blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt416.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user