Support property delegation to inline class values (KT-27070)
This commit is contained in:
@@ -2153,7 +2153,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return StackValue.property(
|
||||
propertyDescriptor, backingFieldOwner,
|
||||
typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
|
||||
isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall, skipLateinitAssertion
|
||||
isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall, skipLateinitAssertion,
|
||||
isDelegatedProperty && forceField ? delegateType : null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2169,7 +2170,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
CallableMethod callableSetter =
|
||||
setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null;
|
||||
return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, receiver, this,
|
||||
null, false);
|
||||
null, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -510,19 +510,29 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
propertyDescriptor, true, false, null, true, StackValue.LOCAL_0, null, false
|
||||
);
|
||||
|
||||
ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall = bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor);
|
||||
if (provideDelegateResolvedCall == null) {
|
||||
if (property.getDelegateExpression() == null) {
|
||||
propValue.store(codegen.gen(initializer), codegen.v);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
StackValue.Property delegate = propValue.getDelegateOrNull();
|
||||
assert delegate != null : "No delegate for delegated property: " + propertyDescriptor;
|
||||
|
||||
StackValue provideDelegateReceiver = codegen.gen(initializer);
|
||||
ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall =
|
||||
bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor);
|
||||
|
||||
StackValue delegateValue = PropertyCodegen.invokeDelegatedPropertyConventionMethod(
|
||||
codegen, provideDelegateResolvedCall, provideDelegateReceiver, propertyDescriptor
|
||||
);
|
||||
if (provideDelegateResolvedCall == null) {
|
||||
delegate.store(codegen.gen(initializer), codegen.v);
|
||||
}
|
||||
else {
|
||||
StackValue provideDelegateReceiver = codegen.gen(initializer);
|
||||
|
||||
propValue.store(delegateValue, codegen.v);
|
||||
StackValue delegateValue = PropertyCodegen.invokeDelegatedPropertyConventionMethod(
|
||||
codegen, provideDelegateResolvedCall, provideDelegateReceiver, propertyDescriptor
|
||||
);
|
||||
|
||||
delegate.store(delegateValue, codegen.v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public accessible for serialization plugin to check whether call to initializeProperty(..) is legal.
|
||||
|
||||
@@ -605,8 +605,10 @@ public class PropertyCodegen {
|
||||
assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
|
||||
|
||||
PropertyDescriptor propertyDescriptor = propertyAccessorDescriptor.getCorrespondingProperty();
|
||||
StackValue.Property receiver = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
||||
StackValue lastValue = invokeDelegatedPropertyConventionMethod(codegen, resolvedCall, receiver, propertyDescriptor);
|
||||
StackValue.Property property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
||||
StackValue.Property delegate = property.getDelegateOrNull();
|
||||
assert delegate != null : "No delegate for delegated property: " + propertyDescriptor;
|
||||
StackValue lastValue = invokeDelegatedPropertyConventionMethod(codegen, resolvedCall, delegate, propertyDescriptor);
|
||||
Type asmType = signature.getReturnType();
|
||||
lastValue.put(asmType, v);
|
||||
v.areturn(asmType);
|
||||
|
||||
@@ -363,10 +363,11 @@ public abstract class StackValue {
|
||||
@NotNull StackValue receiver,
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@Nullable ResolvedCall resolvedCall,
|
||||
boolean skipLateinitAssertion
|
||||
boolean skipLateinitAssertion,
|
||||
@Nullable KotlinType delegateKotlinType
|
||||
) {
|
||||
return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, receiver, codegen,
|
||||
resolvedCall, skipLateinitAssertion);
|
||||
resolvedCall, skipLateinitAssertion, delegateKotlinType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -1460,7 +1461,6 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Field extends StackValueWithSimpleReceiver {
|
||||
public final Type owner;
|
||||
public final String name;
|
||||
@@ -1508,12 +1508,13 @@ public abstract class StackValue {
|
||||
private final ExpressionCodegen codegen;
|
||||
private final ResolvedCall resolvedCall;
|
||||
private final boolean skipLateinitAssertion;
|
||||
private final KotlinType delegateKotlinType;
|
||||
|
||||
public Property(
|
||||
@NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner, @Nullable CallableMethod getter,
|
||||
@Nullable CallableMethod setter, boolean isStaticBackingField, @Nullable String fieldName, @NotNull Type type,
|
||||
@NotNull StackValue receiver, @NotNull ExpressionCodegen codegen, @Nullable ResolvedCall resolvedCall,
|
||||
boolean skipLateinitAssertion
|
||||
boolean skipLateinitAssertion, @Nullable KotlinType delegateKotlinType
|
||||
) {
|
||||
super(type, descriptor.getType(), isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
|
||||
this.backingFieldOwner = backingFieldOwner;
|
||||
@@ -1524,6 +1525,44 @@ public abstract class StackValue {
|
||||
this.codegen = codegen;
|
||||
this.resolvedCall = resolvedCall;
|
||||
this.skipLateinitAssertion = skipLateinitAssertion;
|
||||
this.delegateKotlinType = delegateKotlinType;
|
||||
}
|
||||
|
||||
private static class DelegatePropertyConstructorMarker {
|
||||
private DelegatePropertyConstructorMarker() {}
|
||||
public static final DelegatePropertyConstructorMarker MARKER = new DelegatePropertyConstructorMarker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a delegating property, create a "property" corresponding to the underlying delegate itself.
|
||||
* This will take care of backing fields, accessors, and other such stuff.
|
||||
* Note that we just replace <code>kotlinType</code> with the <code>delegateKotlinType</code>
|
||||
* (so that type coercion will work properly),
|
||||
* and <code>delegateKotlinType</code> with <code>null</code>
|
||||
* (so that the resulting property has no underlying delegate of its own).
|
||||
*
|
||||
* @param delegating delegating property
|
||||
* @param marker intent marker
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private Property(@NotNull Property delegating, @NotNull DelegatePropertyConstructorMarker marker) {
|
||||
super(delegating.type, delegating.delegateKotlinType,
|
||||
delegating.isStaticPut, delegating.isStaticStore, delegating.receiver, true);
|
||||
|
||||
this.backingFieldOwner = delegating.backingFieldOwner;
|
||||
this.getter = delegating.getter;
|
||||
this.setter = delegating.setter;
|
||||
this.descriptor = delegating.descriptor;
|
||||
this.fieldName = delegating.fieldName;
|
||||
this.codegen = delegating.codegen;
|
||||
this.resolvedCall = delegating.resolvedCall;
|
||||
this.skipLateinitAssertion = delegating.skipLateinitAssertion;
|
||||
this.delegateKotlinType = null;
|
||||
}
|
||||
|
||||
public Property getDelegateOrNull() {
|
||||
if (delegateKotlinType == null) return null;
|
||||
return new Property(this, DelegatePropertyConstructorMarker.MARKER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user