Open dpikhulya opened 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).
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
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:
A.content()
).B.content()
(just invoking super method is enough in the overridden method).A.content()
).B
in this case.Here's an example:
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).
Another exception that I've intermittently been getting instead of the one above on Compose 1.6.1 earlier today is this one:
Yesterday (I believe it was exactly the same example in Copose 1.6.1 as well) I was consistently getting the following exception:
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):
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:
The "Cannot seek outside the current group" variant:
The "Cannot skip the enclosing group while in an empty region" variant:
The "Cannot reposition while in an empty region" variant:
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.