diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 3f0e21923bd..2b783624ca7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -163,12 +163,14 @@ class ReflectionTypes(module: ModuleDescriptor) { val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope) val kProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope) val kProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope) + val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope) + val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope) val kProperty0Impl: ClassDescriptor by ClassLookup(konanInternalScope) val kProperty1Impl: ClassDescriptor by ClassLookup(konanInternalScope) val kMutableProperty0Impl: ClassDescriptor by ClassLookup(konanInternalScope) val kMutableProperty1Impl: ClassDescriptor by ClassLookup(konanInternalScope) - val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope) - val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope) + val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope) + val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope) fun getKFunctionType( annotations: Annotations, diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt index b8eef19c073..7e73a1968fe 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DelegationLowering.kt @@ -29,25 +29,33 @@ import org.jetbrains.kotlin.types.* internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass { private val genericKProperty0ImplType = context.reflectionTypes.kProperty0Impl + private val genericKLocalDelegatedPropertyImplType = context.reflectionTypes.kLocalDelegatedPropertyImpl private val genericKProperty1ImplType = context.reflectionTypes.kProperty1Impl private val genericKMutableProperty0ImplType = context.reflectionTypes.kMutableProperty0Impl private val genericKMutableProperty1ImplType = context.reflectionTypes.kMutableProperty1Impl + private val genericKLocalDelegatedMutablePropertyImplType = context.reflectionTypes.kLocalDelegatedMutablePropertyImpl private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin")) private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor - private fun getKPropertyImplConstructorDescriptor(returnType: KotlinType, isMutable: Boolean): ClassConstructorDescriptor { - val genericKPropertyImplType = if (isMutable) genericKMutableProperty0ImplType else genericKProperty0ImplType + private fun getKPropertyImplConstructorDescriptor(returnType: KotlinType, isLocal: Boolean, isMutable: Boolean): ClassConstructorDescriptor { + val genericKPropertyImplType = + if (isMutable) { + if (isLocal) genericKLocalDelegatedMutablePropertyImplType else genericKMutableProperty0ImplType + } else { + if (isLocal) genericKLocalDelegatedPropertyImplType else genericKProperty0ImplType + } val typeParameterR = genericKPropertyImplType.declaredTypeParameters[0] val typeSubstitutor = TypeSubstitutor.create(mapOf( typeParameterR.typeConstructor to TypeProjectionImpl(returnType))) return genericKPropertyImplType.unsubstitutedPrimaryConstructor!!.substitute(typeSubstitutor)!! } - private fun getKPropertyImplConstructorDescriptor(receiverType: KotlinType?, returnType: KotlinType, isMutable: Boolean) + private fun getKPropertyImplConstructorDescriptor(receiverType: KotlinType?, returnType: KotlinType, isLocal: Boolean, isMutable: Boolean) : ClassConstructorDescriptor { if (receiverType == null) - return getKPropertyImplConstructorDescriptor(returnType, isMutable) + return getKPropertyImplConstructorDescriptor(returnType, isLocal, isMutable) + assert(!isLocal, { "Local delegated property always has implicit receiver" }) val genericKPropertyImplType = if (isMutable) genericKMutableProperty1ImplType else genericKProperty1ImplType val typeParameterT = genericKPropertyImplType.declaredTypeParameters[0] val typeParameterR = genericKPropertyImplType.declaredTypeParameters[1] @@ -99,9 +107,11 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa val propertyDescriptor = expression.descriptor as? VariableDescriptorWithAccessors if (propertyDescriptor == null) return expression val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null } - if (receiversCount == 1 || propertyDescriptor !is PropertyDescriptor) // Has receiver or is local delegated. + if (receiversCount == 1 && propertyDescriptor is PropertyDescriptor) // Has receiver and is not local delegated. return createKProperty(expression, propertyDescriptor) - else if (receiversCount == 0) { // Cache KProperties with no arguments. + else if (receiversCount == 2) + throw AssertionError("Callable reference to properties with two receivers is not allowed: $propertyDescriptor") + else { // Cache KProperties with no arguments. val field = kProperties.getOrPut(propertyDescriptor) { createKProperty(expression, propertyDescriptor) to kProperties.size } @@ -111,7 +121,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second)) } } - else throw AssertionError("Callable reference to properties with two receivers is not allowed: $propertyDescriptor") + } }) @@ -127,32 +137,39 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa } private fun createKProperty(expression: IrCallableReference, propertyDescriptor: VariableDescriptorWithAccessors): IrCallImpl { - val getter = propertyDescriptor.getter!! - val receiverTypes = mutableListOf() - getter.dispatchReceiverParameter.let { - if (it != null && expression.dispatchReceiver == null) - receiverTypes.add(it.type) - } - getter.extensionReceiverParameter.let { - if (it != null && expression.extensionReceiver == null) - receiverTypes.add(it.type) - } - val receiverType = receiverTypes.singleOrNull() - val startOffset = expression.startOffset val endOffset = expression.endOffset - val getterKFunctionType = context.reflectionTypes.getKFunctionType( - annotations = Annotations.EMPTY, - receiverType = receiverType, - parameterTypes = listOf(), - returnType = propertyDescriptor.type) - val getterCallableReference = IrCallableReferenceImpl(startOffset, endOffset, getterKFunctionType, getter, null).apply { - dispatchReceiver = expression.dispatchReceiver - extensionReceiver = expression.extensionReceiver + var receiverType: KotlinType? = null + val isLocal = propertyDescriptor !is PropertyDescriptor + + val getterCallableReference = propertyDescriptor.getter.let { + if (it == null || isLocal) null + else { + val getter = propertyDescriptor.getter!! + val receiverTypes = mutableListOf() + getter.dispatchReceiverParameter.let { + if (it != null && expression.dispatchReceiver == null) + receiverTypes.add(it.type) + } + getter.extensionReceiverParameter.let { + if (it != null && expression.extensionReceiver == null) + receiverTypes.add(it.type) + } + receiverType = receiverTypes.singleOrNull() + val getterKFunctionType = context.reflectionTypes.getKFunctionType( + annotations = Annotations.EMPTY, + receiverType = receiverType, + parameterTypes = listOf(), + returnType = propertyDescriptor.type) + IrCallableReferenceImpl(startOffset, endOffset, getterKFunctionType, getter, null).apply { + dispatchReceiver = expression.dispatchReceiver + extensionReceiver = expression.extensionReceiver + } + } } val setterCallableReference = propertyDescriptor.setter.let { - if (it == null) null + if (it == null || isLocal) null else { val setterKFunctionType = context.reflectionTypes.getKFunctionType( annotations = Annotations.EMPTY, @@ -166,11 +183,16 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa } } - val descriptor = getKPropertyImplConstructorDescriptor(receiverType, propertyDescriptor.type, setterCallableReference != null) + val descriptor = getKPropertyImplConstructorDescriptor( + receiverType = receiverType, + returnType = propertyDescriptor.type, + isLocal = isLocal, + isMutable = setterCallableReference != null) val initializer = IrCallImpl(startOffset, endOffset, descriptor).apply { putValueArgument(0, IrConstImpl(startOffset, endOffset, context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString())) - putValueArgument(1, getterCallableReference) + if (getterCallableReference != null) + putValueArgument(1, getterCallableReference) if (setterCallableReference != null) putValueArgument(2, setterCallableReference) } diff --git a/runtime/src/main/kotlin/konan/internal/KPropertyImpl.kt b/runtime/src/main/kotlin/konan/internal/KPropertyImpl.kt index de920a14299..f43a8f2cff9 100644 --- a/runtime/src/main/kotlin/konan/internal/KPropertyImpl.kt +++ b/runtime/src/main/kotlin/konan/internal/KPropertyImpl.kt @@ -6,6 +6,7 @@ import kotlin.reflect.KProperty2 import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty2 +import kotlin.UnsupportedOperationException @FixmeReflection open class KProperty0Impl(override val name: String, val getter: () -> R): KProperty0 { @@ -47,7 +48,7 @@ class KMutableProperty0Impl(name: String, getter: () -> R, val setter: (R) -> } @FixmeReflection -public class KMutableProperty1Impl(name: String, getter: (T) -> R, val setter: (T, R) -> Unit) +class KMutableProperty1Impl(name: String, getter: (T) -> R, val setter: (T, R) -> Unit) : KProperty1Impl(name, getter), KMutableProperty1 { override fun set(receiver: T, value: R): Unit { setter(receiver, value) @@ -55,9 +56,24 @@ public class KMutableProperty1Impl(name: String, getter: (T) -> R, val set } @FixmeReflection -public class KMutableProperty2Impl(name: String, getter: (T1, T2) -> R, val setter: (T1, T2, R) -> Unit) +class KMutableProperty2Impl(name: String, getter: (T1, T2) -> R, val setter: (T1, T2, R) -> Unit) : KProperty2Impl(name, getter), KMutableProperty2 { override fun set(receiver1: T1, receiver2: T2, value: R): Unit { setter(receiver1, receiver2, value) } } + +open class KLocalDelegatedPropertyImpl(override val name: String): KProperty0 { + override fun get(): R { + throw UnsupportedOperationException("Not supported for local property reference.") + } + override fun invoke(): R { + throw UnsupportedOperationException("Not supported for local property reference.") + } +} + +class KLocalDelegatedMutablePropertyImpl(name: String): KLocalDelegatedPropertyImpl(name), KMutableProperty0 { + override fun set(value: R): Unit { + throw UnsupportedOperationException("Not supported for local property reference.") + } +} \ No newline at end of file