KT-13931 generate IntRange#contains with respect to side-effects on argument loading, test added
This commit is contained in:
@@ -3470,38 +3470,35 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Translates x in a..b (for int and char ranges only)
|
* Translates x in a..b (for int and char ranges only) to a <= x && x <= b
|
||||||
* to a <= x && x >= b same way as javac 1.8.0_91 does.
|
|
||||||
*/
|
*/
|
||||||
private void genInIntRange(StackValue leftValue, KtBinaryExpression rangeExpression) {
|
private void genInIntRange(StackValue leftValue, KtBinaryExpression rangeExpression) {
|
||||||
|
int localVarIndex = myFrameMap.enterTemp(Type.INT_TYPE);
|
||||||
|
|
||||||
// Load left bound
|
// Load left bound
|
||||||
gen(rangeExpression.getLeft(), Type.INT_TYPE);
|
gen(rangeExpression.getLeft(), Type.INT_TYPE);
|
||||||
// Load argument
|
// Load x into local variable to avoid StackValue#put side-effects
|
||||||
leftValue.put(Type.INT_TYPE, v);
|
leftValue.put(Type.INT_TYPE, v);
|
||||||
|
v.store(localVarIndex, Type.INT_TYPE);
|
||||||
|
v.load(localVarIndex, Type.INT_TYPE);
|
||||||
|
|
||||||
// If (left > arg) goto L1 (return)
|
// If (x < left) goto L1
|
||||||
Label l1 = new Label();
|
Label l1 = new Label();
|
||||||
v.ificmpgt(l1);
|
v.ificmpgt(l1);
|
||||||
|
|
||||||
// Load argument again
|
// If (x > right) goto L1
|
||||||
leftValue.put(Type.INT_TYPE, v);
|
v.load(localVarIndex, Type.INT_TYPE);
|
||||||
// Load right bound
|
|
||||||
gen(rangeExpression.getRight(), Type.INT_TYPE);
|
gen(rangeExpression.getRight(), Type.INT_TYPE);
|
||||||
// If (x > right) goto L1 (return)
|
|
||||||
v.ificmpgt(l1);
|
v.ificmpgt(l1);
|
||||||
|
|
||||||
Label l2 = new Label();
|
Label l2 = new Label();
|
||||||
// Push 'true'
|
|
||||||
v.iconst(1);
|
v.iconst(1);
|
||||||
// Goto return
|
|
||||||
v.goTo(l2);
|
v.goTo(l2);
|
||||||
|
|
||||||
// L1: push 'false'
|
|
||||||
v.mark(l1);
|
v.mark(l1);
|
||||||
v.iconst(0);
|
v.iconst(0);
|
||||||
|
|
||||||
// L2: implicit ireturn
|
|
||||||
v.mark(l2);
|
v.mark(l2);
|
||||||
|
myFrameMap.leaveTemp(Type.INT_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StackValue generateBooleanAnd(KtBinaryExpression expression) {
|
private StackValue generateBooleanAnd(KtBinaryExpression expression) {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
for (x in 1..10) {
|
||||||
|
assert(x in 1..10)
|
||||||
|
assert(x + 10 !in 1..10)
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = 0
|
||||||
|
assert(0 !in 1..2)
|
||||||
|
|
||||||
|
assert(++x in 1..1)
|
||||||
|
assert(++x !in 1..1)
|
||||||
|
|
||||||
|
assert(sideEffect(x) in 2..3)
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var invocationCounter = 0
|
||||||
|
fun sideEffect(x: Int): Int {
|
||||||
|
++invocationCounter
|
||||||
|
assert(invocationCounter == 1)
|
||||||
|
return x
|
||||||
|
}
|
||||||
@@ -11128,6 +11128,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inIntRange.kt")
|
||||||
|
public void testInIntRange() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/inIntRange.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("multiAssignmentIterationOverIntRange.kt")
|
@TestMetadata("multiAssignmentIterationOverIntRange.kt")
|
||||||
public void testMultiAssignmentIterationOverIntRange() throws Exception {
|
public void testMultiAssignmentIterationOverIntRange() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/multiAssignmentIterationOverIntRange.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/multiAssignmentIterationOverIntRange.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user