toDelegateFor: JVM BE implementation
This commit is contained in:
committed by
Stanislav Erokhin
parent
e2b6d2d849
commit
97d5bbf1c2
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.codegen.inline.*;
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
@@ -46,6 +45,7 @@ import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
@@ -58,6 +58,7 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.storage.NotNullLazyValue;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
@@ -66,6 +67,7 @@ import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.TO_DELEGATE_FOR_RESOLVED_CALL;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_ALIAS;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
@@ -462,10 +464,29 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
||||
KtExpression initializer = property.getDelegateExpressionOrInitializer();
|
||||
assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
|
||||
|
||||
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, false, null, true, StackValue.LOCAL_0,
|
||||
null);
|
||||
StackValue.Property propValue = codegen.intermediateValueForProperty(
|
||||
propertyDescriptor, true, false, null, true, StackValue.LOCAL_0, null);
|
||||
|
||||
ResolvedCall<FunctionDescriptor> toDelegateForResolvedCall = bindingContext.get(TO_DELEGATE_FOR_RESOLVED_CALL, propertyDescriptor);
|
||||
if (toDelegateForResolvedCall == null) {
|
||||
propValue.store(codegen.gen(initializer), codegen.v);
|
||||
return;
|
||||
}
|
||||
|
||||
StackValue toDelegateForReceiver = codegen.gen(initializer);
|
||||
|
||||
int indexOfDelegatedProperty = PropertyCodegen.indexOfDelegatedProperty(property);
|
||||
|
||||
List<? extends ValueArgument> arguments = toDelegateForResolvedCall.getCall().getValueArguments();
|
||||
assert arguments.size() == 2 :
|
||||
"Resolved call for '" + OperatorNameConventions.TO_DELEGATE_FOR.asString() + "' should have exactly 2 value parameters";
|
||||
codegen.tempVariables.put(arguments.get(0).asElement(), StackValue.LOCAL_0);
|
||||
|
||||
StackValue delegateValue = PropertyCodegen.invokeDelegatedPropertyConventionMethodWithReceiver(
|
||||
codegen, typeMapper, toDelegateForResolvedCall, indexOfDelegatedProperty, 1, toDelegateForReceiver);
|
||||
|
||||
propValue.store(delegateValue, codegen.v);
|
||||
|
||||
propValue.store(codegen.gen(initializer), codegen.v);
|
||||
}
|
||||
|
||||
protected boolean shouldInitializeProperty(@NotNull KtProperty property) {
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationSplitter;
|
||||
@@ -367,16 +366,33 @@ public class PropertyCodegen {
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull Annotations annotations
|
||||
) {
|
||||
KtExpression delegateExpression = p.getDelegateExpression();
|
||||
KotlinType delegateType = delegateExpression != null ? bindingContext.getType(p.getDelegateExpression()) : null;
|
||||
if (delegateType == null) {
|
||||
// If delegate expression is unresolved reference
|
||||
delegateType = ErrorUtils.createErrorType("Delegate type");
|
||||
}
|
||||
KotlinType delegateType = getDelegateTypeForProperty(p, propertyDescriptor);
|
||||
|
||||
generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinType getDelegateTypeForProperty(@NotNull KtProperty p, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
KotlinType delegateType = null;
|
||||
|
||||
ResolvedCall<FunctionDescriptor> toDelegateForResolvedCall =
|
||||
bindingContext.get(BindingContext.TO_DELEGATE_FOR_RESOLVED_CALL, propertyDescriptor);
|
||||
KtExpression delegateExpression = p.getDelegateExpression();
|
||||
|
||||
if (toDelegateForResolvedCall != null) {
|
||||
delegateType = toDelegateForResolvedCall.getResultingDescriptor().getReturnType();
|
||||
}
|
||||
else if (delegateExpression != null) {
|
||||
delegateType = bindingContext.getType(delegateExpression);
|
||||
}
|
||||
|
||||
if (delegateType == null) {
|
||||
// Delegation convention is unresolved
|
||||
delegateType = ErrorUtils.createErrorType("Delegate type");
|
||||
}
|
||||
return delegateType;
|
||||
}
|
||||
|
||||
private void generateBackingFieldAccess(
|
||||
@NotNull KtNamedDeclaration p,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@@ -519,20 +535,22 @@ public class PropertyCodegen {
|
||||
final int indexInPropertyMetadataArray,
|
||||
int propertyMetadataArgumentIndex
|
||||
) {
|
||||
CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
|
||||
final Type owner;
|
||||
if (ownerContext instanceof ClassContext) {
|
||||
owner = typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor());
|
||||
}
|
||||
else if (ownerContext instanceof PackageContext) {
|
||||
owner = ((PackageContext) ownerContext).getPackagePartType();
|
||||
}
|
||||
else if (ownerContext instanceof MultifileClassContextBase) {
|
||||
owner = ((MultifileClassContextBase) ownerContext).getFilePartType();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unknown context: " + ownerContext);
|
||||
}
|
||||
StackValue.Property receiver = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
||||
return invokeDelegatedPropertyConventionMethodWithReceiver(
|
||||
codegen, typeMapper, resolvedCall, indexInPropertyMetadataArray, propertyMetadataArgumentIndex,
|
||||
receiver
|
||||
);
|
||||
}
|
||||
|
||||
public static StackValue invokeDelegatedPropertyConventionMethodWithReceiver(
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@NotNull KotlinTypeMapper typeMapper,
|
||||
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
|
||||
final int indexInPropertyMetadataArray,
|
||||
int propertyMetadataArgumentIndex,
|
||||
@Nullable StackValue receiver
|
||||
) {
|
||||
final Type owner = getDelegatedPropertyMetadataOwner(codegen, typeMapper);
|
||||
|
||||
codegen.tempVariables.put(
|
||||
resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
|
||||
@@ -549,8 +567,23 @@ public class PropertyCodegen {
|
||||
}
|
||||
);
|
||||
|
||||
StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
||||
return codegen.invokeFunction(resolvedCall, delegatedProperty);
|
||||
return codegen.invokeFunction(resolvedCall, receiver);
|
||||
}
|
||||
|
||||
private static Type getDelegatedPropertyMetadataOwner(@NotNull ExpressionCodegen codegen, @NotNull KotlinTypeMapper typeMapper) {
|
||||
CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
|
||||
if (ownerContext instanceof ClassContext) {
|
||||
return typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor());
|
||||
}
|
||||
else if (ownerContext instanceof PackageContext) {
|
||||
return ((PackageContext) ownerContext).getPackagePartType();
|
||||
}
|
||||
else if (ownerContext instanceof MultifileClassContextBase) {
|
||||
return ((MultifileClassContextBase) ownerContext).getFilePartType();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unknown context: " + ownerContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
|
||||
|
||||
Reference in New Issue
Block a user