[Lower] Extract lifting logic from `LocalDeclarationsInInlineLambdasPreparationLowering`
^KT-78856
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/LocalDeclarationsInInlineLambdas.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/LocalDeclarationsInInlineLambdas.kt
index 7f47e8a..71f8da0 100644
--- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/LocalDeclarationsInInlineLambdas.kt
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/LocalDeclarationsInInlineLambdas.kt
@@ -11,7 +11,6 @@
import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering
import org.jetbrains.kotlin.backend.common.lower.VisibilityPolicy
import org.jetbrains.kotlin.backend.common.phaser.PhaseDescription
-import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
@@ -22,6 +21,7 @@
import org.jetbrains.kotlin.ir.transformStatement
import org.jetbrains.kotlin.ir.util.isInlineParameter
import org.jetbrains.kotlin.ir.util.isOriginallyLocalDeclaration
+import org.jetbrains.kotlin.ir.util.isSyntheticBlockForInlineCall
import org.jetbrains.kotlin.ir.util.setDeclarationsParent
import org.jetbrains.kotlin.ir.visitors.*
@@ -39,10 +39,6 @@
*/
@PhaseDescription("LocalDeclarationsInInlineLambdasPreparationLowering")
class LocalDeclarationsInInlineLambdasPreparationLowering(val context: LoweringContext) : BodyLoweringPass {
- override fun lower(irFile: IrFile) {
- runOnFilePostfix(irFile)
- }
-
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildren(object : IrTransformer<IrDeclarationParent>() {
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclarationParent) =
@@ -53,20 +49,7 @@
if (!rootCallee.isInline)
return super.visitCall(expression, data)
- val inlineLambdas = mutableListOf<IrFunction>()
- for (index in expression.arguments.indices) {
- val argument = expression.arguments[index]
- val inlineLambda = when (argument) {
- is IrRichPropertyReference -> argument.getterFunction
- is IrRichFunctionReference -> argument.invokeFunction
- else -> null
- }?.takeIf { rootCallee.parameters[index].isInlineParameter() }
- if (inlineLambda == null)
- expression.arguments[index] = argument?.transform(this, data)
- else
- inlineLambdas.add(inlineLambda)
- }
-
+ val inlineLambdas = collectInlineLambdas(expression, rootCallee, this, data)
if (inlineLambdas.isEmpty())
return expression
@@ -102,8 +85,10 @@
// TODO: Remove fragment above after fixing KT-77103
val irBlock = IrBlockImpl(expression.startOffset, expression.endOffset, expression.type).apply {
+ isSyntheticBlockForInlineCall = true
statements += expression
}
+
LocalDeclarationsLowering(
context,
visibilityPolicy = object : VisibilityPolicy {
@@ -122,11 +107,53 @@
remapCapturedTypesInExtractedLocalDeclarations = false,
).lower(irBlock, container, data)
- val localDeclarationsToPopUp = mutableListOf<IrDeclaration>()
-
val outerTransformer = this
for (lambda in inlineLambdas) {
- lambda.transformChildrenVoid(object : IrElementTransformerVoid() {
+ lambda.transformChildrenVoid(object : LocalDeclarationsInInlineLambdasTransformer() {
+ override fun visitSimpleFunctionOrClass(declaration: IrDeclaration): IrStatement {
+ // Recursive call to outer transformer for handling nested inline lambdas
+ declaration.transformChildren(outerTransformer, declaration as IrDeclarationParent)
+ return declaration
+ }
+ })
+ }
+
+ return irBlock
+ }
+ }, container as? IrDeclarationParent ?: container.parent)
+ }
+}
+
+@PhaseDescription("LocalDeclarationsInInlineLambdasPopupLowering")
+class LocalDeclarationsInInlineLambdasPopupLowering(val context: LoweringContext) : BodyLoweringPass {
+ override fun lower(irBody: IrBody, container: IrDeclaration) {
+ irBody.transformChildren(object : IrTransformer<IrDeclarationParent>() {
+ override fun visitDeclaration(declaration: IrDeclarationBase, data: IrDeclarationParent) =
+ super.visitDeclaration(declaration, (declaration as? IrDeclarationParent) ?: data)
+
+ override fun visitBlock(expression: IrBlock, data: IrDeclarationParent): IrExpression {
+ if (!expression.isSyntheticBlockForInlineCall) return super.visitBlock(expression, data)
+
+ val call = expression.statements.firstOrNull() as? IrCall ?: return expression
+ val rootCallee = call.symbol.owner
+ val inlineLambdas = collectInlineLambdas(call, rootCallee, this, data)
+
+ val localDeclarationsToPopUp = mutableListOf<IrDeclaration>()
+ val outerTransformer = this
+ for (lambda in inlineLambdas) {
+ lambda.transformChildrenVoid(object : LocalDeclarationsInInlineLambdasTransformer() {
+ override fun visitSimpleFunctionOrClass(declaration: IrDeclaration): IrStatement {
+ // Recursive call to outer transformer for handling nested inline lambdas
+ declaration.transformChildren(outerTransformer, declaration as IrDeclarationParent)
+ return if (declaration.isOriginallyLocalDeclaration) {
+ localDeclarationsToPopUp += declaration
+ IrCompositeImpl(
+ declaration.startOffset, declaration.endOffset,
+ context.irBuiltIns.unitType
+ )
+ } else declaration
+ }
+
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrStatement {
declaration.getter.transformStatement(this)
declaration.setter?.transformStatement(this)
@@ -145,32 +172,45 @@
expression.setterFunction?.transformChildrenVoid(this)
return expression
}
-
- override fun visitClass(declaration: IrClass): IrStatement = visitSimpleFunctionOrClass(declaration)
-
- override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement =
- visitSimpleFunctionOrClass(declaration)
-
- private fun visitSimpleFunctionOrClass(declaration: IrDeclaration): IrStatement {
- // Recursive call to outer transformer for handling nested inline lambdas
- declaration.transformChildren(outerTransformer, declaration as IrDeclarationParent)
- return if (declaration.isOriginallyLocalDeclaration) {
- localDeclarationsToPopUp += declaration
- IrCompositeImpl(
- declaration.startOffset, declaration.endOffset,
- context.irBuiltIns.unitType
- )
- } else declaration
- }
-
})
}
- irBlock.statements.addAll(0, localDeclarationsToPopUp)
+ expression.statements.addAll(0, localDeclarationsToPopUp)
localDeclarationsToPopUp.forEach { it.setDeclarationsParent(data) }
- return irBlock
+ return expression
}
}, container as? IrDeclarationParent ?: container.parent)
}
}
+
+private abstract class LocalDeclarationsInInlineLambdasTransformer() : IrElementTransformerVoid() {
+ abstract fun visitSimpleFunctionOrClass(declaration: IrDeclaration): IrStatement
+
+ override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement = visitSimpleFunctionOrClass(declaration)
+
+ override fun visitClass(declaration: IrClass): IrStatement = visitSimpleFunctionOrClass(declaration)
+}
+
+private fun collectInlineLambdas(
+ expression: IrCall,
+ rootCallee: IrSimpleFunction,
+ transformer: IrTransformer<IrDeclarationParent>,
+ data: IrDeclarationParent,
+): MutableList<IrFunction> {
+ val inlineLambdas = mutableListOf<IrFunction>()
+ for (index in expression.arguments.indices) {
+ val argument = expression.arguments[index]
+ val inlineLambda = when (argument) {
+ is IrRichPropertyReference -> argument.getterFunction
+ is IrRichFunctionReference -> argument.invokeFunction
+ else -> null
+ }?.takeIf { rootCallee.parameters[index].isInlineParameter() }
+ if (inlineLambda == null) {
+ expression.arguments[index] = argument?.transform(transformer, data)
+ } else
+ inlineLambdas.add(inlineLambda)
+ }
+
+ return inlineLambdas
+}
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt
index 6a690a6..b5790a2 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt
@@ -10,6 +10,7 @@
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToLocalSuspendFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToNonLocalSuspendFunctionsLowering
+import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPopupLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPreparationLowering
import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.backend.common.phaser.*
@@ -180,6 +181,12 @@
name = "LocalDeclarationsInInlineLambdasPreparationPhase",
)
+private val popupLocalDeclarationsInInlineLambdasPhase = makeIrModulePhase(
+ ::LocalDeclarationsInInlineLambdasPopupLowering,
+ name = "LocalDeclarationsInInlineLambdasPopupLowering",
+ prerequisite = setOf(prepareLocalDeclarationsInInlineLambdasPhase)
+)
+
private val replaceSuspendIntrinsicLowering = makeIrModulePhase(
::ReplaceSuspendIntrinsicLowering,
name = "ReplaceSuspendIntrinsicLowering",
@@ -739,6 +746,7 @@
lateinitPhase,
sharedVariablesLoweringPhase,
prepareLocalDeclarationsInInlineLambdasPhase,
+ popupLocalDeclarationsInInlineLambdasPhase,
arrayConstructorPhase,
inlineOnlyPrivateFunctionsPhase,
outerThisSpecialAccessorInInlineFunctionsPhase,
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt
index 4d94881..7d90b0f 100644
--- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt
@@ -9,6 +9,7 @@
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToNonLocalSuspendFunctionsLowering
+import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPopupLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPreparationLowering
import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.backend.common.lower.optimizations.PropertyAccessorInlineLowering
@@ -125,6 +126,12 @@
name = "LocalDeclarationsInInlineLambdasPreparationPhase",
)
+private val popupLocalDeclarationsInInlineLambdasPhase = makeIrModulePhase(
+ ::LocalDeclarationsInInlineLambdasPopupLowering,
+ name = "LocalDeclarationsInInlineLambdasPopupLowering",
+ prerequisite = setOf(prepareLocalDeclarationsInInlineLambdasPhase),
+)
+
/**
* The first phase of inlining (inline only private functions).
*/
@@ -606,6 +613,7 @@
lateinitPhase,
sharedVariablesLoweringPhase,
prepareLocalDeclarationsInInlineLambdasPhase,
+ popupLocalDeclarationsInInlineLambdasPhase,
arrayConstructorPhase,
inlineOnlyPrivateFunctionsPhase,
outerThisSpecialAccessorInInlineFunctionsPhase,
diff --git a/compiler/ir/ir.inline/src/org/jetbrains/kotlin/ir/inline/CommonLoweringPhases.kt b/compiler/ir/ir.inline/src/org/jetbrains/kotlin/ir/inline/CommonLoweringPhases.kt
index 11ac647..114cce8a 100644
--- a/compiler/ir/ir.inline/src/org/jetbrains/kotlin/ir/inline/CommonLoweringPhases.kt
+++ b/compiler/ir/ir.inline/src/org/jetbrains/kotlin/ir/inline/CommonLoweringPhases.kt
@@ -13,6 +13,7 @@
import org.jetbrains.kotlin.backend.common.lower.SharedVariablesLowering
import org.jetbrains.kotlin.backend.common.lower.inline.AvoidLocalFOsInInlineFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.inline.InlineCallCycleCheckerLowering
+import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPopupLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPreparationLowering
import org.jetbrains.kotlin.backend.common.phaser.IrValidationAfterInliningAllFunctionsPhase
import org.jetbrains.kotlin.backend.common.phaser.IrValidationAfterInliningOnlyPrivateFunctionsPhase
@@ -44,6 +45,12 @@
name = "LocalDeclarationsInInlineLambdasPreparationPhase",
)
+private val popupLocalDeclarationsInInlineLambdasPhase = makeIrModulePhase(
+ ::LocalDeclarationsInInlineLambdasPopupLowering,
+ name = "LocalDeclarationsInInlineLambdasPopupPhase",
+ prerequisite = setOf(prepareLocalDeclarationsInInlineLambdasPhase)
+)
+
private val arrayConstructorPhase = makeIrModulePhase(
::ArrayConstructorLowering,
name = "ArrayConstructor",
@@ -145,6 +152,7 @@
this += lateinitPhase
this += sharedVariablesLoweringPhase
this += prepareLocalDeclarationsInInlineLambdasPhase
+ this += popupLocalDeclarationsInInlineLambdasPhase
this += arrayConstructorPhase
this += checkInlineCallCyclesPhase
this += inlineOnlyPrivateFunctionsPhase
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt
index c0ec4b9..db0eeb6 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt
@@ -11,6 +11,7 @@
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue
import org.jetbrains.kotlin.ir.expressions.IrVararg
@@ -220,6 +221,8 @@
*/
var IrDeclaration.isOriginallyLocalDeclaration: Boolean by irFlag(copyByDefault = true)
+var IrBlock.isSyntheticBlockForInlineCall: Boolean by irFlag(copyByDefault = true)
+
private inline fun IrDeclaration.isLocalImpl(isLocal: (IrDeclarationWithVisibility) -> Boolean): Boolean {
var current: IrElement = this
while (current !is IrPackageFragment) {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt
index 3494034..be17494 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/NativeLoweringPhases.kt
@@ -11,6 +11,7 @@
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToNonLocalSuspendFunctionsLowering
+import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPopupLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPreparationLowering
import org.jetbrains.kotlin.backend.common.lower.optimizations.PropertyAccessorInlineLowering
import org.jetbrains.kotlin.backend.common.lower.optimizations.LivenessAnalysis
@@ -158,6 +159,12 @@
prerequisite = setOf(sharedVariablesPhase),
)
+private val popupLocalDeclarationsInInlineLambdasPhase = createFileLoweringPhase(
+ ::LocalDeclarationsInInlineLambdasPopupLowering,
+ name = "PopupLocalDeclarationsInInlineLambdas",
+ prerequisite = setOf(prepareLocalDeclarationsInInlineLambdasPhase),
+)
+
private val postInlinePhase = createFileLoweringPhase(
{ context: Context -> PostInlineLowering(context) },
name = "PostInline",
@@ -378,7 +385,7 @@
InteropLowering(generationState.context, generationState.fileLowerState)
},
name = "Interop",
- prerequisite = setOf(prepareLocalDeclarationsInInlineLambdasPhase)
+ prerequisite = setOf(popupLocalDeclarationsInInlineLambdasPhase)
)
private val specialInteropIntrinsicsPhase = createFileLoweringPhase(
@@ -571,6 +578,7 @@
lateinitPhase,
sharedVariablesPhase,
prepareLocalDeclarationsInInlineLambdasPhase,
+ popupLocalDeclarationsInInlineLambdasPhase,
arrayConstructorPhase,
inlineOnlyPrivateFunctionsPhase,
outerThisSpecialAccessorInInlineFunctionsPhase,
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt
index b3e771f..e382a1e 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/NativeInlineFunctionResolver.kt
@@ -9,6 +9,7 @@
import org.jetbrains.kotlin.backend.common.lower.LateinitLowering
import org.jetbrains.kotlin.backend.common.lower.SharedVariablesLowering
import org.jetbrains.kotlin.backend.common.lower.UpgradeCallableReferences
+import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPopupLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalDeclarationsInInlineLambdasPreparationLowering
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
@@ -60,6 +61,7 @@
SharedVariablesLowering(context).lower(body, function)
LocalDeclarationsInInlineLambdasPreparationLowering(context).lower(body, function)
+ LocalDeclarationsInInlineLambdasPopupLowering(context).lower(body, function)
ArrayConstructorLowering(context).lower(body, function)