[FIR2IR] Introduce & use lazy function for external class functions

This commit is contained in:
Mikhail Glukhikh
2020-06-18 16:09:38 +03:00
parent 6d07af63cf
commit d08f91bf35
6 changed files with 205 additions and 21 deletions
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.fir.descriptors.FirPackageFragmentDescriptor
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.Fir2IrLazySimpleFunction
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.symbols.*
@@ -721,7 +723,7 @@ class Fir2IrDeclarationStorage(
}
}
private fun createIrParameter(
internal fun createIrParameter(
valueParameter: FirValueParameter,
index: Int = -1,
useStubForDefaultValueStub: Boolean = true,
@@ -833,14 +835,37 @@ class Fir2IrDeclarationStorage(
getCachedIrFunction(firDeclaration)?.let { return it.symbol }
val signature = signatureComposer.composeSignature(firDeclaration)
val irParent = findIrParent(firDeclaration)
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
if (signature != null) {
symbolTable.referenceSimpleFunctionIfAny(signature)?.let { irFunctionSymbol ->
val irFunction = irFunctionSymbol.owner
functionCache[firDeclaration] = irFunction
return irFunctionSymbol
}
// TODO: package fragment members (?)
if (firDeclaration is FirSimpleFunction && irParent is Fir2IrLazyClass) {
if (parentOrigin == IrDeclarationOrigin.DEFINED) {
throw AssertionError()
}
val symbol = Fir2IrSimpleFunctionSymbol(signature, firDeclaration.containerSource)
val irFunction = firDeclaration.convertWithOffsets { startOffset, endOffset ->
symbolTable.declareSimpleFunction(signature, { symbol }) {
val isFakeOverride =
firFunctionSymbol is FirNamedFunctionSymbol && firFunctionSymbol.isFakeOverride &&
firFunctionSymbol.callableId != firFunctionSymbol.overriddenSymbol?.callableId
Fir2IrLazySimpleFunction(
components, startOffset, endOffset, parentOrigin, firDeclaration, symbol, isFakeOverride
).apply {
parent = irParent
}
}
}
functionCache[firDeclaration] = irFunction
// NB: this is needed to prevent recursions in case of self bounds
(irFunction as Fir2IrLazySimpleFunction).prepareTypeParameters()
return symbol
}
}
val parentOrigin = (irParent as? IrDeclaration)?.origin ?: IrDeclarationOrigin.DEFINED
createIrFunction(firDeclaration, irParent, origin = parentOrigin).apply {
setAndModifyParent(irParent)
}.symbol
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.lazy
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.toIrType
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.Fir2IrBindableSymbol
import org.jetbrains.kotlin.ir.IrElementBase
@@ -22,7 +23,21 @@ abstract class AbstractFir2IrLazyDeclaration<F : FirMemberDeclaration, D : IrSym
override var origin: IrDeclarationOrigin,
val fir: F,
open val symbol: Fir2IrBindableSymbol<*, D>
) : IrElementBase(startOffset, endOffset), IrDeclaration, Fir2IrComponents by components {
) : IrElementBase(startOffset, endOffset), IrDeclaration, IrDeclarationParent, Fir2IrComponents by components {
internal fun prepareTypeParameters() {
typeParameters = fir.typeParameters.mapIndexedNotNull { index, typeParameter ->
if (typeParameter !is FirTypeParameter) return@mapIndexedNotNull null
classifierStorage.getIrTypeParameter(typeParameter, index).apply {
parent = this@AbstractFir2IrLazyDeclaration
if (superTypes.isEmpty()) {
typeParameter.bounds.mapTo(superTypes) { it.toIrType(typeConverter) }
}
}
}
}
lateinit var typeParameters: List<IrTypeParameter>
override var metadata: Nothing?
get() = null
set(_) = error("We should never need to store metadata of external declarations.")
@@ -41,18 +41,6 @@ class Fir2IrLazyClass(
classifierStorage.preCacheTypeParameters(fir)
}
internal fun prepareTypeParameters() {
typeParameters = fir.typeParameters.mapIndexedNotNull { index, typeParameter ->
if (typeParameter !is FirTypeParameter) return@mapIndexedNotNull null
classifierStorage.getIrTypeParameter(typeParameter, index).apply {
parent = this@Fir2IrLazyClass
if (superTypes.isEmpty()) {
typeParameter.bounds.mapTo(superTypes) { it.toIrType(typeConverter) }
}
}
}
}
override val source: SourceElement
get() = SourceElement.NO_SOURCE
@@ -112,8 +100,6 @@ class Fir2IrLazyClass(
fir.superTypeRefs.map { it.toIrType(typeConverter) }
}
override lateinit var typeParameters: List<IrTypeParameter>
override var thisReceiver: IrValueParameter? by lazyVar {
symbolTable.enterScope(this)
val typeArguments = fir.typeParameters.map {
@@ -151,12 +137,12 @@ class Fir2IrLazyClass(
return@processFunctionsByName
}
result += if (!it.isFakeOverride) {
declarationStorage.createIrFunction(it.fir, irParent = this, origin = origin)
declarationStorage.getIrFunctionSymbol(it).owner
} else {
val fakeOverrideSymbol =
FirClassSubstitutionScope.createFakeOverrideFunction(session, it.fir, it)
classifierStorage.preCacheTypeParameters(it.fir)
declarationStorage.createIrFunction(fakeOverrideSymbol.fir, irParent = this)
declarationStorage.getIrFunctionSymbol(fakeOverrideSymbol).owner
}
}
}
@@ -0,0 +1,159 @@
/*
* 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.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
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.findMatchingOverriddenSymbolsFromSupertypes
import org.jetbrains.kotlin.fir.backend.toIrType
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.Fir2IrSimpleFunctionSymbol
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.IrBody
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.mapOptimized
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
class Fir2IrLazySimpleFunction(
components: Fir2IrComponents,
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
fir: FirSimpleFunction,
symbol: Fir2IrSimpleFunctionSymbol,
override val isFakeOverride: Boolean
) : AbstractFir2IrLazyDeclaration<FirSimpleFunction, IrSimpleFunction>(
components, startOffset, endOffset, origin, fir, symbol
), IrSimpleFunction {
init {
symbol.bind(this)
classifierStorage.preCacheTypeParameters(fir)
}
override val isTailrec: Boolean
get() = fir.isTailRec
override val isSuspend: Boolean
get() = fir.isSuspend
override val isOperator: Boolean
get() = fir.isOperator
@ObsoleteDescriptorBasedAPI
override val descriptor: FunctionDescriptor
get() = super.descriptor as FunctionDescriptor
override val symbol: Fir2IrSimpleFunctionSymbol
get() = super.symbol as Fir2IrSimpleFunctionSymbol
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() = fir.name
override val visibility: Visibility
get() = fir.visibility
override val modality: Modality
get() = fir.modality!!
override var correspondingPropertySymbol: IrPropertySymbol? = null
override var attributeOwnerId: IrAttributeContainer = this
override var returnType: IrType by lazyVar {
fir.returnTypeRef.toIrType(typeConverter)
}
override var dispatchReceiverParameter: IrValueParameter? by lazyVar {
val containingClass = parent as? IrClass
if (!fir.isStatic && containingClass != null) {
declarationStorage.enterScope(this)
declareThisReceiverParameter(
symbolTable,
thisType = containingClass.thisReceiver?.type
?: throw AssertionError(),
thisOrigin = origin
).apply {
declarationStorage.leaveScope(this@Fir2IrLazySimpleFunction)
}
} else null
}
override var extensionReceiverParameter: IrValueParameter? by lazyVar {
fir.receiverTypeRef?.let {
declarationStorage.enterScope(this)
declareThisReceiverParameter(
symbolTable,
thisType = it.toIrType(typeConverter),
thisOrigin = origin,
).apply {
declarationStorage.leaveScope(this@Fir2IrLazySimpleFunction)
}
}
}
override var valueParameters: List<IrValueParameter> by lazyVar {
declarationStorage.enterScope(this)
fir.valueParameters.mapIndexed { index, valueParameter ->
declarationStorage.createIrParameter(
valueParameter, index,
).apply {
this.parent = this@Fir2IrLazySimpleFunction
}
}.apply {
declarationStorage.leaveScope(this@Fir2IrLazySimpleFunction)
}
}
override var overriddenSymbols: List<IrSimpleFunctionSymbol> by lazyVar {
val containingClass = parent as? IrClass
containingClass?.findMatchingOverriddenSymbolsFromSupertypes(irBuiltIns, this)
?.filterIsInstance<IrSimpleFunctionSymbol>().orEmpty()
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitSimpleFunction(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)
}
}
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// FILE: Generic.java
class Generic<T> {
T id(T x) { return x; }
+1 -1
View File
@@ -27,7 +27,7 @@ FILE fqName:<root> fileName:/builtinMap.kt
$receiver: VALUE_PARAMETER name:<this> type:java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?>
BLOCK_BODY
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): kotlin.Unit declared in <root>.plus'
CALL 'public open fun put (p0: K of java.util.LinkedHashMap?, p1: V of java.util.LinkedHashMap?): V of java.util.LinkedHashMap? declared in java.util.LinkedHashMap' type=V1 of <root>.plus? origin=null
CALL 'public open fun put (p0: K of java.util.LinkedHashMap?, p1: V of java.util.LinkedHashMap?): V of java.util.LinkedHashMap? [fake_override] declared in java.util.LinkedHashMap' type=V1 of <root>.plus? origin=null
$this: GET_VAR '<this>: java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?> declared in <root>.plus.<anonymous>' type=java.util.LinkedHashMap<K1 of <root>.plus?, V1 of <root>.plus?> origin=null
p0: CALL 'public final fun <get-first> (): A of kotlin.Pair declared in kotlin.Pair' type=K1 of <root>.plus origin=GET_PROPERTY
$this: GET_VAR 'pair: kotlin.Pair<K1 of <root>.plus, V1 of <root>.plus> declared in <root>.plus' type=kotlin.Pair<K1 of <root>.plus, V1 of <root>.plus> origin=null