Restore anonymous classes for local delegate metadatas in inline functions
The problem is that now that the local delegated property metadata is in the $$delegatedProperties array of the containing class, the access to it from code calling an inline function with a local delegated property is illegal. Currently it seems to be a lot of work to support this rather rare case properly (see the comment in ExpressionCodegen.getVariableMetadataValue) so we postpone it and return the old behavior of using the anonymous KProperty subclass for metadata
This commit is contained in:
@@ -1309,6 +1309,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
Type type = getVariableType(variableDescriptor);
|
||||
int index = myFrameMap.enter(variableDescriptor, type);
|
||||
|
||||
if (isDelegatedLocalVariable(variableDescriptor)) {
|
||||
myFrameMap.enter(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext), AsmTypes.K_PROPERTY0_TYPE);
|
||||
}
|
||||
|
||||
if (isSharedVarType(type)) {
|
||||
markLineNumber(statement, false);
|
||||
v.anew(type);
|
||||
@@ -1356,6 +1360,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
v.mark(scopeStart);
|
||||
|
||||
leaveTasks.add(answer -> {
|
||||
if (isDelegatedLocalVariable(variableDescriptor)) {
|
||||
myFrameMap.leave(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext));
|
||||
}
|
||||
|
||||
int index = myFrameMap.leave(variableDescriptor);
|
||||
|
||||
v.visitLocalVariable(variableDescriptor.getName().asString(), type.getDescriptor(), null, scopeStart, blockEnd, index);
|
||||
@@ -1769,9 +1777,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
StackValue value = context.lookupInContext(descriptor, StackValue.LOCAL_0, state, false);
|
||||
if (value == null) return null;
|
||||
if (isDelegatedLocalVariable(descriptor) && value != null) {
|
||||
VariableDescriptor metadata = getDelegatedLocalVariableMetadata((VariableDescriptor) descriptor, bindingContext);
|
||||
StackValue metadataValue = context.lookupInContext(metadata, StackValue.LOCAL_0, state, false);
|
||||
assert metadataValue != null : "Metadata stack value should be non-null for local delegated property: " + descriptor;
|
||||
return delegatedVariableValue(value, metadataValue, (VariableDescriptorWithAccessors) descriptor, typeMapper);
|
||||
}
|
||||
|
||||
return adjustVariableValue(value, descriptor);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -3466,12 +3479,19 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue getVariableMetadataValue(@NotNull VariableDescriptorWithAccessors variableDescriptor) {
|
||||
StackValue value = findLocalOrCapturedValue(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext));
|
||||
assert value != null : "Can't find stack value for local delegated variable metadata: " + variableDescriptor;
|
||||
return value;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue adjustVariableValue(@NotNull StackValue varValue, DeclarationDescriptor descriptor) {
|
||||
if (!isDelegatedLocalVariable(descriptor)) return varValue;
|
||||
|
||||
VariableDescriptorWithAccessors variableDescriptor = (VariableDescriptorWithAccessors) descriptor;
|
||||
StackValue metadataValue = PropertyCodegen.getDelegatedPropertyMetadata(variableDescriptor, bindingContext);
|
||||
StackValue metadataValue = getVariableMetadataValue(variableDescriptor);
|
||||
return delegatedVariableValue(varValue, metadataValue, variableDescriptor, typeMapper);
|
||||
}
|
||||
|
||||
@@ -3503,16 +3523,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
Type resultType = initializer.type;
|
||||
|
||||
if (isDelegatedLocalVariable(variableDescriptor)) {
|
||||
StackValue metadataValue = PropertyCodegen.getDelegatedPropertyMetadata(variableDescriptor, bindingContext);
|
||||
StackValue metadataValue = getVariableMetadataValue(variableDescriptor);
|
||||
initializePropertyMetadata((KtProperty) variableDeclaration, variableDescriptor, metadataValue);
|
||||
|
||||
ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall = bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, variableDescriptor);
|
||||
if (provideDelegateResolvedCall != null) {
|
||||
resultType = generateProvideDelegateCallForLocalVariable(initializer, metadataValue, provideDelegateResolvedCall);
|
||||
ResolvedCall<FunctionDescriptor> provideDelegateCall = bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, variableDescriptor);
|
||||
if (provideDelegateCall != null) {
|
||||
resultType = generateProvideDelegateCallForLocalVariable(initializer, metadataValue, provideDelegateCall);
|
||||
}
|
||||
}
|
||||
|
||||
storeTo.storeSelector(resultType, v);
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -3559,10 +3579,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
@NotNull LocalVariableDescriptor variableDescriptor,
|
||||
@NotNull StackValue metadataVar
|
||||
) {
|
||||
// TODO: do not generate anonymous classes for local delegated properties in inline functions
|
||||
// We can use the $$delegatedProperties array as in non-inline functions and upon inlining, detect elements at what indices
|
||||
// of that array are used in the inline function body, load the corresponding initializing bytecode from <clinit> of the
|
||||
// container class (where the PropertyReferenceNImpl instance is created), copy and adapt it at the call site
|
||||
//noinspection ConstantConditions
|
||||
StackValue value = generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null, null);
|
||||
value.put(K_PROPERTY0_TYPE, v);
|
||||
metadataVar.storeSelector(K_PROPERTY0_TYPE, v);
|
||||
StackValue value = context.getFunctionDescriptor().isInline()
|
||||
? generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null, null)
|
||||
: PropertyCodegen.getDelegatedPropertyMetadata(variableDescriptor, bindingContext);
|
||||
value.put(K_PROPERTY_TYPE, v);
|
||||
metadataVar.storeSelector(K_PROPERTY_TYPE, v);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -116,10 +116,11 @@ class PropertyReferenceCodegen(
|
||||
generateCallableReferenceSignature(this, target, state)
|
||||
}
|
||||
|
||||
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state)
|
||||
}
|
||||
|
||||
if (!isLocalDelegatedProperty) {
|
||||
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state)
|
||||
}
|
||||
generateAccessors()
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -34,6 +34,8 @@ import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
||||
import org.jetbrains.kotlin.coroutines.CoroutineUtilKt;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
||||
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor;
|
||||
@@ -372,12 +374,32 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
return CodegenBinding.recordClosure(bindingTrace, classDescriptor, peekFromStack(classStack), Type.getObjectType(name));
|
||||
}
|
||||
|
||||
private void recordLocalVariablePropertyMetadata(LocalVariableDescriptor variableDescriptor) {
|
||||
KotlinType delegateType = JvmCodegenUtil.getPropertyDelegateType(variableDescriptor, bindingContext);
|
||||
if (delegateType == null) return;
|
||||
|
||||
LocalVariableDescriptor metadataVariableDescriptor = new LocalVariableDescriptor(
|
||||
variableDescriptor.getContainingDeclaration(),
|
||||
Annotations.Companion.getEMPTY(),
|
||||
Name.identifier(variableDescriptor.getName().asString() + "$metadata"),
|
||||
ReflectionTypes.Companion.createKPropertyStarType(DescriptorUtilsKt.getModule(variableDescriptor)),
|
||||
false,
|
||||
false,
|
||||
SourceElement.NO_SOURCE
|
||||
);
|
||||
bindingTrace.record(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor, metadataVariableDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitProperty(@NotNull KtProperty property) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, property);
|
||||
// working around a problem with shallow analysis
|
||||
if (descriptor == null) return;
|
||||
|
||||
if (descriptor instanceof LocalVariableDescriptor) {
|
||||
recordLocalVariablePropertyMetadata((LocalVariableDescriptor) descriptor);
|
||||
}
|
||||
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(descriptor);
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
|
||||
@@ -69,6 +69,8 @@ public class CodegenBinding {
|
||||
Slices.createSimpleSlice();
|
||||
public static final WritableSlice<VariableDescriptorWithAccessors, Type> DELEGATED_PROPERTY_METADATA_OWNER =
|
||||
Slices.createSimpleSlice();
|
||||
public static final WritableSlice<VariableDescriptor, VariableDescriptor> LOCAL_VARIABLE_PROPERTY_METADATA =
|
||||
Slices.createSimpleSlice();
|
||||
|
||||
static {
|
||||
BasicWritableSlice.initSliceDebugNames(CodegenBinding.class);
|
||||
@@ -223,4 +225,14 @@ public class CodegenBinding {
|
||||
assert type != null : "Type is not yet recorded for " + klass;
|
||||
return type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static VariableDescriptor getDelegatedLocalVariableMetadata(
|
||||
@NotNull VariableDescriptor variableDescriptor,
|
||||
@NotNull BindingContext bindingContext
|
||||
) {
|
||||
VariableDescriptor metadataVariableDescriptor = bindingContext.get(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor);
|
||||
assert metadataVariableDescriptor != null : "Metadata for local delegated property should be not null: " + variableDescriptor;
|
||||
return metadataVariableDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
object Delegate {
|
||||
lateinit var property: KProperty<*>
|
||||
|
||||
operator fun getValue(instance: Any?, kProperty: KProperty<*>) {
|
||||
property = kProperty
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
inline fun foo() {
|
||||
val x by Delegate
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
Foo().foo()
|
||||
assertEquals("val x: kotlin.Unit", Delegate.property.toString())
|
||||
return "OK"
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// FILE: 1.kt
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class Delegate {
|
||||
operator fun getValue(t: Any?, p: KProperty<*>): String = "O"
|
||||
}
|
||||
|
||||
inline fun test(crossinline s: () -> String): String {
|
||||
val delegate = Delegate()
|
||||
val o = object {
|
||||
fun run(): String {
|
||||
val prop: String by delegate
|
||||
return prop + s()
|
||||
}
|
||||
}
|
||||
return o.run()
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
return test { "K" }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// FILE: 1.kt
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class Delegate {
|
||||
operator fun getValue(t: Any?, p: KProperty<*>): String = "OK"
|
||||
}
|
||||
|
||||
inline fun test(): String {
|
||||
val b by Delegate()
|
||||
|
||||
return run {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
import test.*
|
||||
|
||||
fun box(): String {
|
||||
return test()
|
||||
}
|
||||
+6
@@ -16050,6 +16050,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFun.kt")
|
||||
public void testInlineFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/inlineFun.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localDelegatedProperty.kt")
|
||||
public void testLocalDelegatedProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt");
|
||||
|
||||
+12
@@ -1354,6 +1354,18 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInAnonymousObject.kt")
|
||||
public void testLocalInAnonymousObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInLambda.kt")
|
||||
public void testLocalInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/enclosingInfo")
|
||||
|
||||
+12
@@ -1354,6 +1354,18 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInAnonymousObject.kt")
|
||||
public void testLocalInAnonymousObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInLambda.kt")
|
||||
public void testLocalInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/enclosingInfo")
|
||||
|
||||
@@ -16050,6 +16050,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFun.kt")
|
||||
public void testInlineFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/inlineFun.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localDelegatedProperty.kt")
|
||||
public void testLocalDelegatedProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt");
|
||||
|
||||
@@ -1354,6 +1354,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInAnonymousObject.kt")
|
||||
public void testLocalInAnonymousObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInLambda.kt")
|
||||
public void testLocalInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/enclosingInfo")
|
||||
|
||||
+12
@@ -1354,6 +1354,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInAnonymousObject.kt")
|
||||
public void testLocalInAnonymousObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localInLambda.kt")
|
||||
public void testLocalInLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/delegatedProperty/localInLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxInline/enclosingInfo")
|
||||
|
||||
@@ -16050,6 +16050,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFun.kt")
|
||||
public void testInlineFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/inlineFun.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localDelegatedProperty.kt")
|
||||
public void testLocalDelegatedProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt");
|
||||
|
||||
Reference in New Issue
Block a user