Support local property delegation to inline class values

Also, add extra test on property delegation.
This commit is contained in:
Dmitry Petrov
2018-10-01 17:30:48 +03:00
parent 6fa436911a
commit b55b0c1ff1
10 changed files with 324 additions and 9 deletions
@@ -1939,11 +1939,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
Type sharedVarType = typeMapper.getSharedVarType(descriptor);
Type varType = getVariableTypeNoSharing(variableDescriptor);
KotlinType delegateKotlinType =
isDelegatedLocalVariable(descriptor)
? JvmCodegenUtil.getPropertyDelegateType((VariableDescriptorWithAccessors) descriptor, bindingContext)
: null;
if (sharedVarType != null) {
return StackValue.shared(index, varType, variableDescriptor);
return StackValue.shared(index, varType, variableDescriptor, delegateKotlinType);
}
else {
return adjustVariableValue(StackValue.local(index, varType, variableDescriptor), variableDescriptor);
return adjustVariableValue(StackValue.local(index, varType, variableDescriptor, delegateKotlinType), variableDescriptor);
}
}
else {
@@ -4124,9 +4128,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
Type varType = getVariableTypeNoSharing(variableDescriptor);
KotlinType delegateKotlinType = JvmCodegenUtil.getPropertyDelegateType(variableDescriptor, bindingContext);
StackValue storeTo = sharedVarType == null ?
StackValue.local(index, varType, variableDescriptor) :
StackValue.shared(index, varType, variableDescriptor);
StackValue.local(index, varType, variableDescriptor, delegateKotlinType) :
StackValue.shared(index, varType, variableDescriptor, delegateKotlinType);
storeTo.putReceiver(v, false);
if (variableDescriptor.isLateInit()) {
@@ -4918,7 +4923,7 @@ The "returned" value of try expression with no finally is either the last expres
@NotNull VariableDescriptorWithAccessors variableDescriptor,
@NotNull KotlinTypeMapper typeMapper
) {
return StackValue.delegate(typeMapper.mapType(variableDescriptor.getType()), delegateValue, metadataValue, variableDescriptor, this);
return StackValue.localDelegate(typeMapper.mapType(variableDescriptor.getType()), delegateValue, metadataValue, variableDescriptor, this);
}
@NotNull
@@ -25,7 +25,10 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.ValueArgument;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
@@ -160,16 +163,26 @@ public abstract class StackValue {
@NotNull
public static StackValue local(int index, @NotNull Type type, @NotNull VariableDescriptor descriptor) {
return local(index, type, descriptor, null);
}
@NotNull
public static StackValue local(int index, @NotNull Type type, @NotNull VariableDescriptor descriptor, @Nullable KotlinType delegateKotlinType) {
if (descriptor.isLateInit()) {
assert delegateKotlinType == null :
"Delegated property can't be lateinit: " + descriptor + ", delegate type: " + delegateKotlinType;
return new LateinitLocal(index, type, descriptor.getType(), descriptor.getName());
}
else {
return new Local(index, type, descriptor.getType());
return new Local(
index, type,
delegateKotlinType != null ? delegateKotlinType : descriptor.getType()
);
}
}
@NotNull
public static Delegate delegate(
public static Delegate localDelegate(
@NotNull Type type,
@NotNull StackValue delegateValue,
@NotNull StackValue metadataValue,
@@ -186,7 +199,16 @@ public abstract class StackValue {
@NotNull
public static StackValue shared(int index, @NotNull Type type, @NotNull VariableDescriptor descriptor) {
return new Shared(index, type, descriptor.getType(), descriptor.isLateInit(), descriptor.getName());
return shared(index, type, descriptor, null);
}
@NotNull
public static StackValue shared(int index, @NotNull Type type, @NotNull VariableDescriptor descriptor, @Nullable KotlinType delegateKotlinType) {
return new Shared(
index, type,
delegateKotlinType != null ? delegateKotlinType : descriptor.getType(),
descriptor.isLateInit(), descriptor.getName()
);
}
@NotNull
@@ -0,0 +1,91 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
var setterInvoked = 0
var backing = 42
inline class DelegateStr(val ignored: String) {
operator fun getValue(thisRef: Any?, prop: Any?) =
backing
operator fun setValue(thisRef: Any?, prop: Any?, newValue: Int) {
setterInvoked++
backing = newValue
}
}
inline class DelegateInt(val ignored: Int) {
operator fun getValue(thisRef: Any?, prop: Any?) =
backing
operator fun setValue(thisRef: Any?, prop: Any?, newValue: Int) {
setterInvoked++
backing = newValue
}
}
inline class DelegateLong(val ignored: Long) {
operator fun getValue(thisRef: Any?, prop: Any?) =
backing
operator fun setValue(thisRef: Any?, prop: Any?, newValue: Int) {
setterInvoked++
backing = newValue
}
}
fun box(): String {
setterInvoked = 0
testDelegateStr()
if (setterInvoked != 1) throw AssertionError()
setterInvoked = 0
testDelegateInt()
if (setterInvoked != 1) throw AssertionError()
setterInvoked = 0
testDelegateLong()
if (setterInvoked != 1) throw AssertionError()
return "OK"
}
private fun testDelegateStr() {
var localD by DelegateStr("don't care")
return {
if (localD != 42) AssertionError()
localD = 1234
if (localD != 1234) throw AssertionError()
if (backing != 1234) throw AssertionError()
}()
}
private fun testDelegateInt() {
var localD by DelegateInt(999)
return {
if (localD != 42) AssertionError()
localD = 1234
if (localD != 1234) throw AssertionError()
if (backing != 1234) throw AssertionError()
}()
}
private fun testDelegateLong() {
var localD by DelegateLong(999L)
return {
if (localD != 42) AssertionError()
localD = 1234
if (localD != 1234) throw AssertionError()
if (backing != 1234) throw AssertionError()
}()
}
@@ -0,0 +1,85 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
var setterInvoked = 0
var backing = 42
inline class DelegateStr(val ignored: String) {
operator fun getValue(thisRef: Any?, prop: Any?) =
backing
operator fun setValue(thisRef: Any?, prop: Any?, newValue: Int) {
setterInvoked++
backing = newValue
}
}
inline class DelegateInt(val ignored: Int) {
operator fun getValue(thisRef: Any?, prop: Any?) =
backing
operator fun setValue(thisRef: Any?, prop: Any?, newValue: Int) {
setterInvoked++
backing = newValue
}
}
inline class DelegateLong(val ignored: Long) {
operator fun getValue(thisRef: Any?, prop: Any?) =
backing
operator fun setValue(thisRef: Any?, prop: Any?, newValue: Int) {
setterInvoked++
backing = newValue
}
}
fun box(): String {
setterInvoked = 0
testDelegateStr()
if (setterInvoked != 1) throw AssertionError()
setterInvoked = 0
testDelegateInt()
if (setterInvoked != 1) throw AssertionError()
setterInvoked = 0
testDelegateLong()
if (setterInvoked != 1) throw AssertionError()
return "OK"
}
private fun testDelegateStr() {
var localD by DelegateStr("don't care")
if (localD != 42) AssertionError()
localD = 1234
if (localD != 1234) throw AssertionError()
if (backing != 1234) throw AssertionError()
}
private fun testDelegateInt() {
var localD by DelegateInt(999)
if (localD != 42) AssertionError()
localD = 1234
if (localD != 1234) throw AssertionError()
if (backing != 1234) throw AssertionError()
}
private fun testDelegateLong() {
var localD by DelegateLong(999L)
if (localD != 42) AssertionError()
localD = 1234
if (localD != 1234) throw AssertionError()
if (backing != 1234) throw AssertionError()
}
@@ -0,0 +1,37 @@
// !LANGUAGE: +InlineClasses
// IGNORE_BACKEND: JVM_IR
class Foo {
companion object {
var a: Int = 42
private var d by Delegate(0)
fun d() = d
fun d(newValue: Int) { d = newValue }
}
}
var setterInvoked = 0
inline class Delegate(val ignored: Int) {
operator fun getValue(thisRef: Any?, prop: Any?) = Foo.a
operator fun setValue(thisRef: Any?, prop: Any?, newValue: Int) {
setterInvoked++
Foo.a = newValue
}
}
fun box(): String {
if (Foo.d() != 42) throw AssertionError()
Foo.d(1234)
if (Foo.d() != 1234) throw AssertionError()
if (Foo.a != 1234) throw AssertionError()
if (setterInvoked != 1) throw AssertionError()
return "OK"
}
@@ -12323,6 +12323,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/propertyDelegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("captureLocalVarDelegatedToInlineClass.kt")
public void testCaptureLocalVarDelegatedToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/captureLocalVarDelegatedToInlineClass.kt");
}
@TestMetadata("delegateClassVarToInlineClass.kt")
public void testDelegateClassVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateClassVarToInlineClass.kt");
@@ -12343,11 +12348,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateJvmStaticCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateLocalVarToInlineClass.kt")
public void testDelegateLocalVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateLocalVarToInlineClass.kt");
}
@TestMetadata("delegateObjectVarToInlineClass.kt")
public void testDelegateObjectVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateObjectVarToInlineClass.kt");
}
@TestMetadata("delegatePrivateCompanionVarToInlineClass.kt")
public void testDelegatePrivateCompanionVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegatePrivateCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateTopLevelVarToInlineClass.kt")
public void testDelegateTopLevelVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateTopLevelVarToInlineClass.kt");
@@ -12323,6 +12323,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/propertyDelegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("captureLocalVarDelegatedToInlineClass.kt")
public void testCaptureLocalVarDelegatedToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/captureLocalVarDelegatedToInlineClass.kt");
}
@TestMetadata("delegateClassVarToInlineClass.kt")
public void testDelegateClassVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateClassVarToInlineClass.kt");
@@ -12343,11 +12348,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateJvmStaticCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateLocalVarToInlineClass.kt")
public void testDelegateLocalVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateLocalVarToInlineClass.kt");
}
@TestMetadata("delegateObjectVarToInlineClass.kt")
public void testDelegateObjectVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateObjectVarToInlineClass.kt");
}
@TestMetadata("delegatePrivateCompanionVarToInlineClass.kt")
public void testDelegatePrivateCompanionVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegatePrivateCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateTopLevelVarToInlineClass.kt")
public void testDelegateTopLevelVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateTopLevelVarToInlineClass.kt");
@@ -12328,6 +12328,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/propertyDelegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@TestMetadata("captureLocalVarDelegatedToInlineClass.kt")
public void testCaptureLocalVarDelegatedToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/captureLocalVarDelegatedToInlineClass.kt");
}
@TestMetadata("delegateClassVarToInlineClass.kt")
public void testDelegateClassVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateClassVarToInlineClass.kt");
@@ -12348,11 +12353,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateJvmStaticCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateLocalVarToInlineClass.kt")
public void testDelegateLocalVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateLocalVarToInlineClass.kt");
}
@TestMetadata("delegateObjectVarToInlineClass.kt")
public void testDelegateObjectVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateObjectVarToInlineClass.kt");
}
@TestMetadata("delegatePrivateCompanionVarToInlineClass.kt")
public void testDelegatePrivateCompanionVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegatePrivateCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateTopLevelVarToInlineClass.kt")
public void testDelegateTopLevelVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateTopLevelVarToInlineClass.kt");
@@ -10863,6 +10863,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/propertyDelegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
}
@TestMetadata("captureLocalVarDelegatedToInlineClass.kt")
public void testCaptureLocalVarDelegatedToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/captureLocalVarDelegatedToInlineClass.kt");
}
@TestMetadata("delegateClassVarToInlineClass.kt")
public void testDelegateClassVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateClassVarToInlineClass.kt");
@@ -10883,11 +10888,21 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateJvmStaticCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateLocalVarToInlineClass.kt")
public void testDelegateLocalVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateLocalVarToInlineClass.kt");
}
@TestMetadata("delegateObjectVarToInlineClass.kt")
public void testDelegateObjectVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateObjectVarToInlineClass.kt");
}
@TestMetadata("delegatePrivateCompanionVarToInlineClass.kt")
public void testDelegatePrivateCompanionVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegatePrivateCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateTopLevelVarToInlineClass.kt")
public void testDelegateTopLevelVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateTopLevelVarToInlineClass.kt");
@@ -11908,6 +11908,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/propertyDelegation"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("captureLocalVarDelegatedToInlineClass.kt")
public void testCaptureLocalVarDelegatedToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/captureLocalVarDelegatedToInlineClass.kt");
}
@TestMetadata("delegateClassVarToInlineClass.kt")
public void testDelegateClassVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateClassVarToInlineClass.kt");
@@ -11928,11 +11933,21 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateJvmStaticCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateLocalVarToInlineClass.kt")
public void testDelegateLocalVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateLocalVarToInlineClass.kt");
}
@TestMetadata("delegateObjectVarToInlineClass.kt")
public void testDelegateObjectVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateObjectVarToInlineClass.kt");
}
@TestMetadata("delegatePrivateCompanionVarToInlineClass.kt")
public void testDelegatePrivateCompanionVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegatePrivateCompanionVarToInlineClass.kt");
}
@TestMetadata("delegateTopLevelVarToInlineClass.kt")
public void testDelegateTopLevelVarToInlineClass() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/propertyDelegation/delegateTopLevelVarToInlineClass.kt");