cashapp / cashapp/molecule

Method Resolution failing across modules when @Composable fun has a @Composable lambda and called within launchMolecule

Open
#91 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Kotlin
Stars
2.2k
Forks
116
Avg merge
1h 36m
Merged PRs (30d)
8

Description

Reproducing project is here: https://github.com/steve-the-edwards/reproductions/tree/main/overridetest

```
abstract class AndroidLibAbstractClass {
@Composable
abstract fun AComposableWithLambda(
input1: I1,
input2: I2,
hoistState: @Composable (T) -> Unit
): Unit

@Composable
abstract fun AComposableWithoutLambda(
input1: I1,
input2: I2,
): Unit
}

@Composable fun AndroidLibComposableWithLambda(
i1: I1,
i2: I2,
objectWithComposables: AndroidLibAbstractClass
): T? {
val payload: MutableState = remember { mutableStateOf(null) }
objectWithComposables.AComposableWithLambda(i1, i2) @Composable {
payload.value = it
}
return payload.value
}

@Composable fun AndroidLibComposableWithoutLambda(
i1: I1,
i2: I2,
objectWithComposables: AndroidLibAbstractClass
): Unit {
objectWithComposables.AComposableWithoutLambda(i1, i2)
}
```

Are defined in android-lib-module.

In the app module, a concrete child class of `AndroidLibAbstractClass` _can be used successfully_ in a Compose UI composition.

However, in the `launchMolecule` composition (see `MethodResolutionTest`) this fails on `AndroidLibComposableWithLambda`:

```
private class AndroidAppConcreteTestClass(
private val payload: String
) : AndroidLibAbstractClass() {
@Composable
public override fun AComposableWithLambda(
input1: Unit,
input2: String,
hoistState: @Composable (s: String) -> Unit
) {
println("Can you hear me now? $payload")
hoistState(payload + input2)
}

@Composable
override fun AComposableWithoutLambda(
input1: Unit,
input2: String
) {
}
}

@Test fun testMethodResolution() {
val objectUnderTest = AndroidAppConcreteTestClass("a test")
val broadcastFrameClock = BroadcastFrameClock {}
val testScope = CoroutineScope(broadcastFrameClock)

val testFlow = testScope.launchMolecule {
AndroidLibComposableWithoutLambda(Unit, " again", objectUnderTest)
AndroidLibComposableWithLambda(Unit, " again", objectUnderTest)
}

assert(testFlow.value.contentEquals("a test again"))
}
```

because it gets an AbstractMethodError as it cannot resolve the concrete class's override at runtime?

Originally I thought it might be because I was using the 0.3.0-SNAPSHOT and the common KMP artifacts so I include a module with that example as well, but I was able to reproduce it with just 0.2.0 while all in Android/JVM.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the reproducing project in steve-the-edwards/reproductions/overridetest and the MethodResolutionTest described in the issue. Run the launchMolecule test and compare method resolution for the composable with a lambda against the version without one. Done means the concrete override resolves without AbstractMethodError and the assertion passes.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile-dev, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.