diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java index 444be227076..b0722e6d6f5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClosureCodegen.java @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.load.java.JvmAbi; @@ -423,11 +424,16 @@ public class ClosureCodegen extends MemberCodegen { for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { - Type sharedVarType = typeMapper.getSharedVarType(descriptor); - - Type type = sharedVarType != null - ? sharedVarType - : typeMapper.mapType((VariableDescriptor) descriptor); + Type type = typeMapper.getSharedVarType(descriptor); + if (type == null && descriptor instanceof LocalVariableDescriptor) { + KotlinType delegateType = JvmCodegenUtil.getPropertyDelegateType((LocalVariableDescriptor) descriptor, bindingContext); + if (delegateType != null) { + type = typeMapper.mapType(delegateType); + } + } + if (type == null) { + type = typeMapper.mapType((VariableDescriptor) descriptor); + } args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString())); } else if (ExpressionTypingUtils.isLocalFunction(descriptor)) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 159ce2b2b43..79c71019877 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -47,6 +47,7 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.when.SwitchCodegen; import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor; import org.jetbrains.kotlin.diagnostics.DiagnosticUtils; import org.jetbrains.kotlin.diagnostics.Errors; @@ -58,6 +59,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; @@ -74,6 +76,7 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.inline.InlineUtil; +import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; @@ -1612,7 +1615,20 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull private Type getVariableType(@NotNull VariableDescriptor variableDescriptor) { Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); - return sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType()); + return sharedVarType != null ? sharedVarType : getVariableTypeNoSharing(variableDescriptor); + } + + @NotNull + private Type getVariableTypeNoSharing(@NotNull VariableDescriptor variableDescriptor) { + KotlinType varType = isDelegatedLocalVariable(variableDescriptor) + ? JvmCodegenUtil.getPropertyDelegateType((VariableDescriptorWithAccessors) variableDescriptor, bindingContext) + : variableDescriptor.getType(); + //noinspection ConstantConditions + return asmType(varType); + } + + private static boolean isDelegatedLocalVariable(@NotNull DeclarationDescriptor descriptor) { + return descriptor instanceof LocalVariableDescriptor && ((VariableDescriptorWithAccessors) descriptor).getGetter() != null; } private static boolean isSharedVarType(@NotNull Type type) { @@ -1647,6 +1663,11 @@ public class ExpressionCodegen extends KtVisitor impleme Type type = getVariableType(variableDescriptor); int index = myFrameMap.enter(variableDescriptor, type); + if (isDelegatedLocalVariable(variableDescriptor)) { + VariableDescriptor metadataVariableDescriptor = bindingContext.get(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor); + myFrameMap.enter(metadataVariableDescriptor, AsmTypes.K_PROPERTY0_TYPE); + } + if (isSharedVarType(type)) { markLineNumber(statement, false); v.anew(type); @@ -1693,6 +1714,11 @@ public class ExpressionCodegen extends KtVisitor impleme leaveTasks.add(new Function() { @Override public Void fun(StackValue answer) { + if (isDelegatedLocalVariable(variableDescriptor)) { + VariableDescriptor metadataVariableDescriptor = bindingContext.get(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor); + myFrameMap.leave(metadataVariableDescriptor); + } + int index = myFrameMap.leave(variableDescriptor); if (isSharedVarType(type)) { @@ -2112,18 +2138,20 @@ public class ExpressionCodegen extends KtVisitor impleme return StackValue.shared(parameterOffsetInConstructor, parentResult.type); } - return StackValue.local(parameterOffsetInConstructor, parentResult.type); + return adjustVariableValue(StackValue.local(parameterOffsetInConstructor, parentResult.type), descriptor); } private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) { if (descriptor instanceof VariableDescriptor) { + VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor; + Type sharedVarType = typeMapper.getSharedVarType(descriptor); - KotlinType outType = ((VariableDescriptor) descriptor).getType(); + Type varType = getVariableTypeNoSharing(variableDescriptor); if (sharedVarType != null) { - return StackValue.shared(index, asmType(outType)); + return StackValue.shared(index, varType); } else { - return StackValue.local(index, asmType(outType)); + return adjustVariableValue(StackValue.local(index, varType), variableDescriptor); } } else { @@ -2140,19 +2168,6 @@ public class ExpressionCodegen extends KtVisitor impleme return myFrameMap.getIndex(descriptor); } - @Nullable - private static KotlinType getPropertyDelegateType(@NotNull PropertyDescriptor descriptor, @NotNull BindingContext bindingContext) { - PropertyGetterDescriptor getter = descriptor.getGetter(); - if (getter != null) { - Call call = bindingContext.get(DELEGATED_PROPERTY_CALL, getter); - if (call != null) { - assert call.getExplicitReceiver() != null : "No explicit receiver for call:" + call; - return ((ReceiverValue) call.getExplicitReceiver()).getType(); - } - } - return null; - } - @NotNull public StackValue.Property intermediateValueForProperty( @NotNull PropertyDescriptor propertyDescriptor, @@ -2204,7 +2219,7 @@ public class ExpressionCodegen extends KtVisitor impleme boolean isSuper = superCallTarget != null; boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null; - KotlinType delegateType = getPropertyDelegateType(propertyDescriptor, bindingContext); + KotlinType delegateType = JvmCodegenUtil.getPropertyDelegateType(propertyDescriptor, bindingContext); boolean isDelegatedProperty = delegateType != null; CallableMethod callableGetter = null; @@ -2828,7 +2843,9 @@ public class ExpressionCodegen extends KtVisitor impleme VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); if (variableDescriptor != null) { - return generatePropertyReference(expression, variableDescriptor, resolvedCall); + return generatePropertyReference(expression, variableDescriptor, + (VariableDescriptor) resolvedCall.getResultingDescriptor(), + resolvedCall.getDispatchReceiver()); } throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); @@ -2838,7 +2855,8 @@ public class ExpressionCodegen extends KtVisitor impleme private StackValue generatePropertyReference( @NotNull KtElement element, @NotNull VariableDescriptor variableDescriptor, - @NotNull ResolvedCall resolvedCall + @NotNull VariableDescriptor target, + @Nullable ReceiverValue dispatchReceiver ) { ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor); @@ -2850,7 +2868,7 @@ public class ExpressionCodegen extends KtVisitor impleme PropertyReferenceCodegen codegen = new PropertyReferenceCodegen( state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION), - element, classBuilder, resolvedCall + element, classBuilder, target, dispatchReceiver ); codegen.generate(); @@ -3371,10 +3389,16 @@ public class ExpressionCodegen extends KtVisitor impleme @Override public StackValue visitProperty(@NotNull KtProperty property, StackValue receiver) { KtExpression initializer = property.getInitializer(); - if (initializer == null) { - return StackValue.none(); + KtExpression delegateExpression = property.getDelegateExpression(); + + if (initializer != null) { + assert delegateExpression == null : PsiUtilsKt.getElementTextWithContext(property); + initializeLocalVariable(property, gen(initializer)); } - initializeLocalVariable(property, gen(initializer)); + else if (delegateExpression != null) { + initializeLocalVariable(property, gen(delegateExpression)); + } + return StackValue.none(); } @@ -3412,11 +3436,27 @@ public class ExpressionCodegen extends KtVisitor impleme return StackValue.none(); } + @Nullable + private StackValue getVariableMetadataValue(VariableDescriptor variableDescriptor) { + VariableDescriptor metadataVariableDescriptor = bindingContext.get(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor); + return metadataVariableDescriptor != null ? findLocalOrCapturedValue(metadataVariableDescriptor) : null; + } + + @NotNull + private StackValue adjustVariableValue(@NotNull StackValue varValue, DeclarationDescriptor descriptor) { + if (!isDelegatedLocalVariable(descriptor)) return varValue; + + VariableDescriptorWithAccessors variableDescriptor = (VariableDescriptorWithAccessors) descriptor; + StackValue metadataValue = getVariableMetadataValue(variableDescriptor); + assert metadataValue != null : variableDescriptor; + return JvmCodegenUtil.delegatedVariableValue(varValue, metadataValue, variableDescriptor, bindingContext, typeMapper); + } + private void initializeLocalVariable( @NotNull KtVariableDeclaration variableDeclaration, @NotNull StackValue initializer ) { - VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, variableDeclaration); + LocalVariableDescriptor variableDescriptor = (LocalVariableDescriptor) bindingContext.get(VARIABLE, variableDeclaration); if (KtPsiUtil.isScriptDeclaration(variableDeclaration)) { return; @@ -3430,7 +3470,7 @@ public class ExpressionCodegen extends KtVisitor impleme Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor); assert variableDescriptor != null; - Type varType = asmType(variableDescriptor.getType()); + Type varType = getVariableTypeNoSharing(variableDescriptor); StackValue storeTo = sharedVarType == null ? StackValue.local(index, varType) : StackValue.shared(index, varType); @@ -3440,6 +3480,37 @@ public class ExpressionCodegen extends KtVisitor impleme markLineNumber(variableDeclaration, false); storeTo.storeSelector(initializer.type, v); + + StackValue metadataValue = getVariableMetadataValue(variableDescriptor); + if (metadataValue != null) { + initializePropertyMetadata((KtProperty) variableDeclaration, variableDescriptor, metadataValue); + invokePropertyDelegatedOnLocalVar(variableDescriptor, storeTo, metadataValue); + } + } + + private void invokePropertyDelegatedOnLocalVar( + @NotNull LocalVariableDescriptor variableDescriptor, + @NotNull StackValue delegateValue, + @NotNull StackValue metadataValue + ) { + ResolvedCall pdResolvedCall = + bindingContext.get(BindingContext.DELEGATED_PROPERTY_PD_RESOLVED_CALL, variableDescriptor); + if (pdResolvedCall == null) return; + + tempVariables.put(pdResolvedCall.getCall().getValueArguments().get(0).asElement(), metadataValue); + invokeFunction(pdResolvedCall, delegateValue).put(Type.VOID_TYPE, v); + } + + private void initializePropertyMetadata( + @NotNull KtProperty variable, + @NotNull LocalVariableDescriptor variableDescriptor, + @NotNull StackValue metadataVar + ) { + //noinspection ConstantConditions + StackValue value = + generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null); + value.put(K_PROPERTY0_TYPE, v); + metadataVar.storeSelector(K_PROPERTY0_TYPE, v); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java index b2a4f14d1ca..031056797bc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmCodegenUtil.java @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor; import org.jetbrains.kotlin.load.kotlin.ModuleMapping; import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityUtilsKt; +import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFunction; import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilKt; @@ -40,14 +41,17 @@ import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.inline.InlineUtil; +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; import org.jetbrains.kotlin.types.KotlinType; import java.io.File; +import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.LOCAL_VARIABLE_DELEGATE; import static org.jetbrains.kotlin.descriptors.Modality.ABSTRACT; import static org.jetbrains.kotlin.descriptors.Modality.FINAL; import static org.jetbrains.kotlin.resolve.jvm.annotations.AnnotationUtilKt.hasJvmFieldAnnotation; +import static org.jetbrains.kotlin.resolve.BindingContext.DELEGATED_PROPERTY_CALL; public class JvmCodegenUtil { @@ -223,4 +227,40 @@ public class JvmCodegenUtil { if (!(descriptor instanceof JavaPropertyDescriptor)) return false; return descriptor.isConst(); } + + @Nullable + public static KotlinType getPropertyDelegateType( + @NotNull VariableDescriptorWithAccessors descriptor, + @NotNull BindingContext bindingContext + ) { + VariableAccessorDescriptor getter = descriptor.getGetter(); + if (getter != null) { + Call call = bindingContext.get(DELEGATED_PROPERTY_CALL, getter); + if (call != null) { + assert call.getExplicitReceiver() != null : "No explicit receiver for call:" + call; + return ((ReceiverValue) call.getExplicitReceiver()).getType(); + } + } + return null; + } + + @NotNull + public static StackValue.Delegate delegatedVariableValue( + @NotNull StackValue delegateValue, + @NotNull StackValue metadataValue, + VariableDescriptorWithAccessors variableDescriptor, + @NotNull BindingContext bindingContext, + @NotNull KotlinTypeMapper typeMapper + ) { + VariableDescriptor delegateVariableDescriptor = bindingContext.get(LOCAL_VARIABLE_DELEGATE, variableDescriptor); + assert delegateVariableDescriptor != null : variableDescriptor; + + VariableAccessorDescriptor getterDescriptor = variableDescriptor.getGetter(); + VariableAccessorDescriptor setterDescriptor = variableDescriptor.getSetter(); + + //noinspection ConstantConditions + CallableMethod getterMethod = typeMapper.mapToCallableMethod(getterDescriptor, false); + CallableMethod setterMethod = setterDescriptor != null ? typeMapper.mapToCallableMethod(setterDescriptor, false) : null; + return StackValue.delegate(typeMapper.mapType(variableDescriptor.getType()), delegateValue, metadataValue, getterMethod, setterMethod); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java index 672c04dc316..06daf885925 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.builtins.DefaultBuiltIns; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl; import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor; import org.jetbrains.kotlin.name.FqName; @@ -39,6 +40,8 @@ public class JvmRuntimeTypes { private final ClassDescriptor functionReference; private final List propertyReferences; private final List mutablePropertyReferences; + private final ClassDescriptor localVariableReference; + private final ClassDescriptor mutableLocalVariableReference; public JvmRuntimeTypes() { ModuleDescriptorImpl module = TargetPlatformKt.createModule( @@ -47,9 +50,12 @@ public class JvmRuntimeTypes { LockBasedStorageManager.NO_LOCKS, DefaultBuiltIns.getInstance()); PackageFragmentDescriptor kotlinJvmInternal = new MutablePackageFragmentDescriptor(module, new FqName("kotlin.jvm.internal")); + PackageFragmentDescriptor kotlinReflectJvmInternal = new MutablePackageFragmentDescriptor(module, new FqName("kotlin.reflect.jvm.internal")); this.lambda = createClass(kotlinJvmInternal, "Lambda"); this.functionReference = createClass(kotlinJvmInternal, "FunctionReference"); + this.localVariableReference = createClass(kotlinReflectJvmInternal, "LocalVariableReference"); + this.mutableLocalVariableReference = createClass(kotlinReflectJvmInternal, "MutableLocalVariableReference"); this.propertyReferences = new ArrayList(3); this.mutablePropertyReferences = new ArrayList(3); @@ -110,7 +116,11 @@ public class JvmRuntimeTypes { } @NotNull - public KotlinType getSupertypeForPropertyReference(@NotNull PropertyDescriptor descriptor) { + public KotlinType getSupertypeForPropertyReference(@NotNull VariableDescriptorWithAccessors descriptor) { + if (descriptor instanceof LocalVariableDescriptor) { + return (descriptor.isVar() ? mutableLocalVariableReference : localVariableReference).getDefaultType(); + } + int arity = (descriptor.getExtensionReceiverParameter() != null ? 1 : 0) + (descriptor.getDispatchReceiverParameter() != null ? 1 : 0); return (descriptor.isVar() ? mutablePropertyReferences : propertyReferences).get(arity).getDefaultType(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt index a993743ad88..cf9eb3265fc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt @@ -21,17 +21,18 @@ import org.jetbrains.kotlin.codegen.context.ClassContext import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.PropertyImportedFromObject -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.utils.sure import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type @@ -44,13 +45,13 @@ class PropertyReferenceCodegen( context: ClassContext, expression: KtElement, classBuilder: ClassBuilder, - resolvedCall: ResolvedCall<*> + private val target: VariableDescriptor, + dispatchReceiver: ReceiverValue? ) : MemberCodegen(state, parentCodegen, context, expression, classBuilder) { private val classDescriptor = context.contextDescriptor private val asmType = typeMapper.mapClass(classDescriptor) - private val target = resolvedCall.resultingDescriptor as VariableDescriptor - private val dispatchReceiverType = resolvedCall.dispatchReceiver?.type + private val dispatchReceiverType = dispatchReceiver?.type private val extensionReceiverType = target.extensionReceiverParameter?.type private val receiverCount = @@ -85,8 +86,10 @@ class PropertyReferenceCodegen( invokespecial(superAsmType.internalName, "", "()V", false) } - generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) { - ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state) + if (target !is LocalVariableDescriptor) { + generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) { + ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, state) + } } generateMethod("property reference getName", ACC_PUBLIC, method("getName", JAVA_STRING_TYPE)) { @@ -94,7 +97,7 @@ class PropertyReferenceCodegen( } generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) { - aconst(getPropertyReferenceSignature(target as PropertyDescriptor, state)) + aconst(getPropertyReferenceSignature(target as VariableDescriptorWithAccessors, state)) } generateAccessors() @@ -125,7 +128,10 @@ class PropertyReferenceCodegen( StackValue.local(index + 1, OBJECT_TYPE).put(typeMapper.mapType(type), this) } - val value = fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, StackValue.none()) + val value = if (target is LocalVariableDescriptor) { + fakeCodegen.findLocalOrCapturedValue(target)!! + } + else fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, StackValue.none()) accessorBody(value) } @@ -168,9 +174,9 @@ class PropertyReferenceCodegen( companion object { @JvmStatic - fun getPropertyReferenceSignature(property: PropertyDescriptor, state: GenerationState): String { + fun getPropertyReferenceSignature(property: VariableDescriptorWithAccessors, state: GenerationState): String { val getter = - property.getter ?: DescriptorFactory.createDefaultGetter(property, Annotations.EMPTY).apply { + property.getter ?: DescriptorFactory.createDefaultGetter(property as PropertyDescriptor, Annotations.EMPTY).apply { initialize(property.type) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index a36f5cd6c63..93cae534666 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -152,6 +152,17 @@ public abstract class StackValue { return new Local(index, type); } + @NotNull + public static Delegate delegate( + Type type, + @NotNull StackValue delegateValue, + @NotNull StackValue metadataValue, + @NotNull CallableMethod getter, + @Nullable CallableMethod setter + ) { + return new Delegate(type, delegateValue, metadataValue, getter, setter); + } + @NotNull public static StackValue shared(int index, @NotNull Type type) { return new Shared(index, type); @@ -245,17 +256,8 @@ public abstract class StackValue { @NotNull public static StackValue changeReceiverForFieldAndSharedVar(@NotNull StackValueWithSimpleReceiver stackValue, @Nullable StackValue newReceiver) { //TODO static check - if (newReceiver != null) { - if (!stackValue.isStaticPut) { - if (stackValue instanceof Field) { - return field((Field) stackValue, newReceiver); - } - else if (stackValue instanceof FieldForSharedVar) { - return fieldForSharedVar((FieldForSharedVar) stackValue, newReceiver); - } - } - } - return stackValue; + if (newReceiver == null || stackValue.isStaticPut) return stackValue; + return stackValue.changeReceiver(newReceiver); } @NotNull @@ -657,6 +659,56 @@ public abstract class StackValue { } } + public static class Delegate extends StackValueWithSimpleReceiver { + @NotNull private final StackValue delegateValue; + @NotNull private final StackValue metadataValue; + @NotNull private final CallableMethod getter; + @Nullable private final CallableMethod setter; + + private Delegate( + Type type, + @NotNull StackValue delegateValue, + @NotNull StackValue metadataValue, + @NotNull CallableMethod getter, + @Nullable CallableMethod setter + ) { + super(type, false, false, new Receiver(OBJECT_TYPE, delegateValue, constant(null, OBJECT_TYPE), metadataValue), false); + this.delegateValue = delegateValue; + this.metadataValue = metadataValue; + this.getter = getter; + this.setter = setter; + } + + @NotNull + public StackValue getMetadataValue() { + return metadataValue; + } + + @Override + public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { + getter.genInvokeInstruction(v); + coerce(getter.getReturnType(), type, v); + } + + @Override + public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) { + assert setter != null : ""; + coerceFrom(topOfStackType, v); + setter.genInvokeInstruction(v); + } + + @Override + protected StackValueWithSimpleReceiver changeReceiver(@NotNull StackValue newReceiver) { + StackValue newDelegateValue = delegateValue instanceof StackValueWithSimpleReceiver + ? ((StackValueWithSimpleReceiver) delegateValue).changeReceiver(newReceiver) + : delegateValue; + StackValue newMetadataValue = metadataValue instanceof StackValueWithSimpleReceiver + ? ((StackValueWithSimpleReceiver) metadataValue).changeReceiver(newReceiver) + : metadataValue; + return delegate(type, newDelegateValue, newMetadataValue, getter, setter); + } + } + public static class OnStack extends StackValue { public OnStack(Type type) { super(type); @@ -1079,6 +1131,11 @@ public abstract class StackValue { coerceFrom(topOfStackType, v); v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor()); } + + @Override + protected StackValueWithSimpleReceiver changeReceiver(@NotNull StackValue newReceiver) { + return field(this, newReceiver); + } } static class Property extends StackValueWithSimpleReceiver { @@ -1297,6 +1354,11 @@ public abstract class StackValue { coerceFrom(topOfStackType, v); v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor()); } + + @Override + protected StackValueWithSimpleReceiver changeReceiver(@NotNull StackValue newReceiver) { + return fieldForSharedVar(this, newReceiver); + } } private static class ThisOuter extends StackValue { @@ -1558,6 +1620,10 @@ public abstract class StackValue { rightSide.put(rightSide.type, v); storeSelector(rightSide.type, v); } + + protected StackValueWithSimpleReceiver changeReceiver(@NotNull StackValue newReceiver) { + return this; + } } private static class ComplexReceiver extends StackValue { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index 275e724b889..9b2a2a62ce4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -23,6 +23,7 @@ import com.intellij.util.containers.Stack; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.ReflectionTypes; import org.jetbrains.kotlin.cfg.WhenChecker; import org.jetbrains.kotlin.codegen.*; import org.jetbrains.kotlin.codegen.state.GenerationState; @@ -30,6 +31,8 @@ import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt; import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil; import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping; 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.descriptors.SamConstructorDescriptor; @@ -46,7 +49,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.constants.EnumValue; import org.jetbrains.kotlin.resolve.constants.NullValue; -import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor; +import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.org.objectweb.asm.Type; @@ -317,12 +320,43 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { fileClassesProvider); } + private void recordLocalVariablePropertyMetadata(LocalVariableDescriptor variableDescriptor) { + KotlinType delegateType = JvmCodegenUtil.getPropertyDelegateType(variableDescriptor, bindingContext); + if (delegateType == null) return; + + LocalVariableDescriptor delegateVariableDescriptor = new LocalVariableDescriptor( + variableDescriptor.getContainingDeclaration(), + Annotations.Companion.getEMPTY(), + variableDescriptor.getName(), + delegateType, + false, + false, + SourceElement.NO_SOURCE + ); + bindingTrace.record(LOCAL_VARIABLE_DELEGATE, variableDescriptor, delegateVariableDescriptor); + + 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); @@ -332,11 +366,11 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { } KtPropertyDelegate delegate = property.getDelegate(); - if (delegate != null && descriptor instanceof PropertyDescriptor) { - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + if (delegate != null && descriptor instanceof VariableDescriptorWithAccessors) { + VariableDescriptorWithAccessors variableDescriptor = (VariableDescriptorWithAccessors) descriptor; String name = inventAnonymousClassName(); - KotlinType supertype = runtimeTypes.getSupertypeForPropertyReference(propertyDescriptor); - ClassDescriptor classDescriptor = recordClassForCallable(delegate, propertyDescriptor, Collections.singleton(supertype), name); + KotlinType supertype = runtimeTypes.getSupertypeForPropertyReference(variableDescriptor); + ClassDescriptor classDescriptor = recordClassForCallable(delegate, variableDescriptor, Collections.singleton(supertype), name); recordClosure(classDescriptor, name); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java index 1c784a9c782..612f4997f30 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java @@ -60,6 +60,12 @@ public class CodegenBinding { public static final WritableSlice> MAPPINGS_FOR_WHENS_BY_ENUM_IN_CLASS_FILE = Slices.createSimpleSlice(); + public static final WritableSlice LOCAL_VARIABLE_DELEGATE = + Slices.createSimpleSlice(); + + public static final WritableSlice LOCAL_VARIABLE_PROPERTY_METADATA = + Slices.createSimpleSlice(); + static { BasicWritableSlice.initSliceDebugNames(CodegenBinding.class); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java index 34668904103..5637d41b308 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/LocalLookup.java @@ -51,10 +51,19 @@ public interface LocalLookup { Type classType ) { VariableDescriptor vd = (VariableDescriptor) d; + VariableDescriptor originalVariableDescriptor = vd; boolean idx = localLookup != null && localLookup.lookupLocal(vd); if (!idx) return null; + boolean delegatedVar = false; + VariableDescriptor delegateVariableDescriptor = state.getBindingContext().get(LOCAL_VARIABLE_DELEGATE, vd); + VariableDescriptor metadataVariableDescriptor = state.getBindingContext().get(LOCAL_VARIABLE_PROPERTY_METADATA, vd); + if (delegateVariableDescriptor != null) { + vd = delegateVariableDescriptor; + delegatedVar = true; + } + Type sharedVarType = state.getTypeMapper().getSharedVarType(vd); Type localType = state.getTypeMapper().mapType(vd); Type type = sharedVarType != null ? sharedVarType : localType; @@ -71,6 +80,18 @@ public interface LocalLookup { } else { innerValue = StackValue.field(type, classType, fieldName, false, thiz, vd); + if (delegatedVar) { + StackValue metadataValue = innerValue(metadataVariableDescriptor, localLookup, state, closure, classType); + assert metadataValue != null : originalVariableDescriptor; + + innerValue = JvmCodegenUtil.delegatedVariableValue( + innerValue, + metadataValue, + (VariableDescriptorWithAccessors) originalVariableDescriptor, + state.getBindingContext(), + state.getTypeMapper() + ); + } enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 2334509c591..759f2ef1c91 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor; import org.jetbrains.kotlin.fileClasses.FileClasses; import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo; import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; @@ -630,6 +631,13 @@ public class KotlinTypeMapper { return new CallableMethod(owner, owner, defaultImplDesc, method, INVOKESPECIAL, null, null, null); } + if (descriptor instanceof LocalVariableAccessorDescriptor) { + ResolvedCall delegateAccessorResolvedCall = + bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, (VariableAccessorDescriptor) descriptor); + //noinspection ConstantConditions + return mapToCallableMethod(delegateAccessorResolvedCall.getResultingDescriptor(), false); + } + DeclarationDescriptor functionParent = descriptor.getOriginal().getContainingDeclaration(); FunctionDescriptor functionDescriptor = unwrapFakeOverride(descriptor.getOriginal()); @@ -1354,14 +1362,22 @@ public class KotlinTypeMapper { if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) { return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); } - else if (descriptor instanceof PropertyDescriptor || descriptor instanceof FunctionDescriptor) { + + if (descriptor instanceof PropertyDescriptor || descriptor instanceof FunctionDescriptor) { ReceiverParameterDescriptor receiverParameter = ((CallableDescriptor) descriptor).getExtensionReceiverParameter(); assert receiverParameter != null : "Callable should have a receiver parameter: " + descriptor; return StackValue.sharedTypeForType(mapType(receiverParameter.getType())); } - else if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) { + + if (descriptor instanceof VariableDescriptorWithAccessors) { + VariableDescriptorWithAccessors withAccessors = (VariableDescriptorWithAccessors) descriptor; + if (withAccessors.getGetter() != null || withAccessors.getSetter() != null) return null; + } + + if (descriptor instanceof VariableDescriptor && isVarCapturedInClosure(bindingContext, descriptor)) { return StackValue.sharedTypeForType(mapType(((VariableDescriptor) descriptor).getType())); } + return null; } } diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalVal.kt b/compiler/testData/codegen/box/delegatedProperty/capturedLocalVal.kt new file mode 100644 index 00000000000..52a0de0cd68 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/capturedLocalVal.kt @@ -0,0 +1,14 @@ +package foo + +import kotlin.reflect.KProperty + +inline fun run(f: () -> T) = f() + +class Delegate { + operator fun getValue(t: Any?, p: KProperty<*>): Int = 1 +} + +fun box(): String { + val prop: Int by Delegate() + return run { if (prop == 1) "OK" else "fail" } +} diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalValNoInline.kt b/compiler/testData/codegen/box/delegatedProperty/capturedLocalValNoInline.kt new file mode 100644 index 00000000000..bb21f1e3b52 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/capturedLocalValNoInline.kt @@ -0,0 +1,14 @@ +package foo + +import kotlin.reflect.KProperty + +fun run(f: () -> T) = f() + +class Delegate { + operator fun getValue(t: Any?, p: KProperty<*>): Int = 1 +} + +fun box(): String { + val prop: Int by Delegate() + return run { if (prop == 1) "OK" else "fail" } +} diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalVar.kt b/compiler/testData/codegen/box/delegatedProperty/capturedLocalVar.kt new file mode 100644 index 00000000000..d655e965ab1 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/capturedLocalVar.kt @@ -0,0 +1,20 @@ +package foo + +import kotlin.reflect.KProperty + +inline fun run(f: () -> T) = f() + +class Delegate { + var inner = 1 + operator fun getValue(t: Any?, p: KProperty<*>): Int = inner + operator fun setValue(t: Any?, p: KProperty<*>, i: Int) { + inner = i + } +} + +fun box(): String { + var prop: Int by Delegate() + run { prop = 2 } + if (prop != 2) return "fail get" + return run { if (prop != 2) "fail set" else "OK" } +} diff --git a/compiler/testData/codegen/box/delegatedProperty/capturedLocalVarNoInline.kt b/compiler/testData/codegen/box/delegatedProperty/capturedLocalVarNoInline.kt new file mode 100644 index 00000000000..8ac07a3f364 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/capturedLocalVarNoInline.kt @@ -0,0 +1,20 @@ +package foo + +import kotlin.reflect.KProperty + +fun run(f: () -> T) = f() + +class Delegate { + var inner = 1 + operator fun getValue(t: Any?, p: KProperty<*>): Int = inner + operator fun setValue(t: Any?, p: KProperty<*>, i: Int) { + inner = i + } +} + +fun box(): String { + var prop: Int by Delegate() + run { prop = 2 } + if (prop != 2) return "fail get" + return run { if (prop != 2) "fail set" else "OK" } +} diff --git a/compiler/testData/codegen/box/delegatedProperty/localVal.kt b/compiler/testData/codegen/box/delegatedProperty/localVal.kt new file mode 100644 index 00000000000..cd3f7178453 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/localVal.kt @@ -0,0 +1,12 @@ +package foo + +import kotlin.reflect.KProperty + +class Delegate { + operator fun getValue(t: Any?, p: KProperty<*>): Int = 1 +} + +fun box(): String { + val prop: Int by Delegate() + return if (prop == 1) "OK" else "fail" +} diff --git a/compiler/testData/codegen/box/delegatedProperty/localVar.kt b/compiler/testData/codegen/box/delegatedProperty/localVar.kt new file mode 100644 index 00000000000..606bc60c871 --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/localVar.kt @@ -0,0 +1,19 @@ +package foo + +import kotlin.reflect.KProperty + +class Delegate { + var inner = 1 + operator fun getValue(t: Any?, p: KProperty<*>): Int = inner + operator fun setValue(t: Any?, p: KProperty<*>, i: Int) { + inner = i + } +} + +fun box(): String { + var prop: Int by Delegate() + if (prop != 1) return "fail get" + prop = 2 + if (prop != 2) return "fail set" + return "OK" +} diff --git a/compiler/testData/codegen/script/localDelegatedProperty.kts b/compiler/testData/codegen/script/localDelegatedProperty.kts new file mode 100644 index 00000000000..b1b6bffbbc3 --- /dev/null +++ b/compiler/testData/codegen/script/localDelegatedProperty.kts @@ -0,0 +1,14 @@ +import kotlin.reflect.KProperty + +class Delegate { + operator fun getValue(t: Any?, p: KProperty<*>): Int = 3 +} + +fun foo(): Int { + val prop: Int by Delegate() + return prop +} + +val x = foo() + +// expected: x: 3 diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 9ec16eb6b8b..eda77f6bf5e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4747,6 +4747,30 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("capturedLocalVal.kt") + public void testCapturedLocalVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalVal.kt"); + doTest(fileName); + } + + @TestMetadata("capturedLocalValNoInline.kt") + public void testCapturedLocalValNoInline() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalValNoInline.kt"); + doTest(fileName); + } + + @TestMetadata("capturedLocalVar.kt") + public void testCapturedLocalVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalVar.kt"); + doTest(fileName); + } + + @TestMetadata("capturedLocalVarNoInline.kt") + public void testCapturedLocalVarNoInline() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/capturedLocalVarNoInline.kt"); + doTest(fileName); + } + @TestMetadata("castGetReturnType.kt") public void testCastGetReturnType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/castGetReturnType.kt"); @@ -4861,6 +4885,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("localVal.kt") + public void testLocalVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/localVal.kt"); + doTest(fileName); + } + + @TestMetadata("localVar.kt") + public void testLocalVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/localVar.kt"); + doTest(fileName); + } + @TestMetadata("privateVar.kt") public void testPrivateVar() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/delegatedProperty/privateVar.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java index 4137f8b07f5..5fe2a56c019 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ScriptCodegenTestGenerated.java @@ -65,6 +65,12 @@ public class ScriptCodegenTestGenerated extends AbstractScriptCodegenTest { doTest(fileName); } + @TestMetadata("localDelegatedProperty.kts") + public void testLocalDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/localDelegatedProperty.kts"); + doTest(fileName); + } + @TestMetadata("localFunction.kts") public void testLocalFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/script/localFunction.kts"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt new file mode 100644 index 00000000000..d99d2174acc --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/EmptyContainerForLocal.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.reflect.jvm.internal + +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.name.Name +import kotlin.reflect.KCallable +import kotlin.reflect.KotlinReflectionInternalError + +internal object EmptyContainerForLocal : KDeclarationContainerImpl() { + override val jClass: Class<*> + get() = fail() + + override val members: Collection> + get() = fail() + + override val constructorDescriptors: Collection + get() = fail() + + override fun getProperties(name: Name): Collection = fail() + + override fun getFunctions(name: Name): Collection = fail() + + private fun fail(): Nothing = throw KotlinReflectionInternalError("Introspecting local functions, lambdas and anonymous functions " + + "is not yet fully supported in Kotlin reflection") +} \ No newline at end of file diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt index 644f470ac51..74c7f3d5568 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionFromReferenceImpl.kt @@ -62,20 +62,3 @@ internal class KFunctionFromReferenceImpl( override fun invoke(p1: Any?, p2: Any?, p3: Any?, p4: Any?, p5: Any?, p6: Any?, p7: Any?, p8: Any?, p9: Any?, p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, p20: Any?, p21: Any?, p22: Any?): Any? = reference(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22) } -internal object EmptyContainerForLocal : KDeclarationContainerImpl() { - override val jClass: Class<*> - get() = fail() - - override val members: Collection> - get() = fail() - - override val constructorDescriptors: Collection - get() = fail() - - override fun getProperties(name: Name): Collection = fail() - - override fun getFunctions(name: Name): Collection = fail() - - private fun fail(): Nothing = throw KotlinReflectionInternalError("Introspecting local functions, lambdas and anonymous functions " + - "is not yet fully supported in Kotlin reflection") -} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/localVariableReferences.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/localVariableReferences.kt new file mode 100644 index 00000000000..cfb442c2b56 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/localVariableReferences.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.reflect.jvm.internal + +import kotlin.jvm.internal.MutablePropertyReference0 +import kotlin.jvm.internal.PropertyReference0 +import kotlin.reflect.KDeclarationContainer + +open class LocalVariableReference : PropertyReference0() { + override fun getOwner(): KDeclarationContainer = EmptyContainerForLocal +} + +open class MutableLocalVariableReference : MutablePropertyReference0() { + override fun getOwner(): KDeclarationContainer = EmptyContainerForLocal +}