Implement property references in JVM_IR

This commit is contained in:
pyos
2019-03-08 14:59:54 +01:00
committed by max-kammerer
parent 43be01bbc8
commit 330c4648cb
11 changed files with 406 additions and 48 deletions
@@ -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()
@@ -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
@@ -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)) {
@@ -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
@@ -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)
}
}
@@ -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
)
@@ -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)