From ca5e560f1f436f19349b42bc9b7637e242bacb3b Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 24 Jun 2020 17:56:48 +0300 Subject: [PATCH] [FIR2IR] Introduce lazy constructors --- .../fir/backend/Fir2IrDeclarationStorage.kt | 29 +++- .../kotlin/fir/lazy/Fir2IrLazyClass.kt | 2 +- .../kotlin/fir/lazy/Fir2IrLazyConstructor.kt | 136 ++++++++++++++++++ .../jetbrains/kotlin/ir/util/SymbolTable.kt | 3 + 4 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index d7b43a937ec..b33fabf76fe 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass +import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyConstructor import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.* @@ -820,9 +821,33 @@ class Fir2IrDeclarationStorage( fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol { val firConstructor = firConstructorSymbol.fir getCachedIrConstructor(firConstructor)?.let { return it.symbol } - + val signature = signatureComposer.composeSignature(firConstructor) val irParent = findIrParent(firConstructor) as IrClass - val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED + val parentOrigin = irParent.origin + if (signature != null) { + symbolTable.referenceConstructorIfAny(signature)?.let { irConstructorSymbol -> + val irFunction = irConstructorSymbol.owner + constructorCache[firConstructor] = irFunction + return irConstructorSymbol + } + if (parentOrigin == IrDeclarationOrigin.DEFINED) { + throw AssertionError() + } + val symbol = Fir2IrConstructorSymbol(signature) + val irConstructor = firConstructor.convertWithOffsets { startOffset, endOffset -> + symbolTable.declareConstructor(signature, { symbol }) { + Fir2IrLazyConstructor( + components, startOffset, endOffset, parentOrigin, firConstructor, symbol + ).apply { + parent = irParent + } + } + } + constructorCache[firConstructor] = irConstructor + // NB: this is needed to prevent recursions in case of self bounds + (irConstructor as Fir2IrLazyConstructor).prepareTypeParameters() + return symbol + } val irDeclaration = createIrConstructor(firConstructor, irParent, origin = parentOrigin).apply { setAndModifyParent(irParent) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt index b917b4937d0..1429e678073 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt @@ -123,7 +123,7 @@ class Fir2IrLazyClass( // e.g. to avoid accessing un-enhanced Java declarations with FirJavaTypeRef etc. inside val scope = fir.buildUseSiteMemberScope(session, scopeSession)!! scope.processDeclaredConstructors { - result += declarationStorage.createIrConstructor(it.fir, this) + result += declarationStorage.getIrConstructorSymbol(it).owner } for (declaration in fir.declarations) { when (declaration) { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt new file mode 100644 index 00000000000..e63ddaf77f8 --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt @@ -0,0 +1,136 @@ +/* + * 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.fir.lazy + +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.fir.backend.Fir2IrComponents +import org.jetbrains.kotlin.fir.backend.declareThisReceiverParameter +import org.jetbrains.kotlin.fir.backend.toIrType +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.symbols.Fir2IrConstructorSymbol +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar +import org.jetbrains.kotlin.ir.expressions.IrBody +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.mapOptimized +import org.jetbrains.kotlin.ir.util.parentClassOrNull +import org.jetbrains.kotlin.ir.visitors.IrElementTransformer +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.name.Name + +class Fir2IrLazyConstructor( + components: Fir2IrComponents, + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + fir: FirConstructor, + symbol: Fir2IrConstructorSymbol +) : AbstractFir2IrLazyDeclaration( + components, startOffset, endOffset, origin, fir, symbol +), IrConstructor { + init { + symbol.bind(this) + classifierStorage.preCacheTypeParameters(fir) + } + + override val isPrimary: Boolean + get() = fir.isPrimary + + @ObsoleteDescriptorBasedAPI + override val descriptor: ClassConstructorDescriptor + get() = super.descriptor as ClassConstructorDescriptor + + override val symbol: Fir2IrConstructorSymbol + get() = super.symbol as Fir2IrConstructorSymbol + + override val isInline: Boolean + get() = fir.isInline + + override val isExternal: Boolean + get() = fir.isExternal + + override val isExpect: Boolean + get() = fir.isExpect + + override var body: IrBody? = null + + override val name: Name + get() = Name.special("") + + override var visibility: Visibility + get() = fir.visibility + set(_) { + throw AssertionError("Mutating Fir2Ir lazy elements is not possible") + } + + override var returnType: IrType by lazyVar { + fir.returnTypeRef.toIrType(typeConverter) + } + + override var dispatchReceiverParameter: IrValueParameter? by lazyVar { + val containingClass = parent as? IrClass + val outerClass = containingClass?.parentClassOrNull + if (containingClass?.isInner == true && outerClass != null) { + declarationStorage.enterScope(this) + declareThisReceiverParameter( + symbolTable, + thisType = outerClass.thisReceiver!!.type, + thisOrigin = origin + ).apply { + declarationStorage.leaveScope(this@Fir2IrLazyConstructor) + } + } else null + } + + override var extensionReceiverParameter: IrValueParameter? + get() = null + set(_) { + throw AssertionError("Mutating Fir2Ir lazy elements is not possible") + } + + override var valueParameters: List by lazyVar { + declarationStorage.enterScope(this) + fir.valueParameters.mapIndexed { index, valueParameter -> + declarationStorage.createIrParameter( + valueParameter, index, + useStubForDefaultValueStub = (parent as? IrClass)?.name != Name.identifier("Enum") + ).apply { + this.parent = this@Fir2IrLazyConstructor + } + }.apply { + declarationStorage.leaveScope(this@Fir2IrLazyConstructor) + } + } + + override fun accept(visitor: IrElementVisitor, data: D): R { + return visitor.visitConstructor(this, data) + } + + override fun acceptChildren(visitor: IrElementVisitor, data: D) { + typeParameters.forEach { it.accept(visitor, data) } + + dispatchReceiverParameter?.accept(visitor, data) + extensionReceiverParameter?.accept(visitor, data) + valueParameters.forEach { it.accept(visitor, data) } + + body?.accept(visitor, data) + } + + override fun transformChildren(transformer: IrElementTransformer, data: D) { + typeParameters = typeParameters.mapOptimized { it.transform(transformer, data) } + + dispatchReceiverParameter = dispatchReceiverParameter?.transform(transformer, data) + extensionReceiverParameter = extensionReceiverParameter?.transform(transformer, data) + valueParameters = valueParameters.mapOptimized { it.transform(transformer, data) } + + body = body?.transform(transformer, data) + } +} \ No newline at end of file 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 7a8b0d55a61..122cca0551b 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 @@ -487,6 +487,9 @@ open class SymbolTable( override fun referenceConstructor(descriptor: ClassConstructorDescriptor) = constructorSymbolTable.referenced(descriptor) { createConstructorSymbol(descriptor) } + fun referenceConstructorIfAny(sig: IdSignature): IrConstructorSymbol? = + constructorSymbolTable.get(sig) + fun declareConstructorFromLinker( descriptor: ClassConstructorDescriptor, sig: IdSignature,