toDelegateFor: JVM BE implementation

This commit is contained in:
Dmitry Petrov
2016-12-06 17:31:02 +03:00
committed by Stanislav Erokhin
parent e2b6d2d849
commit 97d5bbf1c2
16 changed files with 464 additions and 27 deletions
@@ -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 {