Supported KProperty2 and KMutableProperty2 (#340)
Consider this code:
object Delegate {
operator fun getValue(t: Any?, p: KProperty<*>): String {
return ""
}
}
class A {
val String.ext by Delegate
}
then the type of <p> is KProperty2 (it has 2 receivers).
This commit is contained in:
+2
@@ -168,8 +168,10 @@ class ReflectionTypes(module: ModuleDescriptor) {
|
|||||||
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
val kProperty0Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
val kProperty0Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
val kProperty1Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
val kProperty1Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
|
val kProperty2Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
val kMutableProperty0Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
val kMutableProperty0Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
val kMutableProperty1Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
val kMutableProperty1Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
|
val kMutableProperty2Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope)
|
val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope)
|
val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
|
|
||||||
|
|||||||
+46
-37
@@ -31,38 +31,48 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
private val genericKProperty0ImplType = context.reflectionTypes.kProperty0Impl
|
private val genericKProperty0ImplType = context.reflectionTypes.kProperty0Impl
|
||||||
private val genericKLocalDelegatedPropertyImplType = context.reflectionTypes.kLocalDelegatedPropertyImpl
|
private val genericKLocalDelegatedPropertyImplType = context.reflectionTypes.kLocalDelegatedPropertyImpl
|
||||||
private val genericKProperty1ImplType = context.reflectionTypes.kProperty1Impl
|
private val genericKProperty1ImplType = context.reflectionTypes.kProperty1Impl
|
||||||
|
private val genericKProperty2ImplType = context.reflectionTypes.kProperty2Impl
|
||||||
private val genericKMutableProperty0ImplType = context.reflectionTypes.kMutableProperty0Impl
|
private val genericKMutableProperty0ImplType = context.reflectionTypes.kMutableProperty0Impl
|
||||||
private val genericKMutableProperty1ImplType = context.reflectionTypes.kMutableProperty1Impl
|
private val genericKMutableProperty1ImplType = context.reflectionTypes.kMutableProperty1Impl
|
||||||
|
private val genericKMutableProperty2ImplType = context.reflectionTypes.kMutableProperty2Impl
|
||||||
private val genericKLocalDelegatedMutablePropertyImplType = context.reflectionTypes.kLocalDelegatedMutablePropertyImpl
|
private val genericKLocalDelegatedMutablePropertyImplType = context.reflectionTypes.kLocalDelegatedMutablePropertyImpl
|
||||||
|
|
||||||
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
|
private val kotlinPackage = context.irModule!!.descriptor.getPackage(FqName("kotlin"))
|
||||||
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
private val genericArrayType = kotlinPackage.memberScope.getContributedClassifier(Name.identifier("Array"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||||
|
|
||||||
private fun getKPropertyImplConstructorDescriptor(returnType: KotlinType, isLocal: Boolean, isMutable: Boolean): ClassConstructorDescriptor {
|
private fun getKPropertyImplConstructorDescriptor(receiverTypes: List<KotlinType>,
|
||||||
val genericKPropertyImplType =
|
returnType: KotlinType,
|
||||||
if (isMutable) {
|
isLocal: Boolean,
|
||||||
if (isLocal) genericKLocalDelegatedMutablePropertyImplType else genericKMutableProperty0ImplType
|
isMutable: Boolean) : ClassConstructorDescriptor {
|
||||||
|
val classDescriptor =
|
||||||
|
if (isLocal) {
|
||||||
|
assert(receiverTypes.isEmpty(), { "Local delegated property cannot have explicit receiver" })
|
||||||
|
when {
|
||||||
|
isMutable -> genericKLocalDelegatedMutablePropertyImplType
|
||||||
|
else -> genericKLocalDelegatedPropertyImplType
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isLocal) genericKLocalDelegatedPropertyImplType else genericKProperty0ImplType
|
when (receiverTypes.size) {
|
||||||
|
0 -> when {
|
||||||
|
isMutable -> genericKMutableProperty0ImplType
|
||||||
|
else -> genericKProperty0ImplType
|
||||||
|
}
|
||||||
|
1 -> when {
|
||||||
|
isMutable -> genericKMutableProperty1ImplType
|
||||||
|
else -> genericKProperty1ImplType
|
||||||
|
}
|
||||||
|
2 -> when {
|
||||||
|
isMutable -> genericKMutableProperty2ImplType
|
||||||
|
else -> genericKProperty2ImplType
|
||||||
|
}
|
||||||
|
else -> throw AssertionError("More than 2 receivers is not allowed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val typeParameterR = genericKPropertyImplType.declaredTypeParameters[0]
|
val typeParameters = classDescriptor.declaredTypeParameters
|
||||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(
|
val arguments = (receiverTypes + listOf(returnType))
|
||||||
typeParameterR.typeConstructor to TypeProjectionImpl(returnType)))
|
.mapIndexed { index, type -> typeParameters[index].typeConstructor to TypeProjectionImpl(type) }
|
||||||
return genericKPropertyImplType.unsubstitutedPrimaryConstructor!!.substitute(typeSubstitutor)!!
|
.toMap()
|
||||||
}
|
return classDescriptor.unsubstitutedPrimaryConstructor!!.substitute(TypeSubstitutor.create(arguments))!!
|
||||||
|
|
||||||
private fun getKPropertyImplConstructorDescriptor(receiverType: KotlinType?, returnType: KotlinType, isLocal: Boolean, isMutable: Boolean)
|
|
||||||
: ClassConstructorDescriptor {
|
|
||||||
if (receiverType == null)
|
|
||||||
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]
|
|
||||||
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 {
|
private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType {
|
||||||
@@ -139,28 +149,27 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
private fun createKProperty(expression: IrCallableReference, propertyDescriptor: VariableDescriptorWithAccessors): IrCallImpl {
|
private fun createKProperty(expression: IrCallableReference, propertyDescriptor: VariableDescriptorWithAccessors): IrCallImpl {
|
||||||
val startOffset = expression.startOffset
|
val startOffset = expression.startOffset
|
||||||
val endOffset = expression.endOffset
|
val endOffset = expression.endOffset
|
||||||
var receiverType: KotlinType? = null
|
val receiverTypes = mutableListOf<KotlinType>()
|
||||||
val isLocal = propertyDescriptor !is PropertyDescriptor
|
val isLocal = propertyDescriptor !is PropertyDescriptor
|
||||||
|
|
||||||
|
val returnType = propertyDescriptor.type
|
||||||
val getterCallableReference = propertyDescriptor.getter.let {
|
val getterCallableReference = propertyDescriptor.getter.let {
|
||||||
if (it == null || isLocal) null
|
if (it == null || isLocal) null
|
||||||
else {
|
else {
|
||||||
val getter = propertyDescriptor.getter!!
|
val getter = propertyDescriptor.getter!!
|
||||||
val receiverTypes = mutableListOf<KotlinType>()
|
|
||||||
getter.dispatchReceiverParameter.let {
|
|
||||||
if (it != null && expression.dispatchReceiver == null)
|
|
||||||
receiverTypes.add(it.type)
|
|
||||||
}
|
|
||||||
getter.extensionReceiverParameter.let {
|
getter.extensionReceiverParameter.let {
|
||||||
if (it != null && expression.extensionReceiver == null)
|
if (it != null && expression.extensionReceiver == null)
|
||||||
receiverTypes.add(it.type)
|
receiverTypes.add(it.type)
|
||||||
}
|
}
|
||||||
receiverType = receiverTypes.singleOrNull()
|
getter.dispatchReceiverParameter.let {
|
||||||
|
if (it != null && expression.dispatchReceiver == null)
|
||||||
|
receiverTypes.add(it.type)
|
||||||
|
}
|
||||||
val getterKFunctionType = context.reflectionTypes.getKFunctionType(
|
val getterKFunctionType = context.reflectionTypes.getKFunctionType(
|
||||||
annotations = Annotations.EMPTY,
|
annotations = Annotations.EMPTY,
|
||||||
receiverType = receiverType,
|
receiverType = receiverTypes.firstOrNull(),
|
||||||
parameterTypes = listOf(),
|
parameterTypes = if (receiverTypes.size < 2) listOf() else listOf(receiverTypes[1]),
|
||||||
returnType = propertyDescriptor.type)
|
returnType = returnType)
|
||||||
IrCallableReferenceImpl(startOffset, endOffset, getterKFunctionType, getter, null).apply {
|
IrCallableReferenceImpl(startOffset, endOffset, getterKFunctionType, getter, null).apply {
|
||||||
dispatchReceiver = expression.dispatchReceiver
|
dispatchReceiver = expression.dispatchReceiver
|
||||||
extensionReceiver = expression.extensionReceiver
|
extensionReceiver = expression.extensionReceiver
|
||||||
@@ -173,8 +182,8 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
else {
|
else {
|
||||||
val setterKFunctionType = context.reflectionTypes.getKFunctionType(
|
val setterKFunctionType = context.reflectionTypes.getKFunctionType(
|
||||||
annotations = Annotations.EMPTY,
|
annotations = Annotations.EMPTY,
|
||||||
receiverType = receiverType,
|
receiverType = receiverTypes.firstOrNull(),
|
||||||
parameterTypes = listOf(propertyDescriptor.type),
|
parameterTypes = if (receiverTypes.size < 2) listOf(returnType) else listOf(receiverTypes[1], returnType),
|
||||||
returnType = context.builtIns.unitType)
|
returnType = context.builtIns.unitType)
|
||||||
IrCallableReferenceImpl(startOffset, endOffset, setterKFunctionType, it, null).apply {
|
IrCallableReferenceImpl(startOffset, endOffset, setterKFunctionType, it, null).apply {
|
||||||
dispatchReceiver = expression.dispatchReceiver
|
dispatchReceiver = expression.dispatchReceiver
|
||||||
@@ -184,8 +193,8 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
val descriptor = getKPropertyImplConstructorDescriptor(
|
val descriptor = getKPropertyImplConstructorDescriptor(
|
||||||
receiverType = receiverType,
|
receiverTypes = receiverTypes,
|
||||||
returnType = propertyDescriptor.type,
|
returnType = returnType,
|
||||||
isLocal = isLocal,
|
isLocal = isLocal,
|
||||||
isMutable = setterCallableReference != null)
|
isMutable = setterCallableReference != null)
|
||||||
val initializer = IrCallImpl(startOffset, endOffset, descriptor).apply {
|
val initializer = IrCallImpl(startOffset, endOffset, descriptor).apply {
|
||||||
|
|||||||
Reference in New Issue
Block a user