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