JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.93k stars 1.16k forks source link

Recomposition of overridden composable method throws internal Compose exception #4491

Open dpikhulya opened 6 months ago

dpikhulya commented 6 months ago

Describe the bug

A recomposition that occurs in a composable function, which is implemented as an open method in a class, can throw an internal Compose exception (see below) in a certain configuration.

More precisely, according to the experiments, it only throws the exception when the composable method, where recomposition is triggered, is overridden in a subclass, and an instance of that subclass is used for invoking this method. See the example below.

Affected platforms

I've only been testing this on Desktop (Windows), not sure about other configurations.

Versions

To Reproduce

Run the example below and click "Recompose".

What was found to be essential in the configuration where the issue appears:

Here's an example:

import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.window.singleWindowApplication

open class A {
    @Composable
    open fun content(trigger: State<Int>) /*= workaround*/ {
        trigger.value
    }
}

class B: A() {
    @Composable
    override fun content(trigger: State<Int>): Unit = super.content(trigger)
}

@Composable
fun workaround(content: @Composable () -> Unit) {
    content()
}

fun main(): Unit = singleWindowApplication {
    val trigger = remember { mutableStateOf(0) }
    val b = remember { B() }
    b.content(trigger)

    Button(onClick = { trigger.value++ }) {
        Text("Recompose")
    }
}

NOTE: this issue can be worked around by wrapping the content of the parent method (whose recomposition triggers the problem) into an empty composable function — uncomment the /*= workaround*/ part above.

Surprisingly, I've been receiving different exceptions in seemingly the same circumstances when investigating this. Right now the most frequent exception with Compose 1.6.1 (as well as Compose 1.5.12) is the one below (full stack traces are included in the "Additional context" section below).

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Missed recording an endGroup()). Please report to Google or use https://goo.gle/compose-feedback

Another exception that I've intermittently been getting instead of the one above on Compose 1.6.1 earlier today is this one:

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Cannot seek outside the current group (46-50)). Please report to Google or use https://goo.gle/compose-feedback

Yesterday (I believe it was exactly the same example in Copose 1.6.1 as well) I was consistently getting the following exception:

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Cannot skip the enclosing group while in an empty region). Please report to Google or use https://goo.gle/compose-feedback

Besides, in the real application (on Compose 1.5.12), which of course has a more complex implementation of both methods, I'm getting another exception (and it is fixed when using the workaround mentioned above):

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Cannot reposition while in an empty region). Please report to Google or use https://goo.gle/compose-feedback

Expected behavior

No exceptions are thrown and we're able to use composable methods just like regular composable functions.

Screenshots

Additional context

Here are full stacktraces of different exceptions that I was getting in the described scenario (note that the exceptions disappear when using the workaround mentioned above).

The "Missed recording an endGroup()" variant:

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Missed recording an endGroup()). Please report to Google or use https://goo.gle/compose-feedback
    at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:4188)
    at androidx.compose.runtime.changelist.ComposerChangeListWriter.finalizeComposition(ComposerChangeListWriter.kt:479)
    at androidx.compose.runtime.ComposerImpl.finalizeCompose(Composer.kt:3509)
    at androidx.compose.runtime.ComposerImpl.endRoot(Composer.kt:1486)
    at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3318)
    at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3266)
    at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:940)
    at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1155)
    at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:127)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:583)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:551)
    at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
    at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
    at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:163)
    at androidx.compose.ui.scene.ComposeSceneMediator$DesktopSkikoView.onRender(ComposeSceneMediator.desktop.kt:523)
    at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
    at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:49)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.scene.ComposeContainer$DesktopCoroutineExceptionHandler@56e440f4, androidx.compose.runtime.BroadcastFrameClock@2abe6108, StandaloneCoroutine{Cancelling}@6197732a, FlushCoroutineDispatcher@51c8e148]

