Directly search in IrClass for declarations to fill bodies with plugin

because some other compiler plugins (Compose) copy/rewrite IR declarations
completely, and in the end, functions that are present in the final IR tree
do not have bodies.

Correctly create IrProperty and IrField when they were absent from the
descriptors (in case for private serializer properties)

Do not use symbol table because 'declare' API is not available in plugins.

Fixes https://github.com/JetBrains/compose-jb/issues/46
This commit is contained in:
Leonid Startsev
2020-11-16 23:08:14 +03:00
parent 5efefabb93
commit b1c355e7eb
5 changed files with 56 additions and 70 deletions
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.ir.util
@@ -8,6 +8,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
@@ -69,12 +70,13 @@ abstract class SerializerCodegen(
serializerDescriptor::checkSerializableClassPropertyResult
) { true }
val localSerializersFieldsDescriptors: List<PropertyDescriptor> = findLocalSerializersFieldDescriptors()
lateinit var localSerializersFieldsDescriptors: List<Pair<PropertyDescriptor, IrProperty>>
protected set
// Can be false if user specified inheritance from KSerializer explicitly
protected val isGeneratedSerializer = serializerDescriptor.typeConstructor.supertypes.any(::isGeneratedKSerializer)
private fun findLocalSerializersFieldDescriptors(): List<PropertyDescriptor> {
protected fun findLocalSerializersFieldDescriptors(): List<PropertyDescriptor> {
val count = serializableDescriptor.declaredTypeParameters.size
if (count == 0) return emptyList()
val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" }
@@ -15,8 +15,7 @@ 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.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
@@ -42,10 +41,12 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
interface IrBuilderExtension {
val compilerContext: SerializationPluginContext
private inline fun <reified T : IrDeclaration> IrClass.searchForDeclaration(descriptor: DeclarationDescriptor): T? {
return declarations.singleOrNull { it.descriptor == descriptor } as? T
}
fun IrClass.contributeFunction(descriptor: FunctionDescriptor, bodyGen: IrBlockBodyBuilder.(IrFunction) -> Unit) {
val functionSymbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
assert(functionSymbol.isBound)
val f: IrSimpleFunction = functionSymbol.owner
val f: IrSimpleFunction = searchForDeclaration(descriptor) ?: compilerContext.symbolTable.referenceSimpleFunction(descriptor).owner
// TODO: default parameters
f.body = DeclarationIrBuilder(compilerContext, f.symbol, this.startOffset, this.endOffset).irBlockBody(
this.startOffset,
@@ -59,11 +60,7 @@ interface IrBuilderExtension {
overwriteValueParameters: Boolean = false,
bodyGen: IrBlockBodyBuilder.(IrConstructor) -> Unit
) {
val ctorSymbol = compilerContext.symbolTable.referenceConstructor(descriptor)
assert(ctorSymbol.isBound)
val c = ctorSymbol.owner
val c: IrConstructor = searchForDeclaration(descriptor) ?: compilerContext.symbolTable.referenceConstructor(descriptor).owner
c.body = DeclarationIrBuilder(compilerContext, c.symbol, this.startOffset, this.endOffset).irBlockBody(
this.startOffset,
this.endOffset
@@ -94,7 +91,7 @@ interface IrBuilderExtension {
irInvoke(
dispatchReceiver,
callee,
*valueArguments.toTypedArray(),
args = valueArguments.toTypedArray(),
typeHint = returnTypeHint
).also { call -> typeArguments.forEachIndexed(call::putTypeArgument) }
@@ -226,16 +223,12 @@ interface IrBuilderExtension {
fun generateSimplePropertyWithBackingField(
propertyDescriptor: PropertyDescriptor,
propertyParent: IrClass,
declare: Boolean,
fieldName: Name = propertyDescriptor.name,
): IrProperty {
val irPropertySymbol = compilerContext.symbolTable.referenceProperty(propertyDescriptor)
assert(irPropertySymbol.isBound || declare)
if (!irPropertySymbol.isBound) {
val irProperty = propertyParent.searchForDeclaration<IrProperty>(propertyDescriptor) ?: run {
with(propertyDescriptor) {
propertyParent.factory.createProperty(
propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, irPropertySymbol,
propertyParent.startOffset, propertyParent.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrPropertySymbolImpl(propertyDescriptor),
name, visibility, modality, isVar, isConst, isLateInit, isDelegated, isExternal
).also {
it.parent = propertyParent
@@ -243,50 +236,54 @@ interface IrBuilderExtension {
}
}
}
val irProperty = irPropertySymbol.owner
irProperty.backingField = generatePropertyBackingField(propertyDescriptor, irProperty, fieldName).apply {
parent = propertyParent
correspondingPropertySymbol = irPropertySymbol
}
propertyParent.generatePropertyBackingFieldIfNeeded(propertyDescriptor, irProperty, fieldName)
val fieldSymbol = irProperty.backingField!!.symbol
irProperty.getter = propertyDescriptor.getter?.let { generatePropertyAccessor(irProperty, it, fieldSymbol, declare) }
?.apply { parent = propertyParent }
irProperty.setter = propertyDescriptor.setter?.let { generatePropertyAccessor(irProperty, it, fieldSymbol, declare) }
?.apply { parent = propertyParent }
irProperty.getter = propertyDescriptor.getter?.let {
propertyParent.generatePropertyAccessor(propertyDescriptor, irProperty, it, fieldSymbol, isGetter = true)
}?.apply { parent = propertyParent }
irProperty.setter = propertyDescriptor.setter?.let {
propertyParent.generatePropertyAccessor(propertyDescriptor, irProperty, it, fieldSymbol, isGetter = false)
}?.apply { parent = propertyParent }
return irProperty
}
private fun generatePropertyBackingField(
descriptor: PropertyDescriptor,
private fun IrClass.generatePropertyBackingFieldIfNeeded(
propertyDescriptor: PropertyDescriptor,
originProperty: IrProperty,
name: Name,
): IrField {
val fieldSymbol = compilerContext.symbolTable.referenceField(descriptor)
if (fieldSymbol.isBound) return fieldSymbol.owner
) {
if (originProperty.backingField != null) return
return with(descriptor) {
val field = with(propertyDescriptor) {
// TODO: type parameters
originProperty.factory.createField(
originProperty.startOffset, originProperty.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, fieldSymbol, name, type.toIrType(),
originProperty.startOffset, originProperty.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrFieldSymbolImpl(propertyDescriptor), name, type.toIrType(),
visibility, !isVar, isEffectivelyExternal(), dispatchReceiverParameter == null
)
}
field.apply {
parent = this@generatePropertyBackingFieldIfNeeded
correspondingPropertySymbol = originProperty.symbol
}
originProperty.backingField = field
}
private fun generatePropertyAccessor(
private fun IrClass.generatePropertyAccessor(
propertyDescriptor: PropertyDescriptor,
property: IrProperty,
descriptor: PropertyAccessorDescriptor,
fieldSymbol: IrFieldSymbol,
declare: Boolean
isGetter: Boolean,
): IrSimpleFunction {
val symbol = compilerContext.symbolTable.referenceSimpleFunction(descriptor)
assert(symbol.isBound || declare)
if (!symbol.isBound) {
val irAccessor: IrSimpleFunction = when (isGetter) {
true -> searchForDeclaration<IrProperty>(propertyDescriptor)?.getter
false -> searchForDeclaration<IrProperty>(propertyDescriptor)?.setter
} ?: run {
with(descriptor) {
property.factory.createFunction(
fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, symbol,
fieldSymbol.owner.startOffset, fieldSymbol.owner.endOffset, SERIALIZABLE_PLUGIN_ORIGIN, IrSimpleFunctionSymbolImpl(descriptor),
name, visibility, modality, returnType!!.toIrType(),
isInline, isExternal, isTailrec, isSuspend, isOperator, isInfix, isExpect
)
@@ -298,11 +295,9 @@ interface IrBuilderExtension {
}
}
val irAccessor = symbol.owner
irAccessor.body = when (descriptor) {
is PropertyGetterDescriptor -> generateDefaultGetterBody(descriptor, irAccessor)
is PropertySetterDescriptor -> generateDefaultSetterBody(descriptor, irAccessor)
else -> throw AssertionError("Should be getter or setter: $descriptor")
irAccessor.body = when (isGetter) {
true -> generateDefaultGetterBody(descriptor as PropertyGetterDescriptor, irAccessor)
false -> generateDefaultSetterBody(descriptor as PropertySetterDescriptor, irAccessor)
}
return irAccessor
@@ -557,8 +552,8 @@ interface IrBuilderExtension {
kType,
genericIndex
) { it, _ ->
val prop = enclosingGenerator.localSerializersFieldsDescriptors[it]
irGetField(irGet(dispatchReceiverParameter), compilerContext.symbolTable.referenceField(prop).owner)
val (prop, ir) = enclosingGenerator.localSerializersFieldsDescriptors[it]
irGetField(irGet(dispatchReceiverParameter), ir.backingField!!)
}
fun IrBuilderWithScope.serializerInstance(
@@ -65,7 +65,7 @@ class SerialInfoImplJvmIrGenerator(
ctor.body = ctorBody
for (property in properties) {
generateSimplePropertyWithBackingField(property.descriptor, irClass, true, Name.identifier("_" + property.name.asString()))
generateSimplePropertyWithBackingField(property.descriptor, irClass, Name.identifier("_" + property.name.asString()))
val getter = property.getter!!
getter.origin = SERIALIZABLE_SYNTHETIC_ORIGIN
@@ -65,11 +65,11 @@ open class SerializerIrGenerator(
// how to (auto)create backing field and getter/setter?
compilerContext.symbolTable.withReferenceScope(irClass.descriptor) {
prop = generateSimplePropertyWithBackingField(desc, irClass, false)
prop = generateSimplePropertyWithBackingField(desc, irClass)
// TODO: Do not use descriptors here
localSerializersFieldsDescriptors.forEach {
generateSimplePropertyWithBackingField(it, irClass, true)
localSerializersFieldsDescriptors = findLocalSerializersFieldDescriptors().map { it ->
it to generateSimplePropertyWithBackingField(it, irClass)
}
}
@@ -195,11 +195,11 @@ open class SerializerIrGenerator(
// store type arguments serializers in fields
val thisAsReceiverParameter = irClass.thisReceiver!!
ctor.valueParameters.forEachIndexed { index, param ->
val localSerial = compilerContext.symbolTable.referenceField(localSerializersFieldsDescriptors[index])
val localSerial = localSerializersFieldsDescriptors[index].second.backingField!!
+irSetField(generateReceiverExpressionForFieldAccess(
thisAsReceiverParameter.symbol,
localSerializersFieldsDescriptors[index]
), localSerial.owner, irGet(param))
localSerializersFieldsDescriptors[index].first
), localSerial, irGet(param))
}
@@ -221,7 +221,7 @@ open class SerializerIrGenerator(
val typeParams = serializableDescriptor.declaredTypeParameters.mapIndexed { idx, _ ->
irGetField(
irGet(irFun.dispatchReceiverParameter!!),
compilerContext.symbolTable.referenceField(localSerializersFieldsDescriptors[idx]).owner
localSerializersFieldsDescriptors[idx].second.backingField!!
)
}
val kSerType = ((irFun.returnType as IrSimpleType).arguments.first() as IrTypeProjection).type