[FIR2IR] Introduce lazy properties

This commit is contained in:
Mikhail Glukhikh
2020-06-26 12:40:06 +03:00
parent efd614194b
commit 2d5e6bb90b
3 changed files with 195 additions and 6 deletions
@@ -22,6 +22,7 @@ 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.Fir2IrLazyProperty
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.*
@@ -494,7 +495,7 @@ class Fir2IrDeclarationStorage(
return symbolTable.declareSimpleFunction(signature, { Fir2IrSimpleFunctionSymbol(signature, containerSource) }, factory)
}
private fun createIrPropertyAccessor(
internal fun createIrPropertyAccessor(
propertyAccessor: FirPropertyAccessor?,
property: FirProperty,
correspondingProperty: IrProperty,
@@ -560,7 +561,7 @@ class Fir2IrDeclarationStorage(
}
}
private fun IrProperty.createBackingField(
internal fun IrProperty.createBackingField(
property: FirProperty,
origin: IrDeclarationOrigin,
descriptor: PropertyDescriptor,
@@ -589,7 +590,7 @@ class Fir2IrDeclarationStorage(
}
}
private val FirProperty.fieldVisibility: Visibility
internal val FirProperty.fieldVisibility: Visibility
get() = when {
isLateInit -> setter?.visibility ?: status.visibility
isConst -> status.visibility
@@ -908,14 +909,35 @@ class Fir2IrDeclarationStorage(
propertyCache[fir]?.let { return it.symbol }
val signature = signatureComposer.composeSignature(fir)
val irParent = findIrParent(fir)
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
if (signature != null) {
symbolTable.referencePropertyIfAny(signature)?.let { irPropertySymbol ->
val irProperty = irPropertySymbol.owner
propertyCache[fir] = irProperty
return irPropertySymbol
}
// TODO: package fragment members (?)
if (irParent is Fir2IrLazyClass) {
if (parentOrigin == IrDeclarationOrigin.DEFINED) {
throw AssertionError()
}
val symbol = Fir2IrPropertySymbol(signature, fir.containerSource)
val irProperty = fir.convertWithOffsets { startOffset, endOffset ->
symbolTable.declareProperty(signature, { symbol }) {
val isFakeOverride =
firVariableSymbol is FirPropertySymbol && firVariableSymbol.isFakeOverride &&
firVariableSymbol.callableId != firVariableSymbol.overriddenSymbol?.callableId
Fir2IrLazyProperty(
components, startOffset, endOffset, parentOrigin, fir, symbol, isFakeOverride
).apply {
parent = irParent
}
}
}
propertyCache[fir] = irProperty
return symbol
}
}
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
createIrProperty(fir, irParent, origin = parentOrigin).apply {
setAndModifyParent(irParent)
}.symbol
@@ -145,8 +145,7 @@ class Fir2IrLazyClass(
processedNames += declaration.name
scope.processPropertiesByName(declaration.name) {
if (it is FirPropertySymbol) {
// TODO: replace with getIrFieldOrPropertySymbol(it).owner with lazy property generation
result += declarationStorage.createIrProperty(it.fir, irParent = this, origin = origin)
result += declarationStorage.getIrPropertyOrFieldSymbol(it).owner as IrProperty
}
}
}
@@ -0,0 +1,168 @@
/*
* 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.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.toIrConst
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.symbols.Fir2IrPropertySymbol
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.types.IrErrorType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
class Fir2IrLazyProperty(
components: Fir2IrComponents,
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
fir: FirProperty,
symbol: Fir2IrPropertySymbol,
override val isFakeOverride: Boolean
) : AbstractFir2IrLazyDeclaration<FirProperty, IrProperty>(
components, startOffset, endOffset, origin, fir, symbol
), IrProperty {
init {
symbol.bind(this)
classifierStorage.preCacheTypeParameters(fir)
typeParameters = emptyList()
}
@ObsoleteDescriptorBasedAPI
override val descriptor: PropertyDescriptor
get() = super.descriptor as PropertyDescriptor
override val symbol: Fir2IrPropertySymbol
get() = super.symbol as Fir2IrPropertySymbol
override val isVar: Boolean
get() = fir.isVar
override val isConst: Boolean
get() = fir.isConst
override val isLateinit: Boolean
get() = fir.isLateInit
override val isDelegated: Boolean
get() = fir.delegate != null
override val isExternal: Boolean
get() = fir.isExternal
override val isExpect: Boolean
get() = fir.isExpect
override val name: Name
get() = fir.name
override var visibility: Visibility
get() = fir.visibility
set(_) {
throw AssertionError("Mutating Fir2Ir lazy elements is not possible")
}
override val modality: Modality
get() = fir.modality!!
private val type: IrType by lazy {
with(typeConverter) { fir.returnTypeRef.toIrType() }
}
@OptIn(ObsoleteDescriptorBasedAPI::class)
override var backingField: IrField? by lazyVar {
// TODO: this checks are very preliminary, FIR resolve should determine backing field presence itself
val parent = parent
when {
!fir.isConst && (fir.modality == Modality.ABSTRACT || parent is IrClass && parent.isInterface) -> {
null
}
fir.initializer != null || fir.getter is FirDefaultPropertyGetter || fir.isVar && fir.setter is FirDefaultPropertySetter -> {
with(declarationStorage) {
createBackingField(
fir, IrDeclarationOrigin.PROPERTY_BACKING_FIELD, descriptor,
fir.fieldVisibility, fir.name, fir.isVal, fir.initializer,
type
).also { field ->
val initializer = fir.initializer
if (initializer is FirConstExpression<*>) {
// TODO: Normally we shouldn't have error type here
val constType = with(typeConverter) { initializer.typeRef.toIrType().takeIf { it !is IrErrorType } ?: type }
field.initializer = IrExpressionBodyImpl(initializer.toIrConst(constType))
}
}
}
}
fir.delegate != null -> {
with(declarationStorage) {
createBackingField(
fir, IrDeclarationOrigin.PROPERTY_DELEGATE, descriptor,
fir.fieldVisibility, Name.identifier("${fir.name}\$delegate"), true, fir.delegate
)
}
}
else -> {
null
}
}?.apply {
this.parent = this@Fir2IrLazyProperty.parent
}
}
override var getter: IrSimpleFunction? by lazyVar {
declarationStorage.createIrPropertyAccessor(
fir.getter, fir, this, type, parent, parent as? IrClass, false,
when {
origin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB -> origin
fir.delegate != null -> IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR
fir.getter is FirDefaultPropertyGetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
startOffset, endOffset
)
}
override var setter: IrSimpleFunction? by lazyVar {
if (!fir.isVar) return@lazyVar null
declarationStorage.createIrPropertyAccessor(
fir.setter, fir, this, type, parent, parent as? IrClass, true,
when {
fir.delegate != null -> IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR
fir.setter is FirDefaultPropertySetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
startOffset, endOffset
)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitProperty(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
backingField?.accept(visitor, data)
getter?.accept(visitor, data)
setter?.accept(visitor, data)
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
backingField = backingField?.transform(transformer, data) as? IrField
getter = getter?.run { transform(transformer, data) as IrSimpleFunction }
setter = setter?.run { transform(transformer, data) as IrSimpleFunction }
}
}