Cut references to local delegated properties.
References to local delegated properties are cut - it is forbidden to call get() or set() on them.
This commit is contained in:
+4
-2
@@ -163,12 +163,14 @@ class ReflectionTypes(module: ModuleDescriptor) {
|
|||||||
val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
val kProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
val kProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||||
val kProperty2: 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 kProperty0Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
val kProperty1Impl: ClassDescriptor by ClassLookup(konanInternalScope)
|
val kProperty1Impl: 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 kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(konanInternalScope)
|
||||||
|
|
||||||
fun getKFunctionType(
|
fun getKFunctionType(
|
||||||
annotations: Annotations,
|
annotations: Annotations,
|
||||||
|
|||||||
+52
-30
@@ -29,25 +29,33 @@ 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
|
private val genericKProperty0ImplType = context.reflectionTypes.kProperty0Impl
|
||||||
|
private val genericKLocalDelegatedPropertyImplType = context.reflectionTypes.kLocalDelegatedPropertyImpl
|
||||||
private val genericKProperty1ImplType = context.reflectionTypes.kProperty1Impl
|
private val genericKProperty1ImplType = context.reflectionTypes.kProperty1Impl
|
||||||
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 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, isMutable: Boolean): ClassConstructorDescriptor {
|
private fun getKPropertyImplConstructorDescriptor(returnType: KotlinType, isLocal: Boolean, isMutable: Boolean): ClassConstructorDescriptor {
|
||||||
val genericKPropertyImplType = if (isMutable) genericKMutableProperty0ImplType else genericKProperty0ImplType
|
val genericKPropertyImplType =
|
||||||
|
if (isMutable) {
|
||||||
|
if (isLocal) genericKLocalDelegatedMutablePropertyImplType else genericKMutableProperty0ImplType
|
||||||
|
} else {
|
||||||
|
if (isLocal) genericKLocalDelegatedPropertyImplType else genericKProperty0ImplType
|
||||||
|
}
|
||||||
val typeParameterR = genericKPropertyImplType.declaredTypeParameters[0]
|
val typeParameterR = genericKPropertyImplType.declaredTypeParameters[0]
|
||||||
val typeSubstitutor = TypeSubstitutor.create(mapOf(
|
val typeSubstitutor = TypeSubstitutor.create(mapOf(
|
||||||
typeParameterR.typeConstructor to TypeProjectionImpl(returnType)))
|
typeParameterR.typeConstructor to TypeProjectionImpl(returnType)))
|
||||||
return genericKPropertyImplType.unsubstitutedPrimaryConstructor!!.substitute(typeSubstitutor)!!
|
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 {
|
: ClassConstructorDescriptor {
|
||||||
if (receiverType == null)
|
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 genericKPropertyImplType = if (isMutable) genericKMutableProperty1ImplType else genericKProperty1ImplType
|
||||||
val typeParameterT = genericKPropertyImplType.declaredTypeParameters[0]
|
val typeParameterT = genericKPropertyImplType.declaredTypeParameters[0]
|
||||||
val typeParameterR = genericKPropertyImplType.declaredTypeParameters[1]
|
val typeParameterR = genericKPropertyImplType.declaredTypeParameters[1]
|
||||||
@@ -99,9 +107,11 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
|||||||
val propertyDescriptor = expression.descriptor as? VariableDescriptorWithAccessors
|
val propertyDescriptor = expression.descriptor as? VariableDescriptorWithAccessors
|
||||||
if (propertyDescriptor == null) return expression
|
if (propertyDescriptor == null) return expression
|
||||||
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
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)
|
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) {
|
val field = kProperties.getOrPut(propertyDescriptor) {
|
||||||
createKProperty(expression, propertyDescriptor) to kProperties.size
|
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))
|
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 {
|
private fun createKProperty(expression: IrCallableReference, propertyDescriptor: VariableDescriptorWithAccessors): IrCallImpl {
|
||||||
val getter = propertyDescriptor.getter!!
|
|
||||||
val receiverTypes = mutableListOf<KotlinType>()
|
|
||||||
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 startOffset = expression.startOffset
|
||||||
val endOffset = expression.endOffset
|
val endOffset = expression.endOffset
|
||||||
val getterKFunctionType = context.reflectionTypes.getKFunctionType(
|
var receiverType: KotlinType? = null
|
||||||
annotations = Annotations.EMPTY,
|
val isLocal = propertyDescriptor !is PropertyDescriptor
|
||||||
receiverType = receiverType,
|
|
||||||
parameterTypes = listOf(),
|
val getterCallableReference = propertyDescriptor.getter.let {
|
||||||
returnType = propertyDescriptor.type)
|
if (it == null || isLocal) null
|
||||||
val getterCallableReference = IrCallableReferenceImpl(startOffset, endOffset, getterKFunctionType, getter, null).apply {
|
else {
|
||||||
dispatchReceiver = expression.dispatchReceiver
|
val getter = propertyDescriptor.getter!!
|
||||||
extensionReceiver = expression.extensionReceiver
|
val receiverTypes = mutableListOf<KotlinType>()
|
||||||
|
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 {
|
val setterCallableReference = propertyDescriptor.setter.let {
|
||||||
if (it == null) null
|
if (it == null || isLocal) null
|
||||||
else {
|
else {
|
||||||
val setterKFunctionType = context.reflectionTypes.getKFunctionType(
|
val setterKFunctionType = context.reflectionTypes.getKFunctionType(
|
||||||
annotations = Annotations.EMPTY,
|
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 {
|
val initializer = IrCallImpl(startOffset, endOffset, descriptor).apply {
|
||||||
putValueArgument(0, IrConstImpl<String>(startOffset, endOffset,
|
putValueArgument(0, IrConstImpl<String>(startOffset, endOffset,
|
||||||
context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString()))
|
context.builtIns.stringType, IrConstKind.String, propertyDescriptor.name.asString()))
|
||||||
putValueArgument(1, getterCallableReference)
|
if (getterCallableReference != null)
|
||||||
|
putValueArgument(1, getterCallableReference)
|
||||||
if (setterCallableReference != null)
|
if (setterCallableReference != null)
|
||||||
putValueArgument(2, setterCallableReference)
|
putValueArgument(2, setterCallableReference)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import kotlin.reflect.KProperty2
|
|||||||
import kotlin.reflect.KMutableProperty0
|
import kotlin.reflect.KMutableProperty0
|
||||||
import kotlin.reflect.KMutableProperty1
|
import kotlin.reflect.KMutableProperty1
|
||||||
import kotlin.reflect.KMutableProperty2
|
import kotlin.reflect.KMutableProperty2
|
||||||
|
import kotlin.UnsupportedOperationException
|
||||||
|
|
||||||
@FixmeReflection
|
@FixmeReflection
|
||||||
open class KProperty0Impl<out R>(override val name: String, val getter: () -> R): KProperty0<R> {
|
open class KProperty0Impl<out R>(override val name: String, val getter: () -> R): KProperty0<R> {
|
||||||
@@ -47,7 +48,7 @@ class KMutableProperty0Impl<R>(name: String, getter: () -> R, val setter: (R) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
@FixmeReflection
|
@FixmeReflection
|
||||||
public class KMutableProperty1Impl<T, R>(name: String, getter: (T) -> R, val setter: (T, R) -> Unit)
|
class KMutableProperty1Impl<T, R>(name: String, getter: (T) -> R, val setter: (T, R) -> Unit)
|
||||||
: KProperty1Impl<T, R>(name, getter), KMutableProperty1<T, R> {
|
: KProperty1Impl<T, R>(name, getter), KMutableProperty1<T, R> {
|
||||||
override fun set(receiver: T, value: R): Unit {
|
override fun set(receiver: T, value: R): Unit {
|
||||||
setter(receiver, value)
|
setter(receiver, value)
|
||||||
@@ -55,9 +56,24 @@ public class KMutableProperty1Impl<T, R>(name: String, getter: (T) -> R, val set
|
|||||||
}
|
}
|
||||||
|
|
||||||
@FixmeReflection
|
@FixmeReflection
|
||||||
public class KMutableProperty2Impl<T1, T2, R>(name: String, getter: (T1, T2) -> R, val setter: (T1, T2, R) -> Unit)
|
class KMutableProperty2Impl<T1, T2, R>(name: String, getter: (T1, T2) -> R, val setter: (T1, T2, R) -> Unit)
|
||||||
: KProperty2Impl<T1, T2, R>(name, getter), KMutableProperty2<T1, T2, R> {
|
: KProperty2Impl<T1, T2, R>(name, getter), KMutableProperty2<T1, T2, R> {
|
||||||
override fun set(receiver1: T1, receiver2: T2, value: R): Unit {
|
override fun set(receiver1: T1, receiver2: T2, value: R): Unit {
|
||||||
setter(receiver1, receiver2, value)
|
setter(receiver1, receiver2, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open class KLocalDelegatedPropertyImpl<out R>(override val name: String): KProperty0<R> {
|
||||||
|
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<R>(name: String): KLocalDelegatedPropertyImpl<R>(name), KMutableProperty0<R> {
|
||||||
|
override fun set(value: R): Unit {
|
||||||
|
throw UnsupportedOperationException("Not supported for local property reference.")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user