From ec632c37ab1dd0e26ad6493a07e455d62b4e287d Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Thu, 5 May 2016 14:13:26 +0300 Subject: [PATCH] Support increment and '+=' on local delegated properties --- .../kotlin/codegen/ExpressionCodegen.java | 7 +++++-- .../jetbrains/kotlin/codegen/StackValue.java | 11 +++++++++- .../box/delegatedProperty/local/iinc.kt | 17 +++++++++++++++ .../box/delegatedProperty/local/plusAssign.kt | 16 ++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 21 +++++++++++++++++++ 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/box/delegatedProperty/local/iinc.kt create mode 100644 compiler/testData/codegen/box/delegatedProperty/local/plusAssign.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 89368036d83..a8db83ebc6f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2813,11 +2813,14 @@ public class ExpressionCodegen extends KtVisitor impleme } } - public int indexOfLocal(KtReferenceExpression lhs) { + public int indexOfLocalNotDelegated(KtReferenceExpression lhs) { DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, lhs); if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) { return -1; } + if (declarationDescriptor instanceof LocalVariableDescriptor && ((LocalVariableDescriptor) declarationDescriptor).isDelegated()) { + return -1; + } return lookupLocalIndex(declarationDescriptor); } @@ -3346,7 +3349,7 @@ public class ExpressionCodegen extends KtVisitor impleme // Optimization for j = i++, when j and i are Int without any smart cast: we just work with primitive int if (operand instanceof KtReferenceExpression && asmResultType == Type.INT_TYPE && bindingContext.get(BindingContext.SMARTCAST, operand) == null) { - int index = indexOfLocal((KtReferenceExpression) operand); + int index = indexOfLocalNotDelegated((KtReferenceExpression) operand); if (index >= 0) { return StackValue.postIncrement(index, increment); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 93cae534666..88cb4b9f083 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -672,7 +672,16 @@ public abstract class StackValue { @NotNull CallableMethod getter, @Nullable CallableMethod setter ) { - super(type, false, false, new Receiver(OBJECT_TYPE, delegateValue, constant(null, OBJECT_TYPE), metadataValue), false); + super(type, false, false, new Receiver(OBJECT_TYPE, delegateValue, constant(null, OBJECT_TYPE), metadataValue) { + @Override + public void dup(@NotNull InstructionAdapter v, boolean withReceiver) { + //UGLY HACK + //TODO rethink Receiver/StackValue concept + //We need to make duplication of delegated var, owner (null) and property metadata: dup 3. + //As HACK Type.LONG_TYPE and Type.INT_TYPE passed to dup util to simulate dup 3. + AsmUtil.dup(v, Type.LONG_TYPE, Type.INT_TYPE); + } + }, false); this.delegateValue = delegateValue; this.metadataValue = metadataValue; this.getter = getter; diff --git a/compiler/testData/codegen/box/delegatedProperty/local/iinc.kt b/compiler/testData/codegen/box/delegatedProperty/local/iinc.kt new file mode 100644 index 00000000000..1e80caf7a26 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/local/iinc.kt @@ -0,0 +1,17 @@ +import kotlin.reflect.KProperty + +class Delegate { + var inner = 1 + operator fun getValue(t: Any?, p: KProperty<*>): Int = inner + operator fun setValue(t: Any?, p: KProperty<*>, i: Int) { + inner = i + } +} + +fun box(): String { + var prop: Int by Delegate() + var result = prop++ + if (result != 1) return "fail increment result: $prop" + if (prop != 2) return "fail increment: $prop" + return "OK" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/local/plusAssign.kt b/compiler/testData/codegen/box/delegatedProperty/local/plusAssign.kt new file mode 100644 index 00000000000..7b9997b6316 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/local/plusAssign.kt @@ -0,0 +1,16 @@ +import kotlin.reflect.KProperty + +class Delegate { + var inner = 1 + operator fun getValue(t: Any?, p: KProperty<*>): Int = inner + operator fun setValue(t: Any?, p: KProperty<*>, i: Int) { + inner = i + } +} + +fun box(): String { + var prop: Int by Delegate() + prop += 1 + if (prop != 2) return "fail : $prop" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index eda77f6bf5e..1e4e302cf25 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4974,6 +4974,27 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/varInInnerClass.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/codegen/box/delegatedProperty/local") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Local extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInLocal() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/delegatedProperty/local"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("iinc.kt") + public void testIinc() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/iinc.kt"); + doTest(fileName); + } + + @TestMetadata("plusAssign.kt") + public void testPlusAssign() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/local/plusAssign.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/codegen/box/delegation")