Fixed type of callable reference to property with private setter

The actual type of callable reference is presented in IR, take it
from there.
This commit is contained in:
Igor Chevdar
2017-03-21 18:47:54 +03:00
parent e133e3379b
commit dc5edfeda3
2 changed files with 24 additions and 19 deletions
@@ -167,6 +167,7 @@ class ReflectionTypes(module: ModuleDescriptor) {
val kProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope) val kProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope) val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope) val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
val kMutableProperty2: 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 kProperty2Impl: ClassDescriptor by ClassLookup(konanInternalScope)
@@ -28,15 +28,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass { internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
private val genericKProperty0ImplType = context.reflectionTypes.kProperty0Impl val reflectionTypes = context.reflectionTypes
private val genericKLocalDelegatedPropertyImplType = context.reflectionTypes.kLocalDelegatedPropertyImpl
private val genericKProperty1ImplType = context.reflectionTypes.kProperty1Impl
private val genericKProperty2ImplType = context.reflectionTypes.kProperty2Impl
private val genericKMutableProperty0ImplType = context.reflectionTypes.kMutableProperty0Impl
private val genericKMutableProperty1ImplType = context.reflectionTypes.kMutableProperty1Impl
private val genericKMutableProperty2ImplType = context.reflectionTypes.kMutableProperty2Impl
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
@@ -48,22 +40,22 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
if (isLocal) { if (isLocal) {
assert(receiverTypes.isEmpty(), { "Local delegated property cannot have explicit receiver" }) assert(receiverTypes.isEmpty(), { "Local delegated property cannot have explicit receiver" })
when { when {
isMutable -> genericKLocalDelegatedMutablePropertyImplType isMutable -> reflectionTypes.kLocalDelegatedMutablePropertyImpl
else -> genericKLocalDelegatedPropertyImplType else -> reflectionTypes.kLocalDelegatedPropertyImpl
} }
} else { } else {
when (receiverTypes.size) { when (receiverTypes.size) {
0 -> when { 0 -> when {
isMutable -> genericKMutableProperty0ImplType isMutable -> reflectionTypes.kMutableProperty0Impl
else -> genericKProperty0ImplType else -> reflectionTypes.kProperty0Impl
} }
1 -> when { 1 -> when {
isMutable -> genericKMutableProperty1ImplType isMutable -> reflectionTypes.kMutableProperty1Impl
else -> genericKProperty1ImplType else -> reflectionTypes.kProperty1Impl
} }
2 -> when { 2 -> when {
isMutable -> genericKMutableProperty2ImplType isMutable -> reflectionTypes.kMutableProperty2Impl
else -> genericKProperty2ImplType else -> reflectionTypes.kProperty2Impl
} }
else -> throw AssertionError("More than 2 receivers is not allowed") else -> throw AssertionError("More than 2 receivers is not allowed")
} }
@@ -85,7 +77,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
val arrayItemGetter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"), val arrayItemGetter = genericArrayType.unsubstitutedMemberScope.getContributedFunctions(Name.identifier("get"),
NoLookupLocation.FROM_BACKEND).single() NoLookupLocation.FROM_BACKEND).single()
val typeParameterT = genericArrayType.declaredTypeParameters[0] val typeParameterT = genericArrayType.declaredTypeParameters[0]
val kPropertyImplType = genericKProperty1ImplType.replace(context.builtIns.anyType, context.builtIns.anyType) val kPropertyImplType = reflectionTypes.kProperty1Impl.replace(context.builtIns.anyType, context.builtIns.anyType)
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(kPropertyImplType))) val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(kPropertyImplType)))
val substitutedArrayItemGetter = arrayItemGetter.substitute(typeSubstitutor)!! val substitutedArrayItemGetter = arrayItemGetter.substitute(typeSubstitutor)!!
@@ -178,7 +170,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
} }
val setterCallableReference = propertyDescriptor.setter.let { val setterCallableReference = propertyDescriptor.setter.let {
if (it == null || isLocal) null if (it == null || isLocal || !isKMutablePropertyType(expression.type)) null
else { else {
val setterKFunctionType = context.reflectionTypes.getKFunctionType( val setterKFunctionType = context.reflectionTypes.getKFunctionType(
annotations = Annotations.EMPTY, annotations = Annotations.EMPTY,
@@ -208,6 +200,18 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
return initializer return initializer
} }
private fun isKMutablePropertyType(type: KotlinType): Boolean {
val arguments = type.arguments
val expectedClassDescriptor = when (arguments.size) {
0 -> return false
1 -> reflectionTypes.kMutableProperty0
2 -> reflectionTypes.kMutableProperty1
3 -> reflectionTypes.kMutableProperty2
else -> throw AssertionError("More than 2 receivers is not allowed")
}
return type == expectedClassDescriptor.defaultType.replace(arguments)
}
private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION : private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION :
IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION") IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION")