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 797e7573912..707be93221c 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 @@ -9,17 +9,26 @@ import org.jetbrains.kotlin.backend.konan.llvm.Llvm import org.jetbrains.kotlin.backend.konan.llvm.LlvmDeclarations import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.verifyModule +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.getFunctionTypeArgumentProjections import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.KotlinTypeFactory import java.lang.System.out +import kotlin.reflect.KProperty internal class SpecialDescriptorsFactory(val context: Context) { private val enumSpecialDescriptorsFactory by lazy { EnumSpecialDescriptorsFactory(context) } @@ -106,11 +115,63 @@ internal class SpecialDescriptorsFactory(val context: Context) { } } + +class ReflectionTypes(module: ModuleDescriptor) { + val KOTLIN_REFLECT_FQ_NAME = FqName("kotlin.reflect") + val KONAN_INTERNAL_FQ_NAME = FqName("konan.internal") + + private val kotlinReflectScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) { + module.getPackage(KOTLIN_REFLECT_FQ_NAME).memberScope + } + + private val konanInternalScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) { + module.getPackage(KONAN_INTERNAL_FQ_NAME).memberScope + } + + private fun find(memberScope: MemberScope, className: String): ClassDescriptor { + val name = Name.identifier(className) + return memberScope.getContributedClassifier(name, NoLookupLocation.FROM_REFLECTION) as ClassDescriptor + } + + private class ClassLookup(val memberScope: MemberScope) { + operator fun getValue(types: ReflectionTypes, property: KProperty<*>): ClassDescriptor { + return types.find(memberScope, property.name.capitalize()) + } + } + + fun getKFunction(n: Int): ClassDescriptor = find(kotlinReflectScope, "KFunction$n") + + val kClass: ClassDescriptor by ClassLookup(kotlinReflectScope) + val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope) + val kProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope) + val kProperty2: 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) + + fun getKFunctionType( + annotations: Annotations, + receiverType: KotlinType?, + parameterTypes: List, + parameterNames: List?, + returnType: KotlinType, + builtIns: KotlinBuiltIns + ): KotlinType { + val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns) + val classDescriptor = getKFunction(arguments.size - 1 /* return type */) + return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments) + } +} + internal class Context(val config: KonanConfig) : KonanBackendContext() { var moduleDescriptor: ModuleDescriptor? = null val specialDescriptorsFactory = SpecialDescriptorsFactory(this) + val reflectionTypes: ReflectionTypes by lazy { ReflectionTypes(moduleDescriptor!!) } private val vtableBuilders = mutableMapOf() fun getVtableBuilder(classDescriptor: ClassDescriptor) = vtableBuilders.getOrPut(classDescriptor) { 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 4dfe4a61bf3..99f0d540f23 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 @@ -1,26 +1,26 @@ package org.jetbrains.kotlin.backend.konan.lower -import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.jvm.descriptors.initialize import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.descriptors.OverriddenFunctionDescriptor import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.ir.createArrayOfExpression -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl -import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.IrCallableReference +import org.jetbrains.kotlin.ir.expressions.IrConstKind +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.FqName @@ -28,31 +28,48 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.* internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass { - private val kotlinReflectPackage = context.irModule!!.descriptor.getPackage(FqName.fromSegments(listOf("kotlin", "reflect"))) - private val genericKPropertyImplType = kotlinReflectPackage.memberScope.getContributedClassifier(Name.identifier("KPropertyImpl"), - NoLookupLocation.FROM_BACKEND) as ClassDescriptor + private val genericKProperty0ImplType = context.reflectionTypes.kProperty0Impl + private val genericKProperty1ImplType = context.reflectionTypes.kProperty1Impl + private val genericKMutableProperty0ImplType = context.reflectionTypes.kMutableProperty0Impl + private val genericKMutableProperty1ImplType = context.reflectionTypes.kMutableProperty1Impl private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin")) private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor - fun getKPropertyImplConstructorDescriptorWithProjection(type: KotlinType): ClassConstructorDescriptor { - val typeParameterT = genericKPropertyImplType.declaredTypeParameters[0] - val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(type))) + private fun getKPropertyImplConstructorDescriptor(returnType: KotlinType, isMutable: Boolean): ClassConstructorDescriptor { + val genericKPropertyImplType = if (isMutable) genericKMutableProperty0ImplType else genericKProperty0ImplType + val typeParameterR = genericKPropertyImplType.declaredTypeParameters[0] + val typeSubstitutor = TypeSubstitutor.create(mapOf( + typeParameterR.typeConstructor to TypeProjectionImpl(returnType))) return genericKPropertyImplType.unsubstitutedPrimaryConstructor!!.substitute(typeSubstitutor)!! } - fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType { + private fun getKPropertyImplConstructorDescriptor(receiverType: KotlinType?, returnType: KotlinType, isMutable: Boolean) + : ClassConstructorDescriptor { + if (receiverType == null) + return getKPropertyImplConstructorDescriptor(returnType, isMutable) + val genericKPropertyImplType = if (isMutable) genericKMutableProperty1ImplType else genericKProperty1ImplType + val typeParameterT = genericKPropertyImplType.declaredTypeParameters[0] + val typeParameterR = genericKPropertyImplType.declaredTypeParameters[1] + val typeSubstitutor = TypeSubstitutor.create(mapOf( + typeParameterT.typeConstructor to TypeProjectionImpl(receiverType), + typeParameterR.typeConstructor to TypeProjectionImpl(returnType))) + return genericKPropertyImplType.unsubstitutedPrimaryConstructor!!.substitute(typeSubstitutor)!! + } + + private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType { return this.defaultType.replace(type.map(::TypeProjectionImpl)) } override fun lower(irFile: IrFile) { val kProperties = mutableMapOf>() - val getter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"), NoLookupLocation.FROM_BACKEND).single() + val arrayItemGetter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"), + NoLookupLocation.FROM_BACKEND).single() val typeParameterT = genericArrayType.declaredTypeParameters[0] - val kPropertyImplType = genericKPropertyImplType.replace(context.builtIns.anyType) + val kPropertyImplType = genericKProperty1ImplType.replace(context.builtIns.anyType, context.builtIns.anyType) val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(kPropertyImplType))) - val substitutedGetter = getter.substitute(typeSubstitutor)!! + val substitutedArrayItemGetter = arrayItemGetter.substitute(typeSubstitutor)!! val kPropertiesField = createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor, genericArrayType.replace(kPropertyImplType)) @@ -81,26 +98,27 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa expression.transformChildrenVoid(this) val propertyDescriptor = expression.descriptor as? VariableDescriptorWithAccessors if (propertyDescriptor == null) return expression - val field = kProperties.getOrPut(propertyDescriptor) { - val initializer = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, - getKPropertyImplConstructorDescriptorWithProjection(propertyDescriptor.type)).apply { - putValueArgument(0, IrConstImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, - context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString())) + val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null } + when (receiversCount) { + 0 -> { // Cache KProperties with no arguments. + val field = kProperties.getOrPut(propertyDescriptor) { + createKProperty(expression, propertyDescriptor) to kProperties.size + } + + return IrCallImpl(expression.startOffset, expression.endOffset, substitutedArrayItemGetter).apply { + dispatchReceiver = IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField) + putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second)) + } } - val index = kProperties.size - - initializer to index - } - - return IrCallImpl(expression.startOffset, expression.endOffset, substitutedGetter).apply { - dispatchReceiver = IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField) - putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second)) + 1 -> return createKProperty(expression, propertyDescriptor) + else -> throw AssertionError("Callable reference to properties with two receivers is not allowed: $propertyDescriptor") } } }) if (kProperties.isNotEmpty()) { val initializers = kProperties.values.sortedBy { it.second }.map { it.first } + // TODO: move to object for lazy initialization. irFile.declarations.add(0, IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, kPropertiesField, @@ -109,6 +127,61 @@ 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(), + parameterNames = null, + returnType = propertyDescriptor.type, + builtIns = context.builtIns) + val getterCallableReference = IrCallableReferenceImpl(startOffset, endOffset, getterKFunctionType, getter, null).apply { + dispatchReceiver = expression.dispatchReceiver + extensionReceiver = expression.extensionReceiver + } + + val setterCallableReference = propertyDescriptor.setter.let { + if (it == null) null + else { + val setterKFunctionType = context.reflectionTypes.getKFunctionType( + annotations = Annotations.EMPTY, + receiverType = receiverType, + parameterTypes = listOf(propertyDescriptor.type), + parameterNames = null, + returnType = context.builtIns.unitType, + builtIns = context.builtIns) + IrCallableReferenceImpl(startOffset, endOffset, setterKFunctionType, it, null).apply { + dispatchReceiver = expression.dispatchReceiver + extensionReceiver = expression.extensionReceiver + } + } + } + + val descriptor = getKPropertyImplConstructorDescriptor(receiverType, propertyDescriptor.type, 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 (setterCallableReference != null) + putValueArgument(2, setterCallableReference) + } + return initializer + } + private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION : IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION") diff --git a/runtime/src/main/kotlin/konan/internal/KPropertyImpl.kt b/runtime/src/main/kotlin/konan/internal/KPropertyImpl.kt new file mode 100644 index 00000000000..de920a14299 --- /dev/null +++ b/runtime/src/main/kotlin/konan/internal/KPropertyImpl.kt @@ -0,0 +1,63 @@ +package konan.internal + +import kotlin.reflect.KProperty0 +import kotlin.reflect.KProperty1 +import kotlin.reflect.KProperty2 +import kotlin.reflect.KMutableProperty0 +import kotlin.reflect.KMutableProperty1 +import kotlin.reflect.KMutableProperty2 + +@FixmeReflection +open class KProperty0Impl(override val name: String, val getter: () -> R): KProperty0 { + override fun get(): R { + return getter() + } + override fun invoke(): R { + return getter() + } + +} + +@FixmeReflection +open class KProperty1Impl(override val name: String, val getter: (T) -> R): KProperty1 { + override fun get(receiver: T): R { + return getter(receiver) + } + override fun invoke(receiver: T): R { + return getter(receiver) + } +} + +@FixmeReflection +open class KProperty2Impl(override val name: String, val getter: (T1, T2) -> R): KProperty2 { + override fun get(receiver1: T1, receiver2: T2): R { + return getter(receiver1, receiver2) + } + override fun invoke(receiver1: T1, receiver2: T2): R { + return getter(receiver1, receiver2) + } +} + +@FixmeReflection +class KMutableProperty0Impl(name: String, getter: () -> R, val setter: (R) -> Unit) + : KProperty0Impl(name, getter), KMutableProperty0 { + override fun set(value: R): Unit { + setter(value) + } +} + +@FixmeReflection +public 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) + } +} + +@FixmeReflection +public 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) + } +} diff --git a/runtime/src/main/kotlin/kotlin/Function.kt b/runtime/src/main/kotlin/kotlin/Function.kt index 8c46cd9d69d..b640706adc2 100644 --- a/runtime/src/main/kotlin/kotlin/Function.kt +++ b/runtime/src/main/kotlin/kotlin/Function.kt @@ -5,4 +5,5 @@ package kotlin * * @param R return type of the function. */ +@FixmeReflection public interface Function diff --git a/runtime/src/main/kotlin/kotlin/reflect/KProperty.kt b/runtime/src/main/kotlin/kotlin/reflect/KProperty.kt index e4604877c36..97b734a5dfd 100644 --- a/runtime/src/main/kotlin/kotlin/reflect/KProperty.kt +++ b/runtime/src/main/kotlin/kotlin/reflect/KProperty.kt @@ -47,6 +47,46 @@ public interface KProperty : KCallable { // public interface Getter : Accessor, KFunction } +// +@FixmeReflection +public interface KProperty0 : kotlin.reflect.KProperty/* TODO , (T) -> R*/ { +// public abstract val getter: kotlin.reflect.KProperty1.Getter + + public abstract fun get(): R + public abstract operator fun invoke(): R + +// @kotlin.SinceKotlin public abstract fun getDelegate(receiver: T): kotlin.Any? +// +// public interface Getter : kotlin.reflect.KProperty.Getter, (T) -> R { +// } +} + +@FixmeReflection +public interface KProperty1 : kotlin.reflect.KProperty/* TODO , (T) -> R*/ { +// public abstract val getter: kotlin.reflect.KProperty1.Getter + + public abstract fun get(receiver: T): R + public abstract operator fun invoke(receiver: T): R + +// @kotlin.SinceKotlin public abstract fun getDelegate(receiver: T): kotlin.Any? +// +// public interface Getter : kotlin.reflect.KProperty.Getter, (T) -> R { +// } +} + +@FixmeReflection +public interface KProperty2 : kotlin.reflect.KProperty/* TODO , (T) -> R*/ { +// public abstract val getter: kotlin.reflect.KProperty1.Getter + + public abstract fun get(receiver1: T1, receiver2: T2): R + public abstract operator fun invoke(receiver1: T1, receiver2: T2): R + +// @kotlin.SinceKotlin public abstract fun getDelegate(receiver: T): kotlin.Any? +// +// public interface Getter : kotlin.reflect.KProperty.Getter, (T) -> R { +// } +} + /** * Represents a property declared as a `var`. */ @@ -62,6 +102,16 @@ public interface KMutableProperty : KProperty { } @FixmeReflection -public class KPropertyImpl(override val name: String) : KProperty { +public interface KMutableProperty0 : KProperty0, KMutableProperty { + public abstract fun set(value: R) +} +@FixmeReflection +public interface KMutableProperty1 : KProperty1, KMutableProperty { + public abstract fun set(receiver: T, value: R) +} + +@FixmeReflection +public interface KMutableProperty2 : KProperty2, KMutableProperty { + public abstract fun set(receiver1: T1, receiver2: T2, value: R) } \ No newline at end of file