From b1c355e7eb9731037a8d76718eaca56d1212ecdd Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Mon, 16 Nov 2020 23:08:14 +0300 Subject: [PATCH] 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 --- .../jetbrains/kotlin/ir/util/SymbolTable.kt | 15 +--- .../backend/common/SerializerCodegen.kt | 6 +- .../compiler/backend/ir/GeneratorHelpers.kt | 89 +++++++++---------- .../ir/SerialInfoImplJvmIrGenerator.kt | 2 +- .../backend/ir/SerializerIrGenerator.kt | 14 +-- 5 files changed, 56 insertions(+), 70 deletions(-) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index 510a5b7d7bb..3210fcee44e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -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 diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt index 53ba437fb65..573d30f213c 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt @@ -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 = findLocalSerializersFieldDescriptors() + lateinit var localSerializersFieldsDescriptors: List> + protected set // Can be false if user specified inheritance from KSerializer explicitly protected val isGeneratedSerializer = serializerDescriptor.typeConstructor.supertypes.any(::isGeneratedKSerializer) - private fun findLocalSerializersFieldDescriptors(): List { + protected fun findLocalSerializersFieldDescriptors(): List { val count = serializableDescriptor.declaredTypeParameters.size if (count == 0) return emptyList() val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt index d4c9f558c5d..da69145f543 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/GeneratorHelpers.kt @@ -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 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(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(propertyDescriptor)?.getter + false -> searchForDeclaration(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( diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt index a6261998af8..980291dd50d 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt @@ -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 diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt index dcbf0f23398..66041a9022e 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerIrGenerator.kt @@ -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