Use composer of the correct scope when realizing groups

Updates function body transform to use composer parameter from target scope to realize groups. The realize call can happen outside of such scope and composer parameter is not guaranteed to be the same between scope where groups are being realize and current scope at the time of the call.

Test: CompositionTests
Fixes: 274786923
Change-Id: I0cc3c7be151edb7cbbe4114fffbde8736f7ec428
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
index 3829597..82dcf95 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
@@ -309,7 +309,7 @@
                     if (isTraceInProgress()) {
                       traceEventEnd()
                     }
-                    %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                    %composer@Test.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                       Test(condition, %composer, updateChangedFlags(%changed or 0b0001))
                     }
                     return
@@ -381,7 +381,7 @@
                     if (isTraceInProgress()) {
                       traceEventEnd()
                     }
-                    %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                    %composer@Test.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                       Test(a, b, %composer, updateChangedFlags(%changed or 0b0001))
                     }
                     return
@@ -397,7 +397,7 @@
                     if (isTraceInProgress()) {
                       traceEventEnd()
                     }
-                    %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                    %composer@Test.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                       Test(a, b, %composer, updateChangedFlags(%changed or 0b0001))
                     }
                     return
@@ -705,7 +705,7 @@
                       if (isTraceInProgress()) {
                         traceEventEnd()
                       }
-                      %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                      %composer@testInline_M1_W_Return_Func.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                         testInline_M1_W_Return_Func(condition, %composer, updateChangedFlags(%changed or 0b0001))
                       }
                       return
@@ -852,7 +852,7 @@
                       if (isTraceInProgress()) {
                         traceEventEnd()
                       }
-                      %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                      %composer@test_CM1_CCM1_RetFun.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                         test_CM1_CCM1_RetFun(condition, %composer, updateChangedFlags(%changed or 0b0001))
                       }
                       return
@@ -1330,7 +1330,7 @@
                     if (isTraceInProgress()) {
                       traceEventEnd()
                     }
-                    %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                    %composer@test_CM1_RetFun.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                       test_CM1_RetFun(condition, %composer, updateChangedFlags(%changed or 0b0001))
                     }
                     return
@@ -6287,4 +6287,59 @@
         }
         """
     )
+
+    @Test
+    fun testEarlyReturnFromCrossInlinedLambda() = verifyComposeIrTransform(
+        source = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            private fun Test(param: String?) {
+                Dialog {
+                    if (false) Test(param)
+                }
+            }
+        """,
+        extra = """
+            import androidx.compose.runtime.*
+
+            @Composable
+            internal inline fun Dialog(crossinline block: @Composable () -> Unit) {}
+        """.trimIndent(),
+        expectedTransformed = """
+           @Composable
+           private fun Test(param: String?, %composer: Composer?, %changed: Int) {
+             %composer = %composer.startRestartGroup(<>)
+             sourceInformation(%composer, "C(Test)<Dialog>:Test.kt")
+             val %dirty = %changed
+             if (%changed and 0b1110 === 0) {
+               %dirty = %dirty or if (%composer.changed(param)) 0b0100 else 0b0010
+             }
+             if (%dirty and 0b1011 !== 0b0010 || !%composer.skipping) {
+               if (isTraceInProgress()) {
+                 traceEventStart(<>, %dirty, -1, <>)
+               }
+               Dialog({ %composer: Composer?, %changed: Int ->
+                 sourceInformationMarkerStart(%composer, <>, "C:Test.kt")
+                 %composer.startReplaceableGroup(<>)
+                 sourceInformation(%composer, "<Test(p...>")
+                 if (false) {
+                   Test(param, %composer, 0b1110 and %dirty)
+                 }
+                 %composer.endReplaceableGroup()
+                 sourceInformationMarkerEnd(%composer)
+               }, %composer, 0)
+               if (isTraceInProgress()) {
+                 traceEventEnd()
+               }
+             } else {
+               %composer.skipToGroupEnd()
+             }
+             %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+               Test(param, %composer, updateChangedFlags(%changed or 0b0001))
+             }
+           }
+        """.trimIndent(),
+        dumpTree = true
+    )
 }
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
index b4e644c..edd8cf3 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
@@ -1489,7 +1489,7 @@
                       traceEventStart(<>, %changed, -1, <>)
                     }
                     used(it)
