Postfix expression code generation fixed as per KT-7561.

A set of tests for KT-7561 on codegen side, including exotic inc() functions().
 #KT-7561 Fixed.
This commit is contained in:
Mikhail Glukhikh
2015-04-23 18:09:27 +03:00
parent 5723c2a077
commit 4570872bfd
17 changed files with 258 additions and 2 deletions
@@ -3239,7 +3239,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
final boolean isPrimitiveNumberClassDescriptor = isPrimitiveNumberClassDescriptor(cls);
if (isPrimitiveNumberClassDescriptor && AsmUtil.isPrimitive(asmBaseType)) {
JetExpression operand = expression.getBaseExpression();
if (operand instanceof JetReferenceExpression && asmResultType == Type.INT_TYPE) {
// Optimization for j = i++, when j and i are Int without any smart cast: we just work with primitive int
if (operand instanceof JetReferenceExpression && asmResultType == Type.INT_TYPE &&
bindingContext.get(BindingContext.SMARTCAST, operand) == null) {
int index = indexOfLocal((JetReferenceExpression) operand);
if (index >= 0) {
return StackValue.postIncrement(index, increment);
@@ -3247,7 +3249,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
return StackValue.operation(asmResultType, new Function1<InstructionAdapter, Unit>() {
return StackValue.operation(asmBaseType, new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
StackValue value = gen(expression.getBaseExpression());
@@ -0,0 +1,8 @@
public fun box() : String {
var i : Int?
i = 10
// assignPlus on a smart cast should work
i += 1
return if (11 == i) "OK" else "fail i = $i"
}
@@ -0,0 +1,10 @@
public fun box() : String {
var i : Int?
i = 10
// We have "double" smart cast here:
// first on i and second on i++
// Back-end should NOT think that both i and j are Int
val j: Int = i++
return if (j == 10 && 11 == i) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,12 @@
trait Base
class Derived: Base
class Another: Base
fun Base.inc(): Derived { return Derived() }
public fun box() : String {
var i : Base
i = Another()
val j = i++
return if (j is Another && i is Derived) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,11 @@
open class Base
class Derived: Base()
fun Derived.inc(): Derived { return Derived() }
public fun box() : String {
var i : Base
i = Derived()
val j = i++
return if (j is Derived && i is Derived) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,8 @@
public fun box() : String {
var i : Short?
i = 10
// Postfix increment on a smart casted short should work
val j = i++
return if (j!!.toInt() == 10 && i!!.toInt() == 11) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,9 @@
public fun box() : String {
var i : Int?
i = 10
// Postfix increment on a smart cast should work
// Specific: i.inc() type is Int but i and j types are both Int?
val j = i++
return if (j == 10 && 11 == i) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,12 @@
class MyClass
// In principle it is not correct, MyClass? is not a subtype of MyClass
fun MyClass.inc(): MyClass? = null
public fun box() : String {
var i : MyClass?
i = MyClass()
val j = i++
return if (j is MyClass && null == i) "OK" else "fail i = $i j = $j"
}
@@ -0,0 +1,11 @@
class MyClass
fun MyClass?.inc(): MyClass? = null
public fun box() : String {
var i : MyClass?
i = MyClass()
val j = i++
return if (j is MyClass && null == i) "OK" else "fail i = $i j = $j"
}
@@ -0,0 +1,10 @@
fun Int?.inc(): Int? = this
fun init(): Int? { return 10 }
public fun box() : String {
var i : Int? = init()
val j = i++
return if (j == 10 && 10 == i) "OK" else "fail i = $i j = $j"
}
@@ -0,0 +1,12 @@
trait Base
class Derived: Base
class Another: Base
fun Base.inc(): Derived { return Derived() }
public fun box() : String {
var i : Base
i = Another()
val j = ++i
return if (j is Derived && i is Derived) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,11 @@
open class Base
class Derived: Base()
fun Derived.inc(): Derived { return Derived() }
public fun box() : String {
var i : Base
i = Derived()
val j = ++i
return if (j is Derived && i is Derived) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,8 @@
public fun box() : String {
var i : Int?
i = 10
// Prefix increment on a smart cast should work
val j = ++i
return if (j == 11 && 11 == i) "OK" else "fail j = $j i = $i"
}
@@ -0,0 +1,12 @@
class MyClass
// In principle it is not correct, MyClass? is not a subtype of MyClass
fun MyClass.inc(): MyClass? = null
public fun box() : String {
var i : MyClass?
i = MyClass()
val j = ++i
return if (j == null && null == i) "OK" else "fail i = $i j = $j"
}
@@ -0,0 +1,11 @@
class MyClass
fun MyClass?.inc(): MyClass? = null
public fun box() : String {
var i : MyClass?
i = MyClass()
val j = ++i
return if (j == null && null == i) "OK" else "fail i = $i j = $j"
}
@@ -0,0 +1,10 @@
fun Int?.inc(): Int? = this
fun init(): Int? { return 10 }
public fun box() : String {
var i : Int? = init()
val j = ++i
return if (j == 10 && 10 == i) "OK" else "fail i = $i j = $j"
}
@@ -4049,6 +4049,105 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@TestMetadata("compiler/testData/codegen/box/increment")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Increment extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInIncrement() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/increment"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("assignPlusOnSmartCast.kt")
public void testAssignPlusOnSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/assignPlusOnSmartCast.kt");
doTest(fileName);
}
@TestMetadata("postfixIncrementDoubleSmartCast.kt")
public void testPostfixIncrementDoubleSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixIncrementDoubleSmartCast.kt");
doTest(fileName);
}
@TestMetadata("postfixIncrementOnClass.kt")
public void testPostfixIncrementOnClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixIncrementOnClass.kt");
doTest(fileName);
}
@TestMetadata("postfixIncrementOnClassSmartCast.kt")
public void testPostfixIncrementOnClassSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixIncrementOnClassSmartCast.kt");
doTest(fileName);
}
@TestMetadata("postfixIncrementOnShortSmartCast.kt")
public void testPostfixIncrementOnShortSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixIncrementOnShortSmartCast.kt");
doTest(fileName);
}
@TestMetadata("postfixIncrementOnSmartCast.kt")
public void testPostfixIncrementOnSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixIncrementOnSmartCast.kt");
doTest(fileName);
}
@TestMetadata("postfixNotnullClassIncrement.kt")
public void testPostfixNotnullClassIncrement() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixNotnullClassIncrement.kt");
doTest(fileName);
}
@TestMetadata("postfixNullableClassIncrement.kt")
public void testPostfixNullableClassIncrement() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixNullableClassIncrement.kt");
doTest(fileName);
}
@TestMetadata("postfixNullableIncrement.kt")
public void testPostfixNullableIncrement() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/postfixNullableIncrement.kt");
doTest(fileName);
}
@TestMetadata("prefixIncrementOnClass.kt")
public void testPrefixIncrementOnClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/prefixIncrementOnClass.kt");
doTest(fileName);
}
@TestMetadata("prefixIncrementOnClassSmartCast.kt")
public void testPrefixIncrementOnClassSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/prefixIncrementOnClassSmartCast.kt");
doTest(fileName);
}
@TestMetadata("prefixIncrementOnSmartCast.kt")
public void testPrefixIncrementOnSmartCast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/prefixIncrementOnSmartCast.kt");
doTest(fileName);
}
@TestMetadata("prefixNotnullClassIncrement.kt")
public void testPrefixNotnullClassIncrement() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/prefixNotnullClassIncrement.kt");
doTest(fileName);
}
@TestMetadata("prefixNullableClassIncrement.kt")
public void testPrefixNullableClassIncrement() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/prefixNullableClassIncrement.kt");
doTest(fileName);
}
@TestMetadata("prefixNullableIncrement.kt")
public void testPrefixNullableIncrement() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/increment/prefixNullableIncrement.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/innerNested")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)