Implement property references in JVM_IR
This commit is contained in:
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrPropertyDelegateDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||||
@@ -137,7 +138,8 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
|||||||
val container = descriptor.containingDeclaration
|
val container = descriptor.containingDeclaration
|
||||||
return when (container) {
|
return when (container) {
|
||||||
is PackageFragmentDescriptor -> {
|
is PackageFragmentDescriptor -> {
|
||||||
val packageMemberOwner = internalNameForPackageMemberOwner(descriptor as CallableMemberDescriptor, publicFacade)
|
val packageMemberOwner =
|
||||||
|
internalNameForPackageMemberOwner(descriptor as CallableMemberDescriptor, publicFacade, isIrBackend)
|
||||||
Type.getObjectType(packageMemberOwner)
|
Type.getObjectType(packageMemberOwner)
|
||||||
}
|
}
|
||||||
is ClassDescriptor -> mapClass((container as ClassDescriptor?)!!)
|
is ClassDescriptor -> mapClass((container as ClassDescriptor?)!!)
|
||||||
@@ -1251,7 +1253,11 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
|||||||
*/
|
*/
|
||||||
val LANGUAGE_VERSION_SETTINGS_DEFAULT: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
|
val LANGUAGE_VERSION_SETTINGS_DEFAULT: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
|
||||||
|
|
||||||
private fun internalNameForPackageMemberOwner(callableDescriptor: CallableMemberDescriptor, publicFacade: Boolean): String {
|
private fun internalNameForPackageMemberOwner(
|
||||||
|
callableDescriptor: CallableMemberDescriptor,
|
||||||
|
publicFacade: Boolean,
|
||||||
|
isIrBackend: Boolean
|
||||||
|
): String {
|
||||||
val isAccessor: Boolean
|
val isAccessor: Boolean
|
||||||
val descriptor = if (callableDescriptor is AccessorForCallableDescriptor<*>) {
|
val descriptor = if (callableDescriptor is AccessorForCallableDescriptor<*>) {
|
||||||
isAccessor = true
|
isAccessor = true
|
||||||
@@ -1281,6 +1287,10 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
|||||||
if (facadeFqName != null) return facadeFqName
|
if (facadeFqName != null) return facadeFqName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isIrBackend && directMember is IrPropertyDelegateDescriptor) {
|
||||||
|
return internalNameForPackageMemberOwner(directMember.correspondingProperty, publicFacade, isIrBackend)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: drop this usage and move IrBuiltinsPackageFragmentDescriptor to IR modules; it shouldn't be used here
|
// TODO: drop this usage and move IrBuiltinsPackageFragmentDescriptor to IR modules; it shouldn't be used here
|
||||||
if (descriptor.containingDeclaration is IrBuiltinsPackageFragmentDescriptor) {
|
if (descriptor.containingDeclaration is IrBuiltinsPackageFragmentDescriptor) {
|
||||||
return descriptor.containingDeclaration.name.asString()
|
return descriptor.containingDeclaration.name.asString()
|
||||||
|
|||||||
+21
-13
@@ -531,11 +531,12 @@ class DoubleColonExpressionResolver(
|
|||||||
|
|
||||||
checkReferenceIsToAllowedMember(descriptor, context.trace, expression)
|
checkReferenceIsToAllowedMember(descriptor, context.trace, expression)
|
||||||
|
|
||||||
val type = createKCallableTypeForReference(descriptor, lhs, reflectionTypes, context.scope.ownerDescriptor) ?: return null
|
val scope = context.scope.ownerDescriptor
|
||||||
|
val type = createKCallableTypeForReference(descriptor, lhs, reflectionTypes, scope) ?: return null
|
||||||
|
|
||||||
when (descriptor) {
|
when (descriptor) {
|
||||||
is FunctionDescriptor -> bindFunctionReference(expression, type, context, descriptor)
|
is FunctionDescriptor -> bindFunctionReference(expression, type, context, descriptor)
|
||||||
is PropertyDescriptor -> bindPropertyReference(expression, type, context)
|
is PropertyDescriptor -> bindPropertyReference(expression, type, context, isMutablePropertyReference(descriptor, lhs, scope))
|
||||||
}
|
}
|
||||||
|
|
||||||
return type
|
return type
|
||||||
@@ -608,11 +609,12 @@ class DoubleColonExpressionResolver(
|
|||||||
internal fun bindPropertyReference(
|
internal fun bindPropertyReference(
|
||||||
expression: KtCallableReferenceExpression,
|
expression: KtCallableReferenceExpression,
|
||||||
referenceType: KotlinType,
|
referenceType: KotlinType,
|
||||||
context: ResolutionContext<*>
|
context: ResolutionContext<*>,
|
||||||
|
mutable: Boolean = true
|
||||||
) {
|
) {
|
||||||
val localVariable = LocalVariableDescriptor(
|
val localVariable = LocalVariableDescriptor(
|
||||||
context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"), referenceType,
|
context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"), referenceType,
|
||||||
expression.toSourceElement()
|
mutable, false, expression.toSourceElement()
|
||||||
)
|
)
|
||||||
|
|
||||||
context.trace.record(BindingContext.VARIABLE, expression, localVariable)
|
context.trace.record(BindingContext.VARIABLE, expression, localVariable)
|
||||||
@@ -777,17 +779,26 @@ class DoubleColonExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private fun receiverTypeFor(descriptor: CallableDescriptor, lhs: DoubleColonLHS?): KotlinType? =
|
||||||
|
(descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter)?.let { (lhs as? DoubleColonLHS.Type)?.type }
|
||||||
|
|
||||||
|
private fun isMutablePropertyReference(
|
||||||
|
descriptor: PropertyDescriptor,
|
||||||
|
lhs: DoubleColonLHS?,
|
||||||
|
scopeOwnerDescriptor: DeclarationDescriptor
|
||||||
|
): Boolean {
|
||||||
|
val receiver = receiverTypeFor(descriptor, lhs)?.let(::TransientReceiver)
|
||||||
|
val setter = descriptor.setter
|
||||||
|
return descriptor.isVar && (setter == null || Visibilities.isVisible(receiver, setter, scopeOwnerDescriptor))
|
||||||
|
}
|
||||||
|
|
||||||
fun createKCallableTypeForReference(
|
fun createKCallableTypeForReference(
|
||||||
descriptor: CallableDescriptor,
|
descriptor: CallableDescriptor,
|
||||||
lhs: DoubleColonLHS?,
|
lhs: DoubleColonLHS?,
|
||||||
reflectionTypes: ReflectionTypes,
|
reflectionTypes: ReflectionTypes,
|
||||||
scopeOwnerDescriptor: DeclarationDescriptor
|
scopeOwnerDescriptor: DeclarationDescriptor
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val receiverType =
|
val receiverType = receiverTypeFor(descriptor, lhs)
|
||||||
if (descriptor.extensionReceiverParameter != null || descriptor.dispatchReceiverParameter != null)
|
|
||||||
(lhs as? DoubleColonLHS.Type)?.type
|
|
||||||
else null
|
|
||||||
|
|
||||||
return when (descriptor) {
|
return when (descriptor) {
|
||||||
is FunctionDescriptor -> {
|
is FunctionDescriptor -> {
|
||||||
val returnType = descriptor.returnType ?: return null
|
val returnType = descriptor.returnType ?: return null
|
||||||
@@ -799,10 +810,7 @@ class DoubleColonExpressionResolver(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
is PropertyDescriptor -> {
|
is PropertyDescriptor -> {
|
||||||
val mutable = descriptor.isVar && run {
|
val mutable = isMutablePropertyReference(descriptor, lhs, scopeOwnerDescriptor)
|
||||||
val setter = descriptor.setter
|
|
||||||
setter == null || Visibilities.isVisible(receiverType?.let(::TransientReceiver), setter, scopeOwnerDescriptor)
|
|
||||||
}
|
|
||||||
reflectionTypes.getKPropertyType(Annotations.EMPTY, listOfNotNull(receiverType), descriptor.type, mutable)
|
reflectionTypes.getKPropertyType(Annotations.EMPTY, listOfNotNull(receiverType), descriptor.type, mutable)
|
||||||
}
|
}
|
||||||
is VariableDescriptor -> null
|
is VariableDescriptor -> null
|
||||||
|
|||||||
+5
-6
@@ -159,11 +159,6 @@ class ClosureAnnotator(declaration: IrDeclaration) {
|
|||||||
includeInParent(closureBuilder)
|
includeInParent(closureBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) {
|
|
||||||
// Getter and setter of local delegated properties are special generated functions and don't have closure.
|
|
||||||
declaration.delegate.initializer?.acceptVoid(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitVariableAccess(expression: IrValueAccessExpression) {
|
override fun visitVariableAccess(expression: IrValueAccessExpression) {
|
||||||
closuresStack.peek()?.seeVariable(expression.symbol)
|
closuresStack.peek()?.seeVariable(expression.symbol)
|
||||||
super.visitVariableAccess(expression)
|
super.visitVariableAccess(expression)
|
||||||
@@ -199,7 +194,11 @@ class ClosureAnnotator(declaration: IrDeclaration) {
|
|||||||
processMemberAccess(expression.symbol.owner)
|
processMemberAccess(expression.symbol.owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
// override fun visitPropertyReference(expression: IrPropertyReference) = processMemberAccess(expression.)
|
override fun visitPropertyReference(expression: IrPropertyReference) {
|
||||||
|
expression.acceptChildrenVoid(this)
|
||||||
|
expression.getter?.let { processMemberAccess(it.owner) }
|
||||||
|
expression.setter?.let { processMemberAccess(it.owner) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun processMemberAccess(declaration: IrDeclaration) {
|
private fun processMemberAccess(declaration: IrDeclaration) {
|
||||||
if (DescriptorUtils.isLocal(declaration.descriptor)) {
|
if (DescriptorUtils.isLocal(declaration.descriptor)) {
|
||||||
|
|||||||
+3
-5
@@ -230,6 +230,9 @@ class LocalDeclarationsLowering(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
|
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
|
||||||
|
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) =
|
||||||
|
// Both accessors extracted as closures.
|
||||||
|
declaration.delegate.transform(this, null)
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass) = if (declaration in localClasses) {
|
override fun visitClass(declaration: IrClass) = if (declaration in localClasses) {
|
||||||
// Replace local class definition with an empty composite.
|
// Replace local class definition with an empty composite.
|
||||||
@@ -742,11 +745,6 @@ class LocalDeclarationsLowering(
|
|||||||
val localClassContext = LocalClassContext(declaration)
|
val localClassContext = LocalClassContext(declaration)
|
||||||
localClasses[declaration] = localClassContext
|
localClasses[declaration] = localClassContext
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) {
|
|
||||||
// Getter and setter of local delegated properties are special generated functions and don't have closure.
|
|
||||||
declaration.delegate.initializer?.acceptVoid(this)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
|||||||
object JVM_OVERLOADS_WRAPPER : IrDeclarationOriginImpl("JVM_OVERLOADS_WRAPPER")
|
object JVM_OVERLOADS_WRAPPER : IrDeclarationOriginImpl("JVM_OVERLOADS_WRAPPER")
|
||||||
object SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS :
|
object SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS :
|
||||||
IrDeclarationOriginImpl("SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS", isSynthetic = true)
|
IrDeclarationOriginImpl("SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS", isSynthetic = true)
|
||||||
|
object GENERATED_PROPERTY_REFERENCE : IrDeclarationOriginImpl("GENERATED_PROPERTY_REFERENCE", isSynthetic = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface JvmLoweredStatementOrigin : IrStatementOrigin {
|
interface JvmLoweredStatementOrigin : IrStatementOrigin {
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ internal val jvmPhases = namedIrFilePhase(
|
|||||||
|
|
||||||
moveCompanionObjectFieldsPhase then
|
moveCompanionObjectFieldsPhase then
|
||||||
constPhase then
|
constPhase then
|
||||||
|
propertyReferencePhase then
|
||||||
propertiesToFieldsPhase then
|
propertiesToFieldsPhase then
|
||||||
propertiesPhase then
|
propertiesPhase then
|
||||||
renameFieldsPhase then
|
renameFieldsPhase then
|
||||||
|
|||||||
+329
@@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.backend.jvm.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
|
import org.jetbrains.kotlin.ir.types.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
|
internal val propertyReferencePhase = makeIrFilePhase(
|
||||||
|
::PropertyReferenceLowering,
|
||||||
|
name = "PropertyReference",
|
||||||
|
description = "Construct KProperty instances returned by expressions such as A::x and A()::x"
|
||||||
|
)
|
||||||
|
|
||||||
|
internal class PropertyReferenceLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||||
|
// TODO: join IrLocalDelegatedPropertyReference and IrPropertyReference via the class hierarchy?
|
||||||
|
private val IrMemberAccessExpression.getter: IrFunctionSymbol?
|
||||||
|
get() = (this as? IrPropertyReference)?.getter ?: (this as? IrLocalDelegatedPropertyReference)?.getter
|
||||||
|
|
||||||
|
private val IrMemberAccessExpression.setter: IrFunctionSymbol?
|
||||||
|
get() = (this as? IrPropertyReference)?.setter ?: (this as? IrLocalDelegatedPropertyReference)?.setter
|
||||||
|
|
||||||
|
private val IrMemberAccessExpression.field: IrFieldSymbol?
|
||||||
|
get() = (this as? IrPropertyReference)?.field
|
||||||
|
|
||||||
|
private val IrMemberAccessExpression.signature: String
|
||||||
|
// Plain Java fields do not have a getter, but can be referenced nonetheless.
|
||||||
|
get() = getter?.owner?.let { context.state.typeMapper.mapSignatureSkipGeneric(it.descriptor).toString() }
|
||||||
|
?: TODO("plain Java field signature")
|
||||||
|
|
||||||
|
private val IrMemberAccessExpression.symbol: IrSymbol
|
||||||
|
get() = getter?.owner?.symbol ?: field!!.owner.symbol
|
||||||
|
|
||||||
|
private val plainJavaClass =
|
||||||
|
context.getIrClass(FqName("java.lang.Class")).owner
|
||||||
|
|
||||||
|
private val reflectionClass =
|
||||||
|
context.getIrClass(FqName("kotlin.jvm.internal.Reflection")).owner
|
||||||
|
|
||||||
|
private val getOrCreateKotlinClass =
|
||||||
|
reflectionClass.functions.single { it.name.asString() == "getOrCreateKotlinClass" && it.valueParameters.size == 1 }
|
||||||
|
|
||||||
|
private val getOrCreateKotlinPackage =
|
||||||
|
reflectionClass.functions.single { it.name.asString() == "getOrCreateKotlinPackage" && it.valueParameters.size == 2 }
|
||||||
|
|
||||||
|
private val arrayItemGetter =
|
||||||
|
context.ir.symbols.array.owner.functions.single { it.name.asString() == "get" }
|
||||||
|
|
||||||
|
private val kPropertyType =
|
||||||
|
context.getIrClass(FqName("kotlin.reflect.KProperty")).owner.defaultType
|
||||||
|
|
||||||
|
private val kPropertiesFieldType =
|
||||||
|
context.ir.symbols.array.createType(false, listOf(makeTypeProjection(kPropertyType, Variance.OUT_VARIANCE)))
|
||||||
|
|
||||||
|
// TODO: remove code duplication with CallableReferenceLowering
|
||||||
|
private val IrMemberAccessExpression.parentJavaClassReference
|
||||||
|
get() = IrClassReferenceImpl(
|
||||||
|
startOffset, endOffset,
|
||||||
|
plainJavaClass.defaultType,
|
||||||
|
plainJavaClass.symbol,
|
||||||
|
CrIrType(context.state.typeMapper.mapImplementationOwner(descriptor))
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun IrBuilderWithScope.buildReflectedContainerReference(expression: IrMemberAccessExpression): IrExpression {
|
||||||
|
val parent = expression.getter?.owner?.parent ?: expression.field?.owner?.parent
|
||||||
|
return when (parent) {
|
||||||
|
is IrPackageFragment -> irCall(getOrCreateKotlinPackage).apply {
|
||||||
|
putValueArgument(0, expression.parentJavaClassReference)
|
||||||
|
putValueArgument(1, irString(this@PropertyReferenceLowering.context.state.moduleName))
|
||||||
|
}
|
||||||
|
is IrClass -> irCall(getOrCreateKotlinClass).apply {
|
||||||
|
putValueArgument(0, expression.parentJavaClassReference)
|
||||||
|
}
|
||||||
|
else -> irNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PropertyReferenceKind(
|
||||||
|
val interfaceSymbol: IrClassSymbol,
|
||||||
|
val reflectedSymbol: IrClassSymbol,
|
||||||
|
val wrapper: IrFunction
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun propertyReferenceKind(mutable: Boolean, i: Int) = PropertyReferenceKind(
|
||||||
|
context.getIrClass(FqName("kotlin.jvm.internal.${if (mutable) "Mutable" else ""}PropertyReference$i")),
|
||||||
|
context.getIrClass(FqName("kotlin.jvm.internal.${if (mutable) "Mutable" else ""}PropertyReference${i}Impl")),
|
||||||
|
reflectionClass.functions.single { it.name.asString() == (if (mutable) "mutableProperty$i" else "property$i") }
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun propertyReferenceKindFor(expression: IrMemberAccessExpression): PropertyReferenceKind =
|
||||||
|
expression.getter?.owner?.let {
|
||||||
|
val boundReceivers = listOfNotNull(expression.dispatchReceiver, expression.extensionReceiver).size
|
||||||
|
val needReceivers = listOfNotNull(it.dispatchReceiverParameter, it.extensionReceiverParameter).size
|
||||||
|
// PropertyReference1 will swap the receivers if bound with the extension one, and PropertyReference0
|
||||||
|
// has no way to bind two receivers at once.
|
||||||
|
if (boundReceivers == 2 || (expression.extensionReceiver != null && needReceivers == 2))
|
||||||
|
TODO("property reference with 2 receivers")
|
||||||
|
propertyReferenceKind(expression.setter != null, needReceivers - boundReceivers)
|
||||||
|
} ?: expression.field?.owner?.let {
|
||||||
|
propertyReferenceKind(!it.isFinal, if (it.isStatic || expression.dispatchReceiver != null) 0 else 1)
|
||||||
|
} ?: throw AssertionError("property has no getter and no field: ${expression.dump()}")
|
||||||
|
|
||||||
|
private data class PropertyCacheKey(val symbol: IrSymbol, val reflected: Boolean)
|
||||||
|
private data class PropertyClassCacheKey(val symbol: IrSymbol, val boundReceiver: Boolean)
|
||||||
|
private data class PropertyInstance(val initializer: IrExpression, val index: Int)
|
||||||
|
|
||||||
|
override fun lower(irClass: IrClass) {
|
||||||
|
val kProperties = mutableMapOf<PropertyCacheKey, PropertyInstance>()
|
||||||
|
val kPropertyClasses = mutableMapOf<PropertyClassCacheKey, IrClass>()
|
||||||
|
val kPropertiesField = buildField {
|
||||||
|
name = Name.identifier(JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME)
|
||||||
|
type = kPropertiesFieldType
|
||||||
|
origin = JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
|
||||||
|
isFinal = true
|
||||||
|
isStatic = true
|
||||||
|
}
|
||||||
|
|
||||||
|
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||||
|
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression =
|
||||||
|
cachedKProperty(expression)
|
||||||
|
|
||||||
|
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression =
|
||||||
|
cachedKProperty(expression)
|
||||||
|
|
||||||
|
private fun cachedKProperty(expression: IrMemberAccessExpression): IrExpression {
|
||||||
|
// Reflected implementation does not support partial application; also, cannot cache instances with arguments.
|
||||||
|
if (expression.dispatchReceiver != null || expression.extensionReceiver != null)
|
||||||
|
return createSpecializedKProperty(expression)
|
||||||
|
|
||||||
|
// For delegated properties, the getter and setter contain a reference each as the second argument to getValue
|
||||||
|
// and setValue. Since it's highly unlikely that anyone will call get/set on these, optimize for space.
|
||||||
|
val useReflectedImpl = expression.origin == IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE
|
||||||
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
|
||||||
|
val (_, index) = kProperties.getOrPut(PropertyCacheKey(expression.symbol, useReflectedImpl)) {
|
||||||
|
val kProperty = if (useReflectedImpl)
|
||||||
|
createReflectedKProperty(expression)
|
||||||
|
else
|
||||||
|
createSpecializedKProperty(expression)
|
||||||
|
PropertyInstance(kProperty, kProperties.size)
|
||||||
|
}
|
||||||
|
irCall(arrayItemGetter).apply {
|
||||||
|
dispatchReceiver = irGetField(null, kPropertiesField)
|
||||||
|
putValueArgument(0, irInt(index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an instance of KProperty that uses Java reflection to locate the getter and the setter. This kind of reference
|
||||||
|
// does not support local variables or bound receivers (e.g. `Class()::field`) and is slower, but takes up less space.
|
||||||
|
private fun createReflectedKProperty(expression: IrMemberAccessExpression): IrExpression {
|
||||||
|
val referenceKind = propertyReferenceKindFor(expression)
|
||||||
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
|
||||||
|
irCall(referenceKind.wrapper).apply {
|
||||||
|
putValueArgument(0, irCall(referenceKind.reflectedSymbol.constructors.single()).apply {
|
||||||
|
putValueArgument(0, buildReflectedContainerReference(expression))
|
||||||
|
putValueArgument(1, irString(expression.descriptor.name.asString()))
|
||||||
|
putValueArgument(2, irString(expression.signature))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an instance of KProperty that overrides the get() and set() method to directly call getX() and setX() on the object.
|
||||||
|
// This is (relatively) fast, but space-inefficient. Also, the instances can store bound receivers in their fields.
|
||||||
|
private fun createSpecializedKProperty(expression: IrMemberAccessExpression): IrExpression {
|
||||||
|
val bound = expression.dispatchReceiver != null || expression.extensionReceiver != null
|
||||||
|
val referenceClass = kPropertyClasses.getOrPut(PropertyClassCacheKey(expression.symbol, bound)) {
|
||||||
|
createKPropertySubclass(expression)
|
||||||
|
}
|
||||||
|
return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset).run {
|
||||||
|
irCall(referenceClass.constructors.single()).apply {
|
||||||
|
var index = 0
|
||||||
|
expression.dispatchReceiver?.let { putValueArgument(index++, it) }
|
||||||
|
expression.extensionReceiver?.let { putValueArgument(index++, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createKPropertySubclass(expression: IrMemberAccessExpression): IrClass {
|
||||||
|
val superClass = propertyReferenceKindFor(expression).interfaceSymbol.owner
|
||||||
|
val referenceClass = buildClass {
|
||||||
|
setSourceRange(expression)
|
||||||
|
name = Name.identifier("${expression.descriptor.name}\$${kPropertyClasses.size}")
|
||||||
|
origin = JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE
|
||||||
|
}.apply {
|
||||||
|
parent = irClass
|
||||||
|
superTypes += IrSimpleTypeImpl(superClass.symbol, false, listOf(), listOf())
|
||||||
|
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||||
|
}
|
||||||
|
val referenceThis = referenceClass.thisReceiver!!
|
||||||
|
|
||||||
|
buildConstructor {
|
||||||
|
setSourceRange(expression)
|
||||||
|
returnType = referenceClass.defaultType
|
||||||
|
origin = referenceClass.origin
|
||||||
|
isPrimary = true
|
||||||
|
}.apply {
|
||||||
|
parent = referenceClass
|
||||||
|
referenceClass.declarations.add(this)
|
||||||
|
|
||||||
|
val constructor = this
|
||||||
|
// See propertyReferenceKindFor -- only one of them could ever be present.
|
||||||
|
val parameter = (expression.dispatchReceiver ?: expression.extensionReceiver)?.let {
|
||||||
|
buildValueParameter {
|
||||||
|
setSourceRange(expression)
|
||||||
|
name = Name.identifier("receiver")
|
||||||
|
type = it.type
|
||||||
|
index = valueParameters.size
|
||||||
|
origin = referenceClass.origin
|
||||||
|
}.apply {
|
||||||
|
parent = constructor
|
||||||
|
valueParameters.add(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
||||||
|
val superArgs = if (parameter == null) 0 else 1
|
||||||
|
+irDelegatingConstructorCall(superClass.constructors.single { it.valueParameters.size == superArgs }).apply {
|
||||||
|
parameter?.let { putValueArgument(0, irGet(parameter)) }
|
||||||
|
}
|
||||||
|
+IrInstanceInitializerCallImpl(startOffset, endOffset, referenceClass.symbol, context.irBuiltIns.unitType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun buildOverride(method: IrSimpleFunction, build: IrBlockBodyBuilder.(List<IrValueParameter>) -> IrExpression) =
|
||||||
|
buildFun {
|
||||||
|
setSourceRange(expression)
|
||||||
|
name = if (method.name.asString() == "<get-name>") Name.identifier("getName") else method.name
|
||||||
|
returnType = method.returnType
|
||||||
|
visibility = method.visibility
|
||||||
|
origin = referenceClass.origin
|
||||||
|
}.apply {
|
||||||
|
parent = referenceClass
|
||||||
|
referenceClass.declarations.add(this)
|
||||||
|
|
||||||
|
overriddenSymbols.add(method.symbol)
|
||||||
|
dispatchReceiverParameter = referenceThis.copyTo(this)
|
||||||
|
for (parameter in method.valueParameters)
|
||||||
|
valueParameters.add(parameter.copyTo(this))
|
||||||
|
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
||||||
|
+irReturn(build(valueParameters))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
|
||||||
|
fun IrBuilderWithScope.setReceiversOn(call: IrCall, valueParameters: List<IrValueParameter>) {
|
||||||
|
var index = 0
|
||||||
|
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
|
||||||
|
if (expression.dispatchReceiver != null)
|
||||||
|
irGetField(irGet(referenceThis), receiverField)
|
||||||
|
else
|
||||||
|
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
||||||
|
}
|
||||||
|
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
|
||||||
|
if (expression.extensionReceiver != null)
|
||||||
|
irGetField(irGet(referenceThis), receiverField)
|
||||||
|
else
|
||||||
|
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildOverride(superClass.properties.single { it.name.asString() == "name" }.getter!!) {
|
||||||
|
irString(expression.descriptor.name.asString())
|
||||||
|
}
|
||||||
|
|
||||||
|
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) {
|
||||||
|
buildReflectedContainerReference(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) {
|
||||||
|
irString(expression.signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.getter?.owner?.let { getter ->
|
||||||
|
buildOverride(superClass.functions.single { it.name.asString() == "get" }) { valueParameters ->
|
||||||
|
irGet(getter.returnType, null, getter.symbol).apply { setReceiversOn(this, valueParameters) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.setter?.owner?.let { setter ->
|
||||||
|
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { valueParameters ->
|
||||||
|
val value = irGet(valueParameters.last())
|
||||||
|
irSet(setter.returnType, null, setter.symbol, value).apply { setReceiversOn(this, valueParameters) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.field?.owner?.let {
|
||||||
|
TODO("plain Java property reference") // no accessors, should generate direct field read/write instead
|
||||||
|
}
|
||||||
|
return referenceClass
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Put new field at the beginning so that static delegated properties with initializers work correctly.
|
||||||
|
if (kProperties.isNotEmpty()) {
|
||||||
|
irClass.declarations.add(0, kPropertiesField.apply {
|
||||||
|
parent = irClass
|
||||||
|
initializer = context.createIrBuilder(irClass.symbol).run {
|
||||||
|
val initializers = kProperties.values.sortedBy { it.index }.map { it.initializer }
|
||||||
|
irExprBody(irCall(this@PropertyReferenceLowering.context.ir.symbols.arrayOf).apply {
|
||||||
|
putValueArgument(0, IrVarargImpl(startOffset, endOffset, kPropertiesFieldType, kPropertyType, initializers))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
irClass.declarations.addAll(0, kPropertyClasses.values)
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -191,7 +191,7 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D
|
|||||||
statementGenerator: StatementGenerator
|
statementGenerator: StatementGenerator
|
||||||
): IrCallableReference =
|
): IrCallableReference =
|
||||||
ReflectionReferencesGenerator(statementGenerator).generateCallableReference(
|
ReflectionReferencesGenerator(statementGenerator).generateCallableReference(
|
||||||
ktElement.startOffsetSkippingComments, ktElement.endOffset, type,
|
ktElement, type,
|
||||||
referencedDescriptor,
|
referencedDescriptor,
|
||||||
null, IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE
|
null, IrStatementOrigin.PROPERTY_REFERENCE_FOR_DELEGATE
|
||||||
)
|
)
|
||||||
|
|||||||
+19
-20
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.util.referenceClassifier
|
|||||||
import org.jetbrains.kotlin.ir.util.referenceFunction
|
import org.jetbrains.kotlin.ir.util.referenceFunction
|
||||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -62,9 +63,6 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
|||||||
val descriptorImportedFromObject = resultingDescriptor as? ImportedFromObjectCallableDescriptor<*>
|
val descriptorImportedFromObject = resultingDescriptor as? ImportedFromObjectCallableDescriptor<*>
|
||||||
val referencedDescriptor = descriptorImportedFromObject?.callableFromObject ?: resultingDescriptor
|
val referencedDescriptor = descriptorImportedFromObject?.callableFromObject ?: resultingDescriptor
|
||||||
|
|
||||||
val startOffset = ktCallableReference.startOffsetSkippingComments
|
|
||||||
val endOffset = ktCallableReference.endOffset
|
|
||||||
|
|
||||||
return statementGenerator.generateCallReceiver(
|
return statementGenerator.generateCallReceiver(
|
||||||
ktCallableReference,
|
ktCallableReference,
|
||||||
resultingDescriptor,
|
resultingDescriptor,
|
||||||
@@ -72,7 +70,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
|||||||
isSafe = false
|
isSafe = false
|
||||||
).call { dispatchReceiverValue, extensionReceiverValue ->
|
).call { dispatchReceiverValue, extensionReceiverValue ->
|
||||||
generateCallableReference(
|
generateCallableReference(
|
||||||
startOffset, endOffset,
|
ktCallableReference,
|
||||||
getInferredTypeWithImplicitCastsOrFail(ktCallableReference),
|
getInferredTypeWithImplicitCastsOrFail(ktCallableReference),
|
||||||
referencedDescriptor,
|
referencedDescriptor,
|
||||||
resolvedCall.typeArguments
|
resolvedCall.typeArguments
|
||||||
@@ -84,27 +82,27 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun generateCallableReference(
|
fun generateCallableReference(
|
||||||
startOffset: Int,
|
ktElement: KtElement,
|
||||||
endOffset: Int,
|
|
||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
callableDescriptor: CallableDescriptor,
|
callableDescriptor: CallableDescriptor,
|
||||||
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
||||||
origin: IrStatementOrigin? = null
|
origin: IrStatementOrigin? = null
|
||||||
): IrCallableReference =
|
): IrCallableReference {
|
||||||
when (callableDescriptor) {
|
val startOffset = ktElement.startOffsetSkippingComments
|
||||||
is FunctionDescriptor ->
|
val endOffset = ktElement.endOffset
|
||||||
generateFunctionReference(
|
return when (callableDescriptor) {
|
||||||
startOffset, endOffset, type,
|
is FunctionDescriptor -> {
|
||||||
context.symbolTable.referenceFunction(callableDescriptor.original),
|
val symbol = context.symbolTable.referenceFunction(callableDescriptor.original)
|
||||||
callableDescriptor,
|
generateFunctionReference(startOffset, endOffset, type, symbol, callableDescriptor, typeArguments, origin)
|
||||||
typeArguments,
|
}
|
||||||
origin
|
is PropertyDescriptor -> {
|
||||||
)
|
val mutable = get(BindingContext.VARIABLE, ktElement)?.isVar ?: true
|
||||||
is PropertyDescriptor ->
|
generatePropertyReference(startOffset, endOffset, type, callableDescriptor, typeArguments, origin, mutable)
|
||||||
generatePropertyReference(startOffset, endOffset, type, callableDescriptor, typeArguments, origin)
|
}
|
||||||
else ->
|
else ->
|
||||||
throw AssertionError("Unexpected callable reference: $callableDescriptor")
|
throw AssertionError("Unexpected callable reference: $callableDescriptor")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun generateLocalDelegatedPropertyReference(
|
fun generateLocalDelegatedPropertyReference(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
@@ -135,10 +133,11 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
|||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
propertyDescriptor: PropertyDescriptor,
|
propertyDescriptor: PropertyDescriptor,
|
||||||
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
||||||
origin: IrStatementOrigin?
|
origin: IrStatementOrigin?,
|
||||||
|
mutable: Boolean
|
||||||
): IrPropertyReference {
|
): IrPropertyReference {
|
||||||
val getterDescriptor = propertyDescriptor.getter
|
val getterDescriptor = propertyDescriptor.getter
|
||||||
val setterDescriptor = propertyDescriptor.setter
|
val setterDescriptor = if (mutable) propertyDescriptor.setter else null
|
||||||
|
|
||||||
val fieldSymbol = if (getterDescriptor == null) context.symbolTable.referenceField(propertyDescriptor) else null
|
val fieldSymbol = if (getterDescriptor == null) context.symbolTable.referenceField(propertyDescriptor) else null
|
||||||
val getterSymbol = getterDescriptor?.let { context.symbolTable.referenceSimpleFunction(it.original) }
|
val getterSymbol = getterDescriptor?.let { context.symbolTable.referenceSimpleFunction(it.original) }
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ fun IrBuilderWithScope.irNotEquals(arg1: IrExpression, arg2: IrExpression) =
|
|||||||
irEquals(arg1, arg2, origin = IrStatementOrigin.EXCLEQ)
|
irEquals(arg1, arg2, origin = IrStatementOrigin.EXCLEQ)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun IrBuilderWithScope.irGet(type: IrType, receiver: IrExpression, getterSymbol: IrFunctionSymbol): IrCall =
|
fun IrBuilderWithScope.irGet(type: IrType, receiver: IrExpression?, getterSymbol: IrFunctionSymbol): IrCall =
|
||||||
IrGetterCallImpl(
|
IrGetterCallImpl(
|
||||||
startOffset, endOffset,
|
startOffset, endOffset,
|
||||||
type,
|
type,
|
||||||
@@ -210,6 +210,18 @@ fun IrBuilderWithScope.irGet(type: IrType, receiver: IrExpression, getterSymbol:
|
|||||||
origin = IrStatementOrigin.GET_PROPERTY
|
origin = IrStatementOrigin.GET_PROPERTY
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun IrBuilderWithScope.irSet(type: IrType, receiver: IrExpression?, getterSymbol: IrFunctionSymbol, value: IrExpression): IrCall =
|
||||||
|
IrSetterCallImpl(
|
||||||
|
startOffset, endOffset,
|
||||||
|
type,
|
||||||
|
getterSymbol, getterSymbol.descriptor,
|
||||||
|
typeArgumentsCount = 0,
|
||||||
|
dispatchReceiver = receiver,
|
||||||
|
extensionReceiver = null,
|
||||||
|
argument = value,
|
||||||
|
origin = IrStatementOrigin.EQ
|
||||||
|
)
|
||||||
|
|
||||||
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol, type: IrType, typeArguments: List<IrType> = emptyList()): IrCall =
|
fun IrBuilderWithScope.irCall(callee: IrFunctionSymbol, type: IrType, typeArguments: List<IrType> = emptyList()): IrCall =
|
||||||
IrCallImpl(startOffset, endOffset, type, callee, callee.descriptor).apply {
|
IrCallImpl(startOffset, endOffset, type, callee, callee.descriptor).apply {
|
||||||
typeArguments.forEachIndexed { index, irType ->
|
typeArguments.forEachIndexed { index, irType ->
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class ReflectionTypes(module: ModuleDescriptor, private val notFoundClasses: Not
|
|||||||
fun getKSuspendFunction(n: Int): ClassDescriptor = find("$K_SUSPEND_FUNCTION_PREFIX$n", n + 1)
|
fun getKSuspendFunction(n: Int): ClassDescriptor = find("$K_SUSPEND_FUNCTION_PREFIX$n", n + 1)
|
||||||
|
|
||||||
val kClass: ClassDescriptor by ClassLookup(1)
|
val kClass: ClassDescriptor by ClassLookup(1)
|
||||||
|
val kProperty: ClassDescriptor by ClassLookup(1)
|
||||||
val kProperty0: ClassDescriptor by ClassLookup(1)
|
val kProperty0: ClassDescriptor by ClassLookup(1)
|
||||||
val kProperty1: ClassDescriptor by ClassLookup(2)
|
val kProperty1: ClassDescriptor by ClassLookup(2)
|
||||||
val kProperty2: ClassDescriptor by ClassLookup(3)
|
val kProperty2: ClassDescriptor by ClassLookup(3)
|
||||||
|
|||||||
Reference in New Issue
Block a user