-                    A(x, 0, %composer, 0b1110 and %dirty, 0b0010)
+                    A(x, 0, %composer, 0b1110 and %dirty@Test, 0b0010)
                     if (isTraceInProgress()) {
                       traceEventEnd()
                     }
@@ -2792,7 +2792,7 @@
                         if (isTraceInProgress()) {
                           traceEventStart(<>, %dirty, -1, <>)
                         }
-                        B(x, y, z, %composer, 0b1110 and %dirty or 0b01110000 and %dirty shl 0b0011 or 0b001110000000 and %dirty shl 0b0110, 0)
+                        B(x, y, z, %composer, 0b1110 and %dirty@A or 0b01110000 and %dirty@A.<anonymous> shl 0b0011 or 0b001110000000 and %dirty shl 0b0110, 0)
                         if (isTraceInProgress()) {
                           traceEventEnd()
                         }
@@ -2800,7 +2800,7 @@
                         %composer.skipToGroupEnd()
                       }
                     }, %composer, 0b0110)
-                    B(x, y, 0, %composer, 0b1110 and %dirty or 0b01110000 and %dirty shl 0b0011, 0b0100)
+                    B(x, y, 0, %composer, 0b1110 and %dirty@A or 0b01110000 and %dirty shl 0b0011, 0b0100)
                     if (isTraceInProgress()) {
                       traceEventEnd()
                     }
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt
index 90b67be..b7d9f1b 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TargetAnnotationsTransformTests.kt
@@ -911,7 +911,7 @@
           val tmp0_measurePolicy = localBoxMeasurePolicy
           Layout({ %composer: Composer?, %changed: Int ->
             sourceInformationMarkerStart(%composer, <>, "C<conten...>:Test.kt")
-            content(LocalBoxScopeInstance, %composer, 0b0110 or 0b01110000 and %changed)
+            content(LocalBoxScopeInstance, %composer, 0b0110 or 0b01110000 and %changed@LocalBox)
             sourceInformationMarkerEnd(%composer)
           }, modifier, tmp0_measurePolicy, %composer, 0b000110000000 or 0b01110000 and %changed shl 0b0011, 0)
           %composer.endReplaceableGroup()
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt
index fe08eba..0a5b091 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TraceInformationTest.kt
@@ -136,7 +136,7 @@
                     if (isTraceInProgress()) {
                       traceEventEnd()
                     }
-                    %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                    %composer@Test.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
                       Test(condition, %composer, updateChangedFlags(%changed or 0b0001))
                     }
                     return
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index 05236bc..0dd6696 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -888,7 +888,7 @@
             scope.realizeGroup {
                 irComposite(statements = listOfNotNull(
                     if (emitTraceMarkers) irTraceEventEnd() else null,
-                    irEndReplaceableGroup()
+                    irEndReplaceableGroup(scope = scope)
                 ))
             }
         }
@@ -916,9 +916,9 @@
                 *bodyPreamble.statements.toTypedArray(),
                 *transformed.statements.toTypedArray(),
                 when {
-                    !elideGroups -> irEndReplaceableGroup()
+                    !elideGroups -> irEndReplaceableGroup(scope = scope)
                     collectSourceInformation && !hasExplicitGroups ->
-                        irSourceInformationMarkerEnd(body)
+                        irSourceInformationMarkerEnd(body, scope)
                     else -> null
                 },
                 returnVar?.let { irReturn(declaration.symbol, irGet(it)) }
@@ -926,7 +926,7 @@
         )
         if (elideGroups && !hasExplicitGroups && collectSourceInformation) {
             scope.realizeEndCalls {
-                irSourceInformationMarkerEnd(body)
+                irSourceInformationMarkerEnd(body, scope)
             }
         }
 
@@ -970,7 +970,7 @@
                 sourceInformationPreamble.statements.add(
                     irSourceInformationMarkerStart(body, scope)
                 )
