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:
Igor Chevdar
2017-03-14 08:43:30 -04:00
committed by GitHub
parent 29726e601f
commit ccbf4bb963
2 changed files with 48 additions and 37 deletions
@@ -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)
@@ -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 {