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.TypeAliasConstructorDescriptor
|
||||
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.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
@@ -137,7 +138,8 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
val container = descriptor.containingDeclaration
|
||||
return when (container) {
|
||||
is PackageFragmentDescriptor -> {
|
||||
val packageMemberOwner = internalNameForPackageMemberOwner(descriptor as CallableMemberDescriptor, publicFacade)
|
||||
val packageMemberOwner =
|
||||
internalNameForPackageMemberOwner(descriptor as CallableMemberDescriptor, publicFacade, isIrBackend)
|
||||
Type.getObjectType(packageMemberOwner)
|
||||
}
|
||||
is ClassDescriptor -> mapClass((container as ClassDescriptor?)!!)
|
||||
@@ -1251,7 +1253,11 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
*/
|
||||
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 descriptor = if (callableDescriptor is AccessorForCallableDescriptor<*>) {
|
||||
isAccessor = true
|
||||
@@ -1281,6 +1287,10 @@ class KotlinTypeMapper @JvmOverloads constructor(
|
||||
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
|
||||
if (descriptor.containingDeclaration is IrBuiltinsPackageFragmentDescriptor) {
|
||||
return descriptor.containingDeclaration.name.asString()
|
||||
|
||||
+21
-13
@@ -531,11 +531,12 @@ class DoubleColonExpressionResolver(
|
||||
|
||||
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) {
|
||||
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
|
||||
@@ -608,11 +609,12 @@ class DoubleColonExpressionResolver(
|
||||
internal fun bindPropertyReference(
|
||||
expression: KtCallableReferenceExpression,
|
||||
referenceType: KotlinType,
|
||||
context: ResolutionContext<*>
|
||||
context: ResolutionContext<*>,
|
||||
mutable: Boolean = true
|
||||
) {
|
||||
val localVariable = LocalVariableDescriptor(
|
||||
context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"), referenceType,
|
||||
expression.toSourceElement()
|
||||
mutable, false, expression.toSourceElement()
|
||||
)
|
||||
|
||||
context.trace.record(BindingContext.VARIABLE, expression, localVariable)
|
||||
@@ -777,17 +779,26 @@ class DoubleColonExpressionResolver(
|
||||
}
|
||||
|
||||
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(
|
||||
descriptor: CallableDescriptor,
|
||||
lhs: DoubleColonLHS?,
|
||||
reflectionTypes: ReflectionTypes,
|
||||
scopeOwnerDescriptor: DeclarationDescriptor
|
||||
): KotlinType? {
|
||||
val receiverType =
|
||||
if (descriptor.extensionReceiverParameter != null || descriptor.dispatchReceiverParameter != null)
|
||||
(lhs as? DoubleColonLHS.Type)?.type
|
||||
else null
|
||||
|
||||
val receiverType = receiverTypeFor(descriptor, lhs)
|
||||
return when (descriptor) {
|
||||
is FunctionDescriptor -> {
|
||||
val returnType = descriptor.returnType ?: return null
|
||||
@@ -799,10 +810,7 @@ class DoubleColonExpressionResolver(
|
||||
)
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
val mutable = descriptor.isVar && run {
|
||||
val setter = descriptor.setter
|
||||
setter == null || Visibilities.isVisible(receiverType?.let(::TransientReceiver), setter, scopeOwnerDescriptor)
|
||||
}
|
||||
val mutable = isMutablePropertyReference(descriptor, lhs, scopeOwnerDescriptor)
|
||||
reflectionTypes.getKPropertyType(Annotations.EMPTY, listOfNotNull(receiverType), descriptor.type, mutable)
|
||||
}
|
||||
is VariableDescriptor -> null
|
||||
|
||||
+5
-6
@@ -159,11 +159,6 @@ class ClosureAnnotator(declaration: IrDeclaration) {
|
||||
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) {
|
||||
closuresStack.peek()?.seeVariable(expression.symbol)
|
||||
super.visitVariableAccess(expression)
|
||||
@@ -199,7 +194,11 @@ class ClosureAnnotator(declaration: IrDeclaration) {
|
||||
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) {
|
||||
if (DescriptorUtils.isLocal(declaration.descriptor)) {
|
||||
|
||||
+3
-5
@@ -230,6 +230,9 @@ class LocalDeclarationsLowering(
|
||||
}
|
||||
|
||||
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) {
|
||||
// Replace local class definition with an empty composite.
|
||||
@@ -742,11 +745,6 @@ class LocalDeclarationsLowering(
|
||||
val localClassContext = LocalClassContext(declaration)
|
||||
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 SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS :
|
||||
IrDeclarationOriginImpl("SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS", isSynthetic = true)
|
||||
object GENERATED_PROPERTY_REFERENCE : IrDeclarationOriginImpl("GENERATED_PROPERTY_REFERENCE", isSynthetic = true)
|
||||
}
|
||||
|
||||
interface JvmLoweredStatementOrigin : IrStatementOrigin {
|
||||
|
||||
@@ -66,6 +66,7 @@ internal val jvmPhases = namedIrFilePhase(
|
||||
|
||||
moveCompanionObjectFieldsPhase then
|
||||
constPhase then
|
||||
propertyReferencePhase then
|
||||
propertiesToFieldsPhase then
|
||||
propertiesPhase 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
|
||||
): IrCallableReference =
|
||||
ReflectionReferencesGenerator(statementGenerator).generateCallableReference(
|
||||
ktElement.startOffsetSkippingComments, ktElement.endOffset, type,
|
||||
ktElement, type,
|
||||
referencedDescriptor,
|
||||
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.psi.KtCallableReferenceExpression
|
||||
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.startOffsetSkippingComments
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -62,9 +63,6 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
||||
val descriptorImportedFromObject = resultingDescriptor as? ImportedFromObjectCallableDescriptor<*>
|
||||
val referencedDescriptor = descriptorImportedFromObject?.callableFromObject ?: resultingDescriptor
|
||||
|
||||
val startOffset = ktCallableReference.startOffsetSkippingComments
|
||||
val endOffset = ktCallableReference.endOffset
|
||||
|
||||
return statementGenerator.generateCallReceiver(
|
||||
ktCallableReference,
|
||||
resultingDescriptor,
|
||||
@@ -72,7 +70,7 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
||||
isSafe = false
|
||||
).call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
generateCallableReference(
|
||||
startOffset, endOffset,
|
||||
ktCallableReference,
|
||||
getInferredTypeWithImplicitCastsOrFail(ktCallableReference),
|
||||
referencedDescriptor,
|
||||
resolvedCall.typeArguments
|
||||
@@ -84,27 +82,27 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
||||
}
|
||||
|
||||
fun generateCallableReference(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
ktElement: KtElement,
|
||||
type: KotlinType,
|
||||
callableDescriptor: CallableDescriptor,
|
||||
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
||||
origin: IrStatementOrigin? = null
|
||||
): IrCallableReference =
|
||||
when (callableDescriptor) {
|
||||
is FunctionDescriptor ->
|
||||
generateFunctionReference(
|
||||
startOffset, endOffset, type,
|
||||
context.symbolTable.referenceFunction(callableDescriptor.original),
|
||||
callableDescriptor,
|
||||
typeArguments,
|
||||
origin
|
||||
)
|
||||
is PropertyDescriptor ->
|
||||
generatePropertyReference(startOffset, endOffset, type, callableDescriptor, typeArguments, origin)
|
||||
): IrCallableReference {
|
||||
val startOffset = ktElement.startOffsetSkippingComments
|
||||
val endOffset = ktElement.endOffset
|
||||
return when (callableDescriptor) {
|
||||
is FunctionDescriptor -> {
|
||||
val symbol = context.symbolTable.referenceFunction(callableDescriptor.original)
|
||||
generateFunctionReference(startOffset, endOffset, type, symbol, callableDescriptor, typeArguments, origin)
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
val mutable = get(BindingContext.VARIABLE, ktElement)?.isVar ?: true
|
||||
generatePropertyReference(startOffset, endOffset, type, callableDescriptor, typeArguments, origin, mutable)
|
||||
}
|
||||
else ->
|
||||
throw AssertionError("Unexpected callable reference: $callableDescriptor")
|
||||
}
|
||||
}
|
||||
|
||||
fun generateLocalDelegatedPropertyReference(
|
||||
startOffset: Int,
|
||||
@@ -135,10 +133,11 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St
|
||||
type: KotlinType,
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
||||
origin: IrStatementOrigin?
|
||||
origin: IrStatementOrigin?,
|
||||
mutable: Boolean
|
||||
): IrPropertyReference {
|
||||
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 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)
|
||||
)
|
||||
|
||||
fun IrBuilderWithScope.irGet(type: IrType, receiver: IrExpression, getterSymbol: IrFunctionSymbol): IrCall =
|
||||
fun IrBuilderWithScope.irGet(type: IrType, receiver: IrExpression?, getterSymbol: IrFunctionSymbol): IrCall =
|
||||
IrGetterCallImpl(
|
||||
startOffset, endOffset,
|
||||
type,
|
||||
@@ -210,6 +210,18 @@ fun IrBuilderWithScope.irGet(type: IrType, receiver: IrExpression, getterSymbol:
|
||||
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 =
|
||||
IrCallImpl(startOffset, endOffset, type, callee, callee.descriptor).apply {
|
||||
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)
|
||||
|
||||
val kClass: ClassDescriptor by ClassLookup(1)
|
||||
val kProperty: ClassDescriptor by ClassLookup(1)
|
||||
val kProperty0: ClassDescriptor by ClassLookup(1)
|
||||
val kProperty1: ClassDescriptor by ClassLookup(2)
|
||||
val kProperty2: ClassDescriptor by ClassLookup(3)
|
||||
|
||||
Reference in New Issue
Block a user