[fir2ir] Generate facade stubs for external source declarations

In the IDE, it's impossible to pass classes from all modules to the
backend, so symbols for 'external' source declarations need to be
generated ad-hoc.

Such declarations do not go through the lowering phase, including one
that replaces the containing package fragment with a facade class.
This commit is contained in:
Yan Zhulanow
2023-06-01 17:14:27 +09:00
committed by Space Team
parent 7d88ade005
commit ba0f8c8735
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_FQ_NAMES
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
@@ -42,10 +43,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.UNDEFINED_PARAMETER_INDEX
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.GeneratedByPlugin
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrScriptImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.declarations.impl.SCRIPT_K2_ORIGIN
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind
@@ -55,10 +53,15 @@ import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.utils.addToStdlib.runUnless
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.threadLocal
@@ -294,23 +297,94 @@ class Fir2IrDeclarationStorage(
firBasedSymbol: FirBasedSymbol<*>,
firOrigin: FirDeclarationOrigin
): IrDeclarationParent? {
return if (parentLookupTag != null) {
classifierStorage.findIrClass(parentLookupTag)
} else {
val containerFile = when (firBasedSymbol) {
is FirCallableSymbol -> firProvider.getFirCallableContainerFile(firBasedSymbol)
is FirClassLikeSymbol -> firProvider.getFirClassifierContainerFileIfAny(firBasedSymbol)
else -> error("Unknown symbol: $firBasedSymbol")
}
if (parentLookupTag != null) {
return classifierStorage.findIrClass(parentLookupTag)
}
when {
containerFile != null -> fileCache[containerFile]
firBasedSymbol is FirCallableSymbol -> getIrExternalPackageFragment(packageFqName, firOrigin)
val parentPackage = when (firBasedSymbol) {
is FirCallableSymbol<*> -> {
getIrExternalPackageFragment(packageFqName, firOrigin)
}
else -> {
// TODO: All classes from BUILT_INS_PACKAGE_FQ_NAMES are considered built-ins now,
// which is not exact and can lead to some problems
else -> getIrExternalOrBuiltInsPackageFragment(packageFqName, firOrigin)
getIrExternalOrBuiltInsPackageFragment(packageFqName, firOrigin)
}
}
val firProviderForSymbol = firBasedSymbol.moduleData.session.firProvider
val containerFile = when (firBasedSymbol) {
is FirCallableSymbol -> firProviderForSymbol.getFirCallableContainerFile(firBasedSymbol)
is FirClassLikeSymbol -> firProviderForSymbol.getFirClassifierContainerFileIfAny(firBasedSymbol)
else -> error("Unknown symbol: $firBasedSymbol")
}
if (containerFile != null) {
val existingFile = fileCache[containerFile]
if (existingFile != null) {
return existingFile
}
// Sudden declarations do not go through IR lowering process,
// so the parent file isn't replaced with a facade class, as in 'FileClassLowering'.
if (configuration.allowNonCachedDeclarations && firBasedSymbol is FirCallableSymbol<*>) {
val psiFile = containerFile.psi?.containingFile
if (psiFile is KtFile) {
val fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(psiFile)
val className = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.fileClassFqName)
val facadeClassName: JvmClassName?
val declarationOrigin: IrDeclarationOrigin
if (fileClassInfo.withJvmMultifileClass) {
facadeClassName = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.facadeClassFqName)
declarationOrigin = IrDeclarationOrigin.JVM_MULTIFILE_CLASS
} else {
facadeClassName = null
declarationOrigin = IrDeclarationOrigin.FILE_CLASS
}
val facadeShortName = className.fqNameForClassNameWithoutDollars.shortName()
val containerSource = NonCachedSourceFacadeContainerSource(className, facadeClassName)
return NonCachedSourceFileFacadeClass(declarationOrigin, facadeShortName, containerSource).apply {
parent = parentPackage
createParameterDeclarations()
}
}
}
}
return parentPackage
}
private class NonCachedSourceFileFacadeClass(
origin: IrDeclarationOrigin,
name: Name,
source: SourceElement,
) : IrClassImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, IrClassSymbolImpl(), name,
ClassKind.CLASS, DescriptorVisibilities.PUBLIC, Modality.FINAL,
source = source
)
private class NonCachedSourceFacadeContainerSource(
override val className: JvmClassName,
override val facadeClassName: JvmClassName?
) : DeserializedContainerSource, FacadeClassSource {
override val incompatibility get() = null
override val isPreReleaseInvisible get() = false
override val abiStability get() = DeserializedContainerAbiStability.STABLE
override val presentableString get() = className.internalName
override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE
}
private fun computeThisReceiverOwner(parent: IrDeclarationParent?): IrClass? {
if (parent is IrClass && parent !is NonCachedSourceFileFacadeClass) {
return parent
}
return null
}
internal fun findIrParent(callableDeclaration: FirCallableDeclaration): IrDeclarationParent? {
@@ -462,7 +536,7 @@ class Fir2IrDeclarationStorage(
private fun <T : IrFunction> T.bindAndDeclareParameters(
function: FirFunction?,
irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass,
thisReceiverOwner: IrClass?,
isStatic: Boolean,
forSetter: Boolean,
parentPropertyReceiver: FirReceiverParameter? = null
@@ -540,7 +614,7 @@ class Fir2IrDeclarationStorage(
fun createIrFunction(
function: FirFunction,
irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass,
thisReceiverOwner: IrClass? = computeThisReceiverOwner(irParent),
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
@@ -707,7 +781,7 @@ class Fir2IrDeclarationStorage(
// with the annotation itself.
constructorCache[constructor] = this
enterScope(this)
bindAndDeclareParameters(constructor, irParent, isStatic = false, forSetter = false)
bindAndDeclareParameters(constructor, irParent, irParent, isStatic = false, forSetter = false)
leaveScope(this)
}
}
@@ -739,7 +813,7 @@ class Fir2IrDeclarationStorage(
correspondingProperty: IrDeclarationWithName,
propertyType: IrType,
irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass,
thisReceiverOwner: IrClass? = computeThisReceiverOwner(irParent),
isSetter: Boolean,
origin: IrDeclarationOrigin,
startOffset: Int,
@@ -924,7 +998,7 @@ class Fir2IrDeclarationStorage(
fun createIrProperty(
property: FirProperty,
irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass,
thisReceiverOwner: IrClass? = computeThisReceiverOwner(irParent),
predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = (irParent as? IrClass)?.classId?.toLookupTag(),