The "Cannot seek outside the current group" variant:

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Cannot seek outside the current group (46-50)). Please report to Google or use https://goo.gle/compose-feedback
    at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:4188)
    at androidx.compose.runtime.SlotWriter.advanceBy(SlotTable.kt:3793)
    at androidx.compose.runtime.changelist.Operation$AdvanceSlotsBy.execute(Operation.kt:130)
    at androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations(Operations.kt:308)
    at androidx.compose.runtime.changelist.ChangeList.executeAndFlushAllPendingChanges(ChangeList.kt:78)
    at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:976)
    at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:1005)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:639)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:551)
    at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
    at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
    at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:163)
    at androidx.compose.ui.scene.ComposeSceneMediator$DesktopSkikoView.onRender(ComposeSceneMediator.desktop.kt:523)
    at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
    at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:49)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.scene.ComposeContainer$DesktopCoroutineExceptionHandler@56ecf211, androidx.compose.runtime.BroadcastFrameClock@55fa4cda, StandaloneCoroutine{Cancelling}@2ed416db, FlushCoroutineDispatcher@12a514a3]

The "Cannot skip the enclosing group while in an empty region" variant:

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Cannot skip the enclosing group while in an empty region). Please report to Google or use https://goo.gle/compose-feedback
    at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:4558)
    at androidx.compose.runtime.SlotReader.skipToGroupEnd(SlotTable.kt:3480)
    at androidx.compose.runtime.ComposerImpl.skipReaderToGroupEnd(Composer.kt:2746)
    at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:2759)
    at androidx.compose.material.ButtonKt.Button(Button.kt:103)
    at androidx.compose.material.ButtonKt$Button$4.invoke(Button.kt)
    at androidx.compose.material.ButtonKt$Button$4.invoke(Button.kt)
    at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:169)
    at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2469)
    at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2738)
    at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3353)
    at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3304)
    at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:781)
    at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1097)
    at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:124)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:569)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:537)
    at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
    at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
    at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:543)
    at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:178)
    at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:177)
    at androidx.compose.ui.awt.ComposeBridge.catchExceptions(ComposeBridge.desktop.kt:150)
    at androidx.compose.ui.awt.ComposeBridge.access$catchExceptions(ComposeBridge.desktop.kt:64)
    at androidx.compose.ui.awt.ComposeBridge$skikoView$1.onRender(ComposeBridge.desktop.kt:177)
    at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
    at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:49)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.awt.ComposeBridge$coroutineExceptionHandler$1@1da0db4c, androidx.compose.runtime.BroadcastFrameClock@7719ae35, StandaloneCoroutine{Cancelling}@5bbddaf9, FlushCoroutineDispatcher@6ebaccff]

The "Cannot reposition while in an empty region" variant:

Exception in thread "AWT-EventQueue-0" androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Cannot reposition while in an empty region). Please report to Google or use https://goo.gle/compose-feedback
    at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:4558)
    at androidx.compose.runtime.SlotReader.reposition(SlotTable.kt:3485)
    at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2442)
    at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:2761)
    at androidx.compose.material3.TextFieldKt.TextField(TextField.kt:334)
    at androidx.compose.material3.TextFieldKt$TextField$6.invoke(TextField.kt)
    at androidx.compose.material3.TextFieldKt$TextField$6.invoke(TextField.kt)
    at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:169)
    at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2469)
    at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:2761)
    at io.appname.elements.layout.CommandWizardPage$content$1$2$1$1.invoke(CommandWizard.kt:126)
    at io.appname.elements.layout.CommandWizardPage$content$1$2$1$1.invoke(CommandWizard.kt:125)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:117)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
    at io.appname.elements.form.MultipartFormScopeImpl.FormPart(MessageFormScopes.kt:91)
    at io.appname.elements.form.MultipartFormScope$DefaultImpls.FormPart(MessageFormScopes.kt:71)
    at io.appname.elements.form.MultipartFormScopeImpl.FormPart(MessageFormScopes.kt:80)
    at io.appname.elements.form.MessageForm$Form$1.invoke(MessageFormClass.kt:764)
    at io.appname.elements.form.MessageForm$Form$1.invoke(MessageFormClass.kt:763)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:117)
    at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35)
    at io.appname.elements.form.MessageForm.MultipartForm(MessageFormClass.kt:804)
    at io.appname.elements.form.MessageForm$MultipartForm$2.invoke(MessageFormClass.kt)
    at io.appname.elements.form.MessageForm$MultipartForm$2.invoke(MessageFormClass.kt)
    at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:169)
    at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2469)
    at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2738)
    at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3353)
    at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3304)
    at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:781)
    at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1097)
    at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:124)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:569)
    at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:537)
    at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
    at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
    at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:543)
    at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:178)
    at androidx.compose.ui.awt.ComposeBridge$skikoView$1$onRender$1.invoke(ComposeBridge.desktop.kt:177)
    at androidx.compose.ui.awt.ComposeBridge.catchExceptions(ComposeBridge.desktop.kt:150)
    at androidx.compose.ui.awt.ComposeBridge.access$catchExceptions(ComposeBridge.desktop.kt:64)
    at androidx.compose.ui.awt.ComposeBridge$skikoView$1.onRender(ComposeBridge.desktop.kt:177)
    at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
    at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:49)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
    at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
    Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.awt.ComposeBridge$coroutineExceptionHandler$1@1d2f5751, androidx.compose.runtime.BroadcastFrameClock@207de29, StandaloneCoroutine{Cancelling}@38cbfbe9, FlushCoroutineDispatcher@6b462584]

