[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.KtFakeSourceElementKind
import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_FQ_NAMES import org.jetbrains.kotlin.builtins.StandardNames.BUILT_INS_PACKAGE_FQ_NAMES
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty 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.builders.declarations.UNDEFINED_PARAMETER_INDEX
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.GeneratedByPlugin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.GeneratedByPlugin
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.*
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.lazy.IrLazyClass import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind 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.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.name.SpecialNames 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.addToStdlib.runUnless
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.threadLocal import org.jetbrains.kotlin.utils.threadLocal
@@ -294,23 +297,94 @@ class Fir2IrDeclarationStorage(
firBasedSymbol: FirBasedSymbol<*>, firBasedSymbol: FirBasedSymbol<*>,
firOrigin: FirDeclarationOrigin firOrigin: FirDeclarationOrigin
): IrDeclarationParent? { ): IrDeclarationParent? {
return if (parentLookupTag != null) { if (parentLookupTag != null) {
classifierStorage.findIrClass(parentLookupTag) return classifierStorage.findIrClass(parentLookupTag)
} else { }
val containerFile = when (firBasedSymbol) {
is FirCallableSymbol -> firProvider.getFirCallableContainerFile(firBasedSymbol)
is FirClassLikeSymbol -> firProvider.getFirClassifierContainerFileIfAny(firBasedSymbol)
else -> error("Unknown symbol: $firBasedSymbol")
}
when { val parentPackage = when (firBasedSymbol) {
containerFile != null -> fileCache[containerFile] is FirCallableSymbol<*> -> {
firBasedSymbol is FirCallableSymbol -> getIrExternalPackageFragment(packageFqName, firOrigin) getIrExternalPackageFragment(packageFqName, firOrigin)
}
else -> {
// TODO: All classes from BUILT_INS_PACKAGE_FQ_NAMES are considered built-ins now, // TODO: All classes from BUILT_INS_PACKAGE_FQ_NAMES are considered built-ins now,
// which is not exact and can lead to some problems // 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? { internal fun findIrParent(callableDeclaration: FirCallableDeclaration): IrDeclarationParent? {
@@ -462,7 +536,7 @@ class Fir2IrDeclarationStorage(
private fun <T : IrFunction> T.bindAndDeclareParameters( private fun <T : IrFunction> T.bindAndDeclareParameters(
function: FirFunction?, function: FirFunction?,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass, thisReceiverOwner: IrClass?,
isStatic: Boolean, isStatic: Boolean,
forSetter: Boolean, forSetter: Boolean,
parentPropertyReceiver: FirReceiverParameter? = null parentPropertyReceiver: FirReceiverParameter? = null
@@ -540,7 +614,7 @@ class Fir2IrDeclarationStorage(
fun createIrFunction( fun createIrFunction(
function: FirFunction, function: FirFunction,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass, thisReceiverOwner: IrClass? = computeThisReceiverOwner(irParent),
predefinedOrigin: IrDeclarationOrigin? = null, predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false, isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null, fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
@@ -707,7 +781,7 @@ class Fir2IrDeclarationStorage(
// with the annotation itself. // with the annotation itself.
constructorCache[constructor] = this constructorCache[constructor] = this
enterScope(this) enterScope(this)
bindAndDeclareParameters(constructor, irParent, isStatic = false, forSetter = false) bindAndDeclareParameters(constructor, irParent, irParent, isStatic = false, forSetter = false)
leaveScope(this) leaveScope(this)
} }
} }
@@ -739,7 +813,7 @@ class Fir2IrDeclarationStorage(
correspondingProperty: IrDeclarationWithName, correspondingProperty: IrDeclarationWithName,
propertyType: IrType, propertyType: IrType,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass, thisReceiverOwner: IrClass? = computeThisReceiverOwner(irParent),
isSetter: Boolean, isSetter: Boolean,
origin: IrDeclarationOrigin, origin: IrDeclarationOrigin,
startOffset: Int, startOffset: Int,
@@ -924,7 +998,7 @@ class Fir2IrDeclarationStorage(
fun createIrProperty( fun createIrProperty(
property: FirProperty, property: FirProperty,
irParent: IrDeclarationParent?, irParent: IrDeclarationParent?,
thisReceiverOwner: IrClass? = irParent as? IrClass, thisReceiverOwner: IrClass? = computeThisReceiverOwner(irParent),
predefinedOrigin: IrDeclarationOrigin? = null, predefinedOrigin: IrDeclarationOrigin? = null,
isLocal: Boolean = false, isLocal: Boolean = false,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = (irParent as? IrClass)?.classId?.toLookupTag(), fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = (irParent as? IrClass)?.classId?.toLookupTag(),