-                bodyEpilogue.statements.add(irSourceInformationMarkerEnd(body))
+                bodyEpilogue.statements.add(irSourceInformationMarkerEnd(body, scope))
             } else {
                 sourceInformationPreamble.statements.add(irSourceInformation(scope))
             }
@@ -1042,7 +1042,7 @@
 
         if (collectSourceInformation && isInlineLambda) {
             scope.realizeEndCalls {
-                irSourceInformationMarkerEnd(body)
+                irSourceInformationMarkerEnd(body, scope)
             }
         }
 
@@ -1588,7 +1588,7 @@
                 )
 
                 // composer.endMovableGroup()
-                skipPreamble.statements.add(irEndMovableGroup())
+                skipPreamble.statements.add(irEndMovableGroup(scope))
 
                 // if (dirty and 0b0110 === 0) {
                 //   dirty = dirty or 0b0010
@@ -1763,7 +1763,7 @@
             statements = listOfNotNull(
                 outerReceiver,
                 irSafeCall(
-                    irEndRestartGroup(),
+                    irEndRestartGroup(scope),
                     updateScopeFunction.symbol,
                     lambda
                 ),
@@ -1910,6 +1910,12 @@
         )
     }
 
+    private fun Scope.BlockScope.irCurrentComposer(
+        startOffset: Int = UNDEFINED_OFFSET,
+        endOffset: Int = UNDEFINED_OFFSET,
+    ): IrExpression =
+        irCurrentComposer(startOffset, endOffset, nearestComposer ?: nearestComposer())
+
     private fun IrElement.sourceKey(): Int {
         var hash = currentFunctionScope
             .function
@@ -1958,7 +1964,7 @@
     ): IrExpression {
         return irWithSourceInformation(
             irMethodCall(
-                irCurrentComposer(startOffset, endOffset),
+                scope.irCurrentComposer(startOffset, endOffset),
                 startReplaceableFunction,
                 startOffset,
                 endOffset
@@ -1982,7 +1988,7 @@
         val sourceInformation = irCall(
             sourceInformationFunction
         ).also {
-            it.putValueArgument(0, irCurrentComposer())
+            it.putValueArgument(0, scope.irCurrentComposer())
         }
         recordSourceParameter(sourceInformation, 1, scope)
         return sourceInformation
@@ -1998,7 +2004,7 @@
             element.startOffset,
             element.endOffset
         ).also {
-            it.putValueArgument(0, irCurrentComposer())
+            it.putValueArgument(0, scope.irCurrentComposer())
             it.putValueArgument(1, key)
             recordSourceParameter(it, 2, scope)
         }
@@ -2048,13 +2054,14 @@
 
     private fun irSourceInformationMarkerEnd(
         element: IrElement,
+        scope: Scope.BlockScope
     ): IrExpression {
         return irCall(
             sourceInformationMarkerEndFunction,
             element.startOffset,
             element.endOffset
         ).also {
-            it.putValueArgument(0, irCurrentComposer())
+            it.putValueArgument(0, scope.irCurrentComposer())
         }
     }
 
@@ -2076,7 +2083,7 @@
             irSet(
                 nearestComposer(),
                 irMethodCall(
-                    irCurrentComposer(),
+                    scope.irCurrentComposer(),
                     startRestartGroupFunction,
                     element.startOffset,
                     element.endOffset
@@ -2088,8 +2095,8 @@
         )
     }
 
-    private fun irEndRestartGroup(): IrExpression {
-        return irMethodCall(irCurrentComposer(), endRestartGroupFunction)
+    private fun irEndRestartGroup(scope: Scope.BlockScope): IrExpression {
+        return irMethodCall(scope.irCurrentComposer(), endRestartGroupFunction)
     }
 
     private fun irCache(
@@ -2147,10 +2154,11 @@
 
     private fun irEndReplaceableGroup(
         startOffset: Int = UNDEFINED_OFFSET,
-        endOffset: Int = UNDEFINED_OFFSET
+        endOffset: Int = UNDEFINED_OFFSET,
+        scope: Scope.BlockScope
     ): IrExpression {
         return irMethodCall(
-            irCurrentComposer(startOffset, endOffset),
+            scope.irCurrentComposer(startOffset, endOffset),
             endReplaceableFunction,
             startOffset,
             endOffset
@@ -2168,7 +2176,7 @@
     ): IrExpression {
         return irWithSourceInformation(
             irMethodCall(
-                irCurrentComposer(),
+                scope.irCurrentComposer(),
                 startMovableFunction,
                 element.startOffset,
                 element.endOffset
@@ -2180,12 +2188,12 @@
         )
     }
 
-    private fun irEndMovableGroup(): IrExpression {
-        return irMethodCall(irCurrentComposer(), endMovableFunction)
+    private fun irEndMovableGroup(scope: Scope.BlockScope): IrExpression {
+        return irMethodCall(scope.irCurrentComposer(), endMovableFunction)
     }
 
-    private fun irEndToMarker(marker: IrExpression): IrExpression {
-        return irMethodCall(irCurrentComposer(), endToMarkerFunction!!).apply {
+    private fun irEndToMarker(marker: IrExpression, scope: Scope.BlockScope): IrExpression {
+        return irMethodCall(scope.irCurrentComposer(), endToMarkerFunction!!).apply {
             putValueArgument(0, marker)
         }
     }
@@ -2273,7 +2281,9 @@
 
     private fun IrBlock.withReplaceableGroupStatements(scope: Scope.BlockScope): IrExpression {
         currentFunctionScope.metrics.recordGroup()
-        scope.realizeGroup(::irEndReplaceableGroup)
+        scope.realizeGroup {
+            irEndReplaceableGroup(scope = scope)
+        }
         return when {
             // if the scope ends with a return call, then it will get properly ended if we
             // just push the end call on the scope because of the way returns get transformed in
@@ -2299,7 +2309,7 @@
                         startOffset = startOffset,
                         endOffset = endOffset
                     )
-                ) + statements + listOf(irEndReplaceableGroup(startOffset, endOffset))
+                ) + statements + listOf(irEndReplaceableGroup(startOffset, endOffset, scope))
             )
         }
     }
@@ -2319,11 +2329,13 @@
                         startOffset = startOffset,
                         endOffset = endOffset,
                     ),
-                    irEndReplaceableGroup(startOffset, endOffset)
+                    irEndReplaceableGroup(startOffset, endOffset, scope)
                 )
             )
         }
-        scope.realizeGroup(::irEndReplaceableGroup)
+        scope.realizeGroup {
+            irEndReplaceableGroup(scope = scope)
+        }
         return when {
             // if the scope ends with a return call, then it will get properly ended if we
             // just push the end call on the scope because of the way returns get transformed in
@@ -2343,7 +2355,7 @@
                             endOffset = endOffset
                         )
                     ),
-                    after = listOf(irEndReplaceableGroup(startOffset, endOffset))
+                    after = listOf(irEndReplaceableGroup(startOffset, endOffset, scope))
                 )
             }
         }
@@ -2402,10 +2414,12 @@
                 if (before.statements.isEmpty()) {
                     metrics.recordGroup()
                     before.statements.add(irStartReplaceableGroup(this, scope))
-                    after.statements.add(irEndReplaceableGroup())
+                    after.statements.add(irEndReplaceableGroup(scope = scope))
                 }
             },
-            makeEnd = ::irEndReplaceableGroup
+            makeEnd = {
+                irEndReplaceableGroup(scope = scope)
+            }
         )
         return wrap(
             listOf(before),
@@ -2526,13 +2540,14 @@
                             scope.markReturn(extraEndLocation)
                         } else {
                             val functionScope = scope
+                            val targetScope = currentScope as? Scope.BlockScope ?: functionScope
                             if (functionScope.isInlinedLambda) {
                                 val marker = irGet(functionScope.allocateMarker())
-                                extraEndLocation(irEndToMarker(marker))
+                                extraEndLocation(irEndToMarker(marker, targetScope))
                             } else {
                                 val marker = functionScope.allocateMarker()
                                 functionScope.markReturn {
-                                    extraEndLocation(irEndToMarker(irGet(marker)))
+                                    extraEndLocation(irEndToMarker(irGet(marker), targetScope))
                                     extraEndLocation(it)
                                 }
                             }
@@ -3186,7 +3201,7 @@
                     scope
                 ),
                 block,
-                irEndMovableGroup(),
+                irEndMovableGroup(scope),
                 after,
                 resultVar?.let { irGet(resultVar) }
             )
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
index dd2a8ed..4782eb0 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
@@ -39,6 +39,7 @@
 import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
 import org.jetbrains.kotlin.ir.declarations.IrTypeAlias
 import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
+import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
 import org.jetbrains.kotlin.ir.declarations.IrValueParameter
 import org.jetbrains.kotlin.ir.declarations.IrVariable
 import org.jetbrains.kotlin.ir.expressions.IrBlock
@@ -106,6 +107,7 @@
 import org.jetbrains.kotlin.ir.util.isAnnotationClass
 import org.jetbrains.kotlin.ir.util.isInterface
 import org.jetbrains.kotlin.ir.util.isObject
+import org.jetbrains.kotlin.ir.util.kotlinFqName
 import org.jetbrains.kotlin.ir.util.parentAsClass
 import org.jetbrains.kotlin.ir.util.primaryConstructor
 import org.jetbrains.kotlin.ir.util.statements
@@ -131,11 +133,17 @@
         .replace(Regex("}\\n(\\s)*,", RegexOption.MULTILINE), "},")
 }
 
+class Scope(
+    val owner: IrFunction? = null,
+    val localValues: HashSet<IrValueDeclaration> = hashSetOf()
+)
+
 class IrSourcePrinterVisitor(
     out: Appendable,
     indentUnit: String = "  ",
 ) : IrElementVisitorVoid {
     private val printer = Printer(out, indentUnit)
+    private var currentScope: Scope = Scope()
 
     private fun IrElement.print() {
         accept(this@IrSourcePrinterVisitor, null)
@@ -146,6 +154,18 @@
 
     fun printType(type: IrType) = type.renderSrc()
 
+    private inline fun IrFunction.scoped(block: (IrFunction) -> Unit) {
+        val previousScope = currentScope
+        currentScope = Scope(
+            this,
+            HashSet(valueParameters)
+        )
+
+        block(this)
+
+        currentScope = previousScope
+    }
+
     private inline fun indented(body: () -> Unit) {
         printer.pushIndent()
         body()
@@ -197,47 +217,49 @@
 
     override fun visitSimpleFunction(declaration: IrSimpleFunction) {
         if (declaration.origin == IrDeclarationOrigin.FAKE_OVERRIDE) return
-        declaration.printAnnotations(onePerLine = true)
-        if (declaration.overriddenSymbols.isNotEmpty()) {
-            print("override ")
-        } else {
-            if (
-                declaration.visibility != DescriptorVisibilities.PUBLIC &&
-                declaration.visibility != DescriptorVisibilities.LOCAL
-            ) {
-                print(declaration.visibility.toString().lowercase(Locale.ROOT))
-                print(" ")
+        declaration.scoped {
+            declaration.printAnnotations(onePerLine = true)
+            if (declaration.overriddenSymbols.isNotEmpty()) {
+                print("override ")
+            } else {
+                if (
+                    declaration.visibility != DescriptorVisibilities.PUBLIC &&
+                    declaration.visibility != DescriptorVisibilities.LOCAL
+                ) {
+                    print(declaration.visibility.toString().lowercase(Locale.ROOT))
+                    print(" ")
+                }
+                if (declaration.modality != Modality.FINAL) {
+                    print(declaration.modality.toString().lowercase(Locale.ROOT))
+                    print(" ")
+                }
             }
-            if (declaration.modality != Modality.FINAL) {
-                print(declaration.modality.toString().lowercase(Locale.ROOT))
-                print(" ")
+            if (declaration.isSuspend) {
+                print("suspend ")
             }
+            print("fun ")
+            if (declaration.typeParameters.isNotEmpty()) {
+                print("<")
+                declaration.typeParameters.printJoin(", ")
+                print("> ")
+            }
+            declaration.extensionReceiverParameter?.let {
+                print(it.type.renderSrc())
+                print(".")
+            }
+            print(declaration.name)
+            print("(")
+            declaration.valueParameters.printJoin(", ")
+            print(")")
+            if (!declaration.returnType.isUnit()) {
+                print(": ")
+                print(
+                    declaration.returnType.renderSrc()
+                )
+            }
+            print(" ")
+            declaration.printBody()
         }
-        if (declaration.isSuspend) {
-            print("suspend ")
-        }
-        print("fun ")
-        if (declaration.typeParameters.isNotEmpty()) {
-            print("<")
-            declaration.typeParameters.printJoin(", ")
-            print("> ")
-        }
-        declaration.extensionReceiverParameter?.let {
-            print(it.type.renderSrc())
-            print(".")
-        }
-        print(declaration.name)
-        print("(")
-        declaration.valueParameters.printJoin(", ")
-        print(")")
-        if (!declaration.returnType.isUnit()) {
-            print(": ")
-            print(
-                declaration.returnType.renderSrc()
-            )
-        }
-        print(" ")
-        declaration.printBody()
     }
 
     fun IrFunction.printBody() {
@@ -551,20 +573,22 @@
     }
 
     fun IrFunction.printAsLambda() {
-        print("{")
-        val parameters = valueParameters
-        if (parameters.isNotEmpty()) {
-            print(" ")
-            parameters.printJoin(", ")
-            println(" ->")
-        } else {
+        scoped {
+            print("{")
+            val parameters = valueParameters
+            if (parameters.isNotEmpty()) {
+                print(" ")
+                parameters.printJoin(", ")
+                println(" ->")
+            } else {
+                println()
+            }
+            indented {
+                body?.print()
+            }
             println()
+            println("}")
         }
-        indented {
-            body?.print()
-        }
-        println()
-        println("}")
     }
 
     override fun visitTypeOperator(expression: IrTypeOperatorCall) {
@@ -855,6 +879,8 @@
     }
 
     override fun visitVariable(declaration: IrVariable) {
+        currentScope.localValues.add(declaration)
+
         if (declaration.isLateinit) {
             print("lateinit")
         }
@@ -875,7 +901,16 @@
     }
 
     override fun visitGetValue(expression: IrGetValue) {
-        print(expression.symbol.owner.name)
+        val owner = expression.symbol.owner
+        print(owner.name)
+
+        if (
+            owner.parent != currentScope.owner &&
+            currentScope.localValues.any { it.name == owner.name }
+        ) {
+            print("@")
+            print(owner.parent.kotlinFqName)
+        }
     }
 
     override fun visitField(declaration: IrField) {
@@ -964,7 +999,7 @@
             }
         }
         indented {
-            declaration.getter?.let {
+            declaration.getter?.scoped {
                 if (it.origin != IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) {
                     println()
                     it.printAnnotations()
@@ -977,7 +1012,7 @@
                     println("}")
                 }
             }
-            declaration.setter?.let {
+            declaration.setter?.scoped {
                 if (it.origin != IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR) {
                     println()
                     it.printAnnotations()
diff --git a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
index bcf5e0f..9c514dc 100644
--- a/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
+++ b/compose/runtime/runtime/src/commonTest/kotlin/androidx/compose/runtime/CompositionTests.kt
@@ -3690,6 +3690,30 @@
         assertEquals(2, i2)
         assertEquals(3, i3)
     }
+
+    @Test
+    fun test_crossinline_differentComposition() = compositionTest {
+        var branch by mutableStateOf(false)
+        compose {
+            if (branch) {
+                Text("Content")
+            }
+            InlineSubcomposition {
+                if (false) {
+                    remember { "Something" }
+                }
+            }
+        }
+        validate {
+            if (branch) {
+                Text("Content")
+            }
+        }
+
+        branch = true
+        expectChanges()
+        revalidate()
+    }
 }
 
 class SomeUnstableClass(val a: Any = "abc")
@@ -3936,4 +3960,9 @@
 
 private inline fun MockViewValidator.simulatedIf(condition: Boolean, block: () -> Unit) {
     if (condition) block()
-}
\ No newline at end of file
+}
+
+@Composable
+private inline fun InlineSubcomposition(
+    crossinline content: @Composable () -> Unit
+) = TestSubcomposition { content() }
\ No newline at end of file