P.S.: I've also earlier reported this issue using the link in the exception (see here: https://issuetracker.google.com/issues/329477544), but then realized it formally seems more appropriate here, since I've faced this issue in Compose Desktop.

eymar commented 6 months ago

Thanks for reporting! It's reproducible on Android as well (using kotlin 1.9.22 and kotlinCompilerExtensionVersion = "1.5.10"):

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val trigger = remember { mutableStateOf(0) }
            val b = remember { B() }
            b.content(trigger)

            Button(onClick = { trigger.value++ }) {
                Text("Recompose")
            }
        }
    }
}

open class A {
    @Composable
    open fun content(trigger: State<Int>) /*= workaround*/ {
        trigger.value
    }
}

class B: A() {
    @Composable
    override fun content(trigger: State<Int>): Unit = super.content(trigger)
}

@Composable
fun workaround(content: @Composable () -> Unit) {
    content()
}
androidx.compose.runtime.ComposeRuntimeError: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Cannot skip the enclosing group while in an empty region). Please report to Google or use https://goo.gle/compose-feedback
                                                                                                        at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:4557)
                                                                                                        at androidx.compose.runtime.SlotReader.skipToGroupEnd(SlotTable.kt:3480)
                                                                                                        at androidx.compose.runtime.ComposerImpl.skipReaderToGroupEnd(Composer.kt:2745)
                                                                                                        at androidx.compose.runtime.ComposerImpl.skipToGroupEnd(Composer.kt:2758)
                                                                                                        at androidx.compose.material3.ButtonKt.Button(Button.kt:957)
                                                                                                        at androidx.compose.material3.ButtonKt$Button$4.invoke(Unknown Source:31)
                                                                                                        at androidx.compose.material3.ButtonKt$Button$4.invoke(Unknown Source:10)
                                                                                                        at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:169)
                                                                                                        at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2468)
                                                                                                        at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2737)
                                                                                                        at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3352)
                                                                                                        at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:3303)
                                                                                                        at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:781)
                                                                                                        at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1097)
                                                                                                        at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:124)
                                                                                                        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:569)
                                                                                                        at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:537)
                                                                                                        at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:41)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
                                                                                                        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
                                                                                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1337)
                                                                                                        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1348)
                                                                                                        at android.view.Choreographer.doCallbacks(Choreographer.java:952)
                                                                                                        at android.view.Choreographer.doFrame(Choreographer.java:878)
                                                                                                        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1322)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:958)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:205)
                                                                                                        at android.os.Looper.loop(Looper.java:294)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8177)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

Therefore, it was correct that you reported it at google's tracker - https://issuetracker.google.com/issues/329477544 (If it affects android as well, then it's better to report there).

okushnikov commented 3 weeks ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.