[FIR2IR] Make ExternalPackageParentPatcher a lowering

This is needed for two reasons:
1. Consistency
2. It should run after compiler plugins, which are now runs after fir2ir
   is finished for all modules

^KT-56173
This commit is contained in:
Dmitriy Novozhilov
2023-07-05 12:21:16 +03:00
committed by Space Team
parent 8e73d5a54a
commit fd87d722c1
8 changed files with 120 additions and 63 deletions
@@ -1,43 +0,0 @@
/*
* 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.backend
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
// TODO: should be a lowering
internal class ExternalPackageParentPatcher(
private val components: Fir2IrComponents,
private val fir2IrExtensions: Fir2IrExtensions
) : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression<*>) {
super.visitMemberAccess(expression)
val callee = expression.symbol.owner as? IrMemberWithContainerSource ?: return
if (callee.parent is IrExternalPackageFragment) {
val parentClass = fir2IrExtensions.generateOrGetFacadeClass(callee, components) ?: return
parentClass.parent = callee.parent
callee.parent = parentClass
when (callee) {
is IrProperty -> handleProperty(callee, parentClass)
is IrSimpleFunction -> callee.correspondingPropertySymbol?.owner?.let { handleProperty(it, parentClass) }
}
}
}
private fun handleProperty(property: IrProperty, newParent: IrClass) {
property.parent = newParent
property.getter?.parent = newParent
property.setter?.parent = newParent
property.backingField?.parent = newParent
}
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping
import org.jetbrains.kotlin.KtSourceFileLinesMappingFromLineStartOffsets
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.AnalysisFlags
@@ -32,12 +31,9 @@ import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
import org.jetbrains.kotlin.ir.interpreter.transformer.preprocessForConstTransformer
import org.jetbrains.kotlin.ir.interpreter.transformer.transformConst
import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.platform.isJs
import org.jetbrains.kotlin.psi.KtFile
class Fir2IrConverter(
@@ -54,7 +50,6 @@ class Fir2IrConverter(
allFirFiles: List<FirFile>,
irModuleFragment: IrModuleFragmentImpl,
fir2irVisitor: Fir2IrVisitor,
fir2IrExtensions: Fir2IrExtensions,
runPreCacheBuiltinClasses: Boolean
) {
session.lazyDeclarationResolver.disableLazyResolveContractChecks()
@@ -98,8 +93,6 @@ class Fir2IrConverter(
}
evaluateConstants(irModuleFragment, configuration)
irModuleFragment.acceptVoid(ExternalPackageParentPatcher(components, fir2IrExtensions))
}
fun bindFakeOverridesOrPostpone(declarations: List<IrDeclaration>) {
@@ -499,8 +492,7 @@ class Fir2IrConverter(
}
converter.runSourcesConversion(
allFirFiles, irModuleFragment, fir2irVisitor, fir2IrExtensions,
runPreCacheBuiltinClasses = initializedIrBuiltIns == null
allFirFiles, irModuleFragment, fir2irVisitor, runPreCacheBuiltinClasses = initializedIrBuiltIns == null
)
return Fir2IrResult(irModuleFragment, components, moduleDescriptor)
@@ -331,7 +331,8 @@ open class JvmIrCodegenFactory(
val phases = if (evaluatorFragmentInfoForPsi2Ir != null) jvmFragmentLoweringPhases else jvmLoweringPhases
val phaseConfig = customPhaseConfig ?: PhaseConfig(phases)
val context = JvmBackendContext(
state, irModuleFragment.irBuiltins, symbolTable, phaseConfig, extensions, backendExtension, irSerializer, irPluginContext
state, irModuleFragment.irBuiltins, symbolTable, phaseConfig, extensions,
backendExtension, irSerializer, JvmIrDeserializerImpl(), irProviders, irPluginContext
)
if (evaluatorFragmentInfoForPsi2Ir != null) {
context.localDeclarationsLoweringData = mutableMapOf()
@@ -473,7 +473,8 @@ private fun buildJvmLoweringPhases(
nlevels = 1,
actions = setOf(defaultDumper, validationAction),
lower =
fragmentSharedVariablesLowering then
externalPackageParentPatcherPhase then
fragmentSharedVariablesLowering then
validateIrBeforeLowering then
processOptionalAnnotationsPhase then
expectDeclarationsRemovingPhase then
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2023 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.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmFileFacadeClass
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
internal val externalPackageParentPatcherPhase = makeIrModulePhase(
::createLowering,
name = "ExternalPackageParentPatcherLowering",
description = "Replace parent from package fragment to FileKt class for top-level callables (K2 only)"
)
private fun createLowering(context: CommonBackendContext): FileLoweringPass {
require(context is JvmBackendContext)
return when (context.configuration[CommonConfigurationKeys.USE_FIR]) {
true -> ExternalPackageParentPatcherLowering(context)
false, null -> FileLoweringPass.Empty
}
}
class ExternalPackageParentPatcherLowering(val context: JvmBackendContext) : FileLoweringPass {
override fun lower(irFile: IrFile) {
irFile.acceptVoid(Visitor())
}
private inner class Visitor : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression<*>) {
visitElement(expression)
val callee = expression.symbol.owner as? IrMemberWithContainerSource ?: return
if (callee.parent is IrExternalPackageFragment) {
val parentClass = generateOrGetFacadeClass(callee) ?: return
parentClass.parent = callee.parent
callee.parent = parentClass
when (callee) {
is IrProperty -> handleProperty(callee, parentClass)
is IrSimpleFunction -> callee.correspondingPropertySymbol?.owner?.let { handleProperty(it, parentClass) }
}
}
}
private fun generateOrGetFacadeClass(declaration: IrMemberWithContainerSource): IrClass? {
val deserializedSource = declaration.containerSource ?: return null
if (deserializedSource !is FacadeClassSource) return null
val facadeName = deserializedSource.facadeClassName ?: deserializedSource.className
return JvmFileFacadeClass(
if (deserializedSource.facadeClassName != null) IrDeclarationOrigin.JVM_MULTIFILE_CLASS else IrDeclarationOrigin.FILE_CLASS,
facadeName.fqNameForTopLevelClassMaybeWithDollars.shortName(),
deserializedSource,
deserializeIr = { irClass -> deserializeTopLevelClass(irClass) }
).also {
it.createParameterDeclarations()
context.classNameOverride[it] = facadeName
}
}
private fun deserializeTopLevelClass(irClass: IrClass): Boolean {
return context.irDeserializer.deserializeTopLevelClass(
irClass, context.irBuiltIns, context.symbolTable, context.irProviders, context.generatorExtensions
)
}
private fun handleProperty(property: IrProperty, newParent: IrClass) {
property.parent = newParent
property.getter?.parent = newParent
property.setter?.parent = newParent
property.backingField?.parent = newParent
}
}
}
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
internal val typeAliasAnnotationMethodsPhase = makeIrFilePhase(
::TypeAliasAnnotationMethodsLowering,
name = "TypeAliasAnnotationMethodsLowering",
@@ -31,8 +31,8 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.linkage.IrProvider
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.util.*
@@ -49,6 +49,8 @@ class JvmBackendContext(
val generatorExtensions: JvmGeneratorExtensions,
val backendExtension: JvmBackendExtension,
val irSerializer: JvmIrSerializer?,
val irDeserializer: JvmIrDeserializer,
val irProviders: List<IrProvider>,
val irPluginContext: IrPluginContext?,
) : CommonBackendContext {
@@ -63,12 +65,17 @@ class JvmBackendContext(
generatorExtensions: JvmGeneratorExtensions,
backendExtension: JvmBackendExtension,
irSerializer: JvmIrSerializer?,
) : this(state, irBuiltIns, symbolTable, phaseConfig, generatorExtensions, backendExtension, irSerializer, null)
irProviders: List<IrProvider>,
irDeserializer: JvmIrDeserializer,
) : this(
state, irBuiltIns, symbolTable, phaseConfig, generatorExtensions,
backendExtension, irSerializer, irDeserializer, irProviders, irPluginContext = null
)
data class LocalFunctionData(
val localContext: LocalDeclarationsLowering.LocalFunctionContext,
val newParameterToOld: Map<IrValueParameter, IrValueParameter>,
val newParameterToCaptured: Map<IrValueParameter, IrValueSymbol>
val newParameterToCaptured: Map<IrValueParameter, IrValueSymbol>,
)
// If not-null, this is populated by LocalDeclarationsLowering with the intermediate data
@@ -219,7 +226,7 @@ class JvmBackendContext(
override fun handleDeepCopy(
fileSymbolMap: MutableMap<IrFileSymbol, IrFileSymbol>,
classSymbolMap: MutableMap<IrClassSymbol, IrClassSymbol>,
functionSymbolMap: MutableMap<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>
functionSymbolMap: MutableMap<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>,
) {
val oldClassesWithNameOverride = classNameOverride.keys.toList()
for (klass in oldClassesWithNameOverride) {
@@ -290,7 +297,7 @@ class JvmBackendContext(
get() = false
inner class JvmIr(
symbolTable: SymbolTable
symbolTable: SymbolTable,
) : Ir<JvmBackendContext>(this) {
override val symbols = JvmSymbols(this@JvmBackendContext, symbolTable)
@@ -300,7 +307,7 @@ class JvmBackendContext(
override fun remapMultiFieldValueClassStructure(
oldFunction: IrFunction,
newFunction: IrFunction,
parametersMappingOrNull: Map<IrValueParameter, IrValueParameter>?
parametersMappingOrNull: Map<IrValueParameter, IrValueParameter>?,
) {
val parametersMapping = parametersMappingOrNull ?: run {
require(oldFunction.explicitParametersCount == newFunction.explicitParametersCount) {
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.test.backend.handlers
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.lazy.AbstractIrLazyFunction
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
@@ -25,7 +27,7 @@ class IrInlineBodiesHandler(testServices: TestServices) : AbstractIrHandler(test
override fun processModule(module: TestModule, info: IrBackendInput) {
info.processAllIrModuleFragments(module) { irModule, _ ->
irModule.acceptChildrenVoid(InlineFunctionsCollector())
irModule.acceptChildrenVoid(InlineCallBodiesCheck())
irModule.acceptChildrenVoid(InlineCallBodiesCheck(firEnabled = module.frontendKind == FrontendKinds.FIR))
}
assertions.assertTrue((info as IrBackendInput.JvmIrBackendInput).backendInput.symbolTable.allUnbound.isEmpty())
@@ -46,7 +48,7 @@ class IrInlineBodiesHandler(testServices: TestServices) : AbstractIrHandler(test
}
}
inner class InlineCallBodiesCheck : IrElementVisitorVoid {
inner class InlineCallBodiesCheck(val firEnabled: Boolean) : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
@@ -68,7 +70,14 @@ class IrInlineBodiesHandler(testServices: TestServices) : AbstractIrHandler(test
if (this !is AbstractIrLazyFunction) return body != null
if (!isDeserializationEnabled) return false
if (!isInline || isFakeOverride) return false
return getTopLevelDeclaration() is DeserializableClass
val topLevelDeclaration = getTopLevelDeclaration()
if (topLevelDeclaration is DeserializableClass) return true
return when (firEnabled) {
// In compilation with FIR parents of external top-levels functions are replaced
// in lowerings, not in fir2ir converter
true -> topLevelDeclaration.parent is IrExternalPackageFragment
false -> false
}
}
}
}