[FIR2IR] Introduce lazy constructors

This commit is contained in:
Mikhail Glukhikh
2020-06-24 17:56:48 +03:00
parent fcabd02fe8
commit ca5e560f1f
4 changed files with 167 additions and 3 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass 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.lazy.Fir2IrLazySimpleFunction
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
@@ -820,9 +821,33 @@ class Fir2IrDeclarationStorage(
fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol { fun getIrConstructorSymbol(firConstructorSymbol: FirConstructorSymbol): IrConstructorSymbol {
val firConstructor = firConstructorSymbol.fir val firConstructor = firConstructorSymbol.fir
getCachedIrConstructor(firConstructor)?.let { return it.symbol } getCachedIrConstructor(firConstructor)?.let { return it.symbol }
val signature = signatureComposer.composeSignature(firConstructor)
val irParent = findIrParent(firConstructor) as IrClass 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 { val irDeclaration = createIrConstructor(firConstructor, irParent, origin = parentOrigin).apply {
setAndModifyParent(irParent) setAndModifyParent(irParent)
} }
@@ -123,7 +123,7 @@ class Fir2IrLazyClass(
// e.g. to avoid accessing un-enhanced Java declarations with FirJavaTypeRef etc. inside // e.g. to avoid accessing un-enhanced Java declarations with FirJavaTypeRef etc. inside
val scope = fir.buildUseSiteMemberScope(session, scopeSession)!! val scope = fir.buildUseSiteMemberScope(session, scopeSession)!!
scope.processDeclaredConstructors { scope.processDeclaredConstructors {
result += declarationStorage.createIrConstructor(it.fir, this) result += declarationStorage.getIrConstructorSymbol(it).owner
} }
for (declaration in fir.declarations) { for (declaration in fir.declarations) {
when (declaration) { when (declaration) {
@@ -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<FirConstructor, IrConstructor>(
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("<init>")
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<IrValueParameter> 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 <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitConstructor(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, 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 <D> transformChildren(transformer: IrElementTransformer<D>, 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)
}
}
@@ -487,6 +487,9 @@ open class SymbolTable(
override fun referenceConstructor(descriptor: ClassConstructorDescriptor) = override fun referenceConstructor(descriptor: ClassConstructorDescriptor) =
constructorSymbolTable.referenced(descriptor) { createConstructorSymbol(descriptor) } constructorSymbolTable.referenced(descriptor) { createConstructorSymbol(descriptor) }
fun referenceConstructorIfAny(sig: IdSignature): IrConstructorSymbol? =
constructorSymbolTable.get(sig)
fun declareConstructorFromLinker( fun declareConstructorFromLinker(
descriptor: ClassConstructorDescriptor, descriptor: ClassConstructorDescriptor,
sig: IdSignature, sig: IdSignature,