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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user