Turn on Composer Param rewriting code generation strategy
relnote: “Updated the `ComposeFlags.COMPOSER_PARAM` flag to be `true`, which will change the code generation strategy for the compose plugin. At a high level, this causes @Composable functions to be generated with an additional synthetic parameter, which is passed through to subsequent @Composable calls in order for the runtime to properly manage execution. This is a significant binary breaking change, however, should preserve source-level compatibility in all sanctioned usage of compose.”
This effort has been a work in progress for some time, and most of the code which this flag enables has been added in previous commits. Links to these commits can be found below:
Fix final composables in non-final classes (52, 0)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1224219
Fix a few corner cases that break the composer param flag (19, 15)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1220520
Fix dex naming corner cases in compose runtime (65, 18)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1224216
Fix inlining with composer param flag (201, 4)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1221901
Fix inner class transforms with Composer Param (81, 5)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1218286
Fix inline property getters with Composer Param (147, 8)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1218287
Fix multifile symbol remapping issue (514, 327)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1217405
Refactor Composer Param flag to not depend on SyntheticIrExtension (83, 100)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1215921
Refactor ObservePatcher to work with Composer Param (617, 289)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1215621
Fix orphanned symbols from composer param transforms (133, 1)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1214982
Add Model class generation phase with Composer Param (4, 2)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1214983
Fix inlining for composer param codegen (145, 66)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1212446
Run all passing tests with Composer Param flag on and off (341, 289)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1211287
Remove Component and refactor top-level composition APIs (1489, 3531)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1209009
Transform composable calls with composer param (500, 170)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1208485
Cross-module composer param with synthetic decoys (561, 62)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1206252
Remove Composition classes in favor of Composer base class (294, 464)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1204929
Guard for circular composable references in param transformer (21, 3)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1205292
Add tests for composability of different function scopes (227, 0)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1201582
Add a few more composer param tests (100, 0)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1202047
Add currentComposerIntrinsic and tests to ensure correct param passing (272, 19)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1202044
Make composable invoke outside of composable scope error (20, 10)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1202042
Basic Composer Param Rewriting (754, 0)
https://android-review.googlesource.com/c/platform/frameworks/support/+/1196950
Change-Id: I7971ca1b6525440c38643953645fa388131e31f0
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCodegenSignatureTest.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCodegenSignatureTest.kt
index d83c2ec..97a4cdd 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCodegenSignatureTest.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCodegenSignatureTest.kt
@@ -24,6 +24,41 @@
import org.robolectric.Robolectric
import java.net.URLClassLoader
+
+fun printPublicApi(classDump: String, name: String): String {
+ return classDump
+ .splitToSequence("\n")
+ .filter {
+ if (it.contains("INVOKESTATIC kotlin/internal/ir/Intrinsic")) {
+ // if instructions like this end up in our generated code, it means something
+ // went wrong. Usually it means that it just can't find the function to call,
+ // so it transforms it into this intrinsic call instead of failing. If this
+ // happens, we want to hard-fail the test as the code is definitely incorrect.
+ error(
+ buildString {
+ append("An unresolved call was found in the generated bytecode of '")
+ append(name)
+ append("'")
+ appendln()
+ appendln()
+ appendln("Call was: $it")
+ appendln()
+ appendln("Entire class file output:")
+ appendln(classDump)
+ }
+ )
+ }
+ if (it.startsWith(" ")) {
+ if (it.startsWith(" ")) false
+ else it[2] != '/' && it[2] != '@'
+ } else {
+ it == "}" || it.endsWith("{")
+ }
+ }
+ .joinToString(separator = "\n")
+ .replace('$', '%') // replace $ to % to make comparing it to kotlin string literals easier
+}
+
abstract class AbstractCodegenSignatureTest : AbstractCodegenTest() {
private var isSetup = false
@@ -38,37 +73,7 @@
}
private fun OutputFile.printApi(): String {
- val text = asText()
- return text
- .splitToSequence("\n")
- .filter {
- if (it.contains("INVOKESTATIC kotlin/internal/ir/Intrinsic")) {
- // if instructions like this end up in our generated code, it means something
- // went wrong. Usually it means that it just can't find the function to call,
- // so it transforms it into this intrinsic call instead of failing. If this
- // happens, we want to hard-fail the test as the code is definitely incorrect.
- error(
- buildString {
- append("An unresolved call was found in the generated bytecode of '")
- append(this@printApi.relativePath)
- append("'")
- appendln()
- appendln()
- appendln("Call was: $it")
- appendln()
- appendln("Entire class file output:")
- appendln(text)
- }
- )
- }
- if (it.startsWith(" ")) {
- if (it.startsWith(" ")) false
- else it[2] != '/' && it[2] != '@'
- } else {
- it == "}" || it.endsWith("{")
- }
- }
- .joinToString(separator = "\n")
+ return printPublicApi(asText(), relativePath)
}
fun checkApi(src: String, expected: String, dumpClasses: Boolean = false): Unit = ensureSetup {
@@ -85,7 +90,6 @@
.allGeneratedFiles
.filter { it.relativePath.endsWith(".class") }
.map { it.printApi() }
- .map { it.replace('$', '%') }
.joinToString(separator = "\n")
.replace(className, "Test")
@@ -98,6 +102,29 @@
assertEquals(expectedApiString, apiString)
}
+ fun validateBytecode(
+ src: String,
+ dumpClasses: Boolean = false,
+ validate: (String) -> Unit): Unit = ensureSetup {
+ val className = "Test_REPLACEME_${uniqueNumber++}"
+ val fileName = "$className.kt"
+
+ val loader = classLoader("""
+ import androidx.compose.*
+
+ $src
+ """, fileName, dumpClasses)
+
+ val apiString = loader
+ .allGeneratedFiles
+ .filter { it.relativePath.endsWith(".class") }
+ .map {
+ it.asText().replace('$', '%').replace(className, "Test")
+ }.joinToString("\n")
+
+ validate(apiString)
+ }
+
fun checkComposerParam(src: String, dumpClasses: Boolean = false): Unit = ensureSetup {
val className = "Test_REPLACEME_${uniqueNumber++}"
val compiledClasses = classLoader(
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCompilerTest.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCompilerTest.kt
index 37bb611..70396db 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCompilerTest.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractCompilerTest.kt
@@ -85,11 +85,7 @@
open fun forComposerParam(vararg values: Boolean, block: () -> Unit) {
val exceptions = mutableListOf<Pair<Boolean, Throwable>>()
- val valuesToRun = if (INVERT_COMPOSER_PARAM_TESTS) {
- if (values.size == 2) error("Intentional failure to make success indicate a change")
- arrayOf(true) // assume if there is just one value provided that it was "false"
- } else
- values.toTypedArray()
+ val valuesToRun = arrayOf(true)
for (flag in valuesToRun) {
val prevValue = ComposeFlags.COMPOSER_PARAM
try {
@@ -282,11 +278,19 @@
companion object {
val homeDir by lazy { File(computeHomeDirectory()).absolutePath }
val projectRoot by lazy { File(homeDir, "../../../../..").absolutePath }
+ val kotlinHome by lazy {
+ File(projectRoot, "prebuilts/androidx/external/org/jetbrains/kotlin/")
+ }
+ val outDir by lazy {
+ File(System.getenv("OUT_DIR") ?: File(projectRoot, "out").absolutePath)
+ }
+ val composePluginJar by lazy {
+
+ File(outDir, "ui/compose/compose-compiler/build/jarjar/compose-compiler.jar")
+ }
fun kotlinRuntimeJar(module: String) = File(
- projectRoot,
- "prebuilts/androidx/external/org/jetbrains/kotlin/$module/" +
- "$KOTLIN_RUNTIME_VERSION/$module-$KOTLIN_RUNTIME_VERSION.jar")
+ kotlinHome, "$module/$KOTLIN_RUNTIME_VERSION/$module-$KOTLIN_RUNTIME_VERSION.jar")
init {
System.setProperty("idea.home",
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
index 9168a9a..989c5fe 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
@@ -16,3 +16,147 @@
package androidx.compose.plugins.kotlin
+
+import com.intellij.openapi.util.io.FileUtil
+import org.jetbrains.kotlin.cli.common.CLICompiler
+import org.jetbrains.kotlin.cli.common.CLITool
+import org.jetbrains.kotlin.cli.common.ExitCode
+import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
+import org.jetbrains.org.objectweb.asm.ClassReader
+import org.jetbrains.org.objectweb.asm.util.TraceClassVisitor
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.io.PrintStream
+import java.io.PrintWriter
+
+// KotlinTestUtils
+private fun tmpDir(name: String): File {
+ return FileUtil.createTempDirectory(name, "", false).canonicalFile
+}
+// AbstractCliTest
+private fun executeCompilerGrabOutput(
+ compiler: CLITool<*>,
+ args: List<String>
+): Pair<String, ExitCode> {
+ val output = StringBuilder()
+
+ var index = 0
+ do {
+ var next = args.subList(index, args.size).indexOf("---")
+ if (next == -1) {
+ next = args.size
+ }
+ val (first, second) = executeCompiler(compiler, args.subList(index, next))
+ output.append(first)
+ if (second != ExitCode.OK) {
+ return Pair(output.toString(), second)
+ }
+ index = next + 1
+ } while (index < args.size)
+
+ return Pair(output.toString(), ExitCode.OK)
+}
+// CompilerTestUtil
+private fun executeCompiler(compiler: CLITool<*>, args: List<String>): Pair<String, ExitCode> {
+ val bytes = ByteArrayOutputStream()
+ val origErr = System.err
+ try {
+ System.setErr(PrintStream(bytes))
+ val exitCode = CLITool.doMainNoExit(compiler, args.toTypedArray())
+ return Pair(String(bytes.toByteArray()), exitCode)
+ }
+ finally {
+ System.setErr(origErr)
+ }
+}
+// jetTestUtils
+fun String.trimTrailingWhitespaces(): String =
+ this.split('\n').joinToString(separator = "\n") { it.trimEnd() }
+// jetTestUtils
+fun String.trimTrailingWhitespacesAndAddNewlineAtEOF(): String =
+ this.trimTrailingWhitespaces().let {
+ result -> if (result.endsWith("\n")) result else result + "\n"
+ }
+
+abstract class AbstractMultiPlatformIntegrationTest : AbstractCompilerTest() {
+ fun multiplatform(
+ common: String,
+ jvm: String,
+ output: String
+ ) {
+ setUp()
+ val tmpdir = tmpDir(getTestName(true))
+
+ assert(composePluginJar.exists())
+
+ val optionalArgs = arrayOf(
+ "-cp",
+ defaultClassPath
+ .filter { it.exists() }
+ .joinToString(File.pathSeparator) { it.absolutePath },
+ "-kotlin-home",
+ AbstractCompilerTest.kotlinHome.absolutePath,
+ "-P", "plugin:androidx.compose.plugins.idea:enabled=true",
+ "-Xplugin=${composePluginJar.absolutePath}",
+ "-Xuse-ir"
+ )
+
+ val jvmOnlyArgs = arrayOf("-no-stdlib")
+
+ val srcDir = File(tmpdir, "srcs").absolutePath
+ val commonSrc = File(srcDir, "common.kt")
+ val jvmSrc = File(srcDir, "jvm.kt")
+
+ FileUtil.writeToFile(commonSrc, common)
+ FileUtil.writeToFile(jvmSrc, jvm)
+
+ val jvmDest = File(tmpdir, "jvm").absolutePath
+
+ val result = K2JVMCompiler().compile(
+ jvmSrc,
+ commonSrc,
+ "-d", jvmDest,
+ *optionalArgs,
+ *jvmOnlyArgs
+ )
+
+ val files = File(jvmDest).listFiles()
+
+ if (files == null || files.isEmpty()) {
+ assertEquals(output.trimIndent(), result)
+ return
+ }
+
+ val sb = StringBuilder()
+
+ files
+ .filter { it.extension == "class" }
+ .sortedBy { it.absolutePath }
+ .distinctBy { it.name }
+ .forEach {
+ val os = ByteArrayOutputStream()
+ val printWriter = PrintWriter(os)
+ val writer = TraceClassVisitor(printWriter)
+ val reader = ClassReader(it.inputStream())
+ reader.accept(
+ writer,
+ ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
+ )
+ sb.append(os.toString())
+ sb.appendln()
+ }
+
+ assertEquals(output.trimIndent(), printPublicApi(sb.toString(), "test"))
+ }
+
+ private fun CLICompiler<*>.compile(sources: File, commonSources: File?, vararg mainArguments: String): String = buildString {
+ val (output, exitCode) = executeCompilerGrabOutput(
+ this@compile,
+ listOfNotNull(sources.absolutePath, commonSources?.absolutePath, commonSources?.absolutePath?.let("-Xcommon-sources="::plus)) +
+ "-Xmulti-platform" + mainArguments
+ )
+ appendln("Exit code: $exitCode")
+ appendln("Output:")
+ appendln(output)
+ }.trimTrailingWhitespacesAndAddNewlineAtEOF().trimEnd('\r', '\n')
+}
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt
index 607d004..c51a541 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeCallLoweringTests.kt
@@ -43,7 +43,7 @@
class ComposeCallLoweringTests : AbstractCodegenTest() {
@Test
- fun testInlineGroups(): Unit = forComposerParam(/*true, */false) {
+ fun testInlineGroups(): Unit = forComposerParam(true, false) {
compose("""
@Composable
@@ -611,7 +611,7 @@
}
@Test // java.lang.ClassNotFoundException: Z
- fun testObservableLambda(): Unit = forComposerParam(/*true, */false) {
+ fun testObservableLambda(): Unit = forComposerParam(true, false) {
compose(
"""
@Model
@@ -648,7 +648,7 @@
}
@Test
- fun testObservableGenericFunction(): Unit = forComposerParam(/*true, */false) {
+ fun testObservableGenericFunction(): Unit = forComposerParam(true, false) {
compose("""
@Model
class Counter() {
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeMultiPlatformTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeMultiPlatformTests.kt
index 9168a9a..7d7b782 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeMultiPlatformTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposeMultiPlatformTests.kt
@@ -16,3 +16,56 @@
package androidx.compose.plugins.kotlin
+import org.junit.Test
+
+class ComposeMultiPlatformTests : AbstractMultiPlatformIntegrationTest() {
+ @Test
+ fun testBasicMpp() = forComposerParam(true) {
+ multiplatform(
+ """
+ expect val foo: String
+ """,
+ """
+ actual val foo = ""
+ """,
+ """
+ public final class JvmKt {
+ private final static Ljava/lang/String; foo = ""
+ public final static getFoo()Ljava/lang/String;
+ public final static <clinit>()V
+ }
+ """
+ )
+ }
+
+ @Test
+ fun testBasicComposable() = forComposerParam(true) {
+ multiplatform(
+ """
+ import androidx.compose.Composable
+
+ expect @Composable fun Test()
+ """,
+ """
+ import androidx.compose.Composable
+
+ actual @Composable fun Test() {}
+ """,
+ """
+ final class JvmKt%Test%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
+ OUTERCLASS JvmKt Test (Landroidx/compose/Composer;)V
+ final static INNERCLASS JvmKt%Test%1 null null
+ private final synthetic Landroidx/compose/Composer; %%composer
+ synthetic <init>(Landroidx/compose/Composer;)V
+ public final invoke()V
+ public synthetic bridge invoke()Ljava/lang/Object;
+ }
+ public final class JvmKt {
+ final static INNERCLASS JvmKt%Test%1 null null
+ public final static Test(Landroidx/compose/Composer;)V
+ public final static synthetic Test()V
+ }
+ """
+ )
+ }
+}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposerParamSignatureTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposerParamSignatureTests.kt
index ef17290..a573176 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposerParamSignatureTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/ComposerParamSignatureTests.kt
@@ -16,7 +16,6 @@
package androidx.compose.plugins.kotlin
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
@@ -30,6 +29,20 @@
class ComposerParamSignatureTests : AbstractCodegenSignatureTest() {
@Test
+ fun testAnonymousParamNaming(): Unit = validateBytecode(
+ """
+ @Composable
+ fun Foo(children: @Composable() (a: Int, b: Int) -> Unit) {}
+ @Composable
+ fun test() {
+ Foo { _, _ -> }
+ }
+ """
+ ) {
+ assert(!it.contains("%anonymous parameter 0%"))
+ }
+
+ @Test
fun testLambdaReorderedParameter(): Unit = checkApi(
"""
@Composable fun Foo(a: String, b: () -> Unit) { }
@@ -75,7 +88,6 @@
"""
)
- @Ignore("turn this test back on once the runtime is compiled with composer param turned on")
@Test
fun testAmbientCurrent(): Unit = checkApi(
"""
@@ -150,6 +162,16 @@
)
@Test
+ fun testDataClassHashCode(): Unit = validateBytecode(
+ """
+ data class Foo(
+ val bar: @Composable() () -> Unit
+ )
+ """) {
+ assert(!it.contains("CHECKCAST kotlin/jvm/functions/Function0"))
+ }
+
+ @Test
fun testCorrectComposerPassed1(): Unit = checkComposerParam(
"""
var a: Composer<*>? = null
@@ -465,15 +487,15 @@
public final static Bar(Landroidx/compose/Composer;)V
public final static synthetic Bar()V
public final static <clinit>()V
- final static INNERCLASS TestKt%Bar%1 null null
+ final static INNERCLASS TestKt%Bar%3 null null
final static INNERCLASS TestKt%foo%1 null null
}
- final class TestKt%Bar%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
+ final class TestKt%Bar%3 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
synthetic <init>(Landroidx/compose/Composer;)V
public final invoke()V
private final synthetic Landroidx/compose/Composer; %%composer
public synthetic bridge invoke()Ljava/lang/Object;
- final static INNERCLASS TestKt%Bar%1 null null
+ final static INNERCLASS TestKt%Bar%3 null null
OUTERCLASS TestKt Bar (Landroidx/compose/Composer;)V
}
final class TestKt%foo%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function2 {
@@ -500,7 +522,7 @@
public final static Bar(Lkotlin/jvm/functions/Function1;Landroidx/compose/Composer;)V
public final static synthetic Bar(Lkotlin/jvm/functions/Function0;)V
final static INNERCLASS TestKt%Bar%foo%1 null null
- final static INNERCLASS TestKt%Bar%1 null null
+ final static INNERCLASS TestKt%Bar%5 null null
}
final class TestKt%Bar%foo%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function2 {
synthetic <init>()V
@@ -509,13 +531,13 @@
final static INNERCLASS TestKt%Bar%foo%1 null null
OUTERCLASS TestKt Bar (Lkotlin/jvm/functions/Function1;Landroidx/compose/Composer;)V
}
- final class TestKt%Bar%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
+ final class TestKt%Bar%5 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
synthetic <init>(Lkotlin/jvm/functions/Function1;Landroidx/compose/Composer;)V
public final invoke()V
private final synthetic Lkotlin/jvm/functions/Function1; %children
private final synthetic Landroidx/compose/Composer; %%composer
public synthetic bridge invoke()Ljava/lang/Object;
- final static INNERCLASS TestKt%Bar%1 null null
+ final static INNERCLASS TestKt%Bar%5 null null
OUTERCLASS TestKt Bar (Lkotlin/jvm/functions/Function1;Landroidx/compose/Composer;)V
}
"""
@@ -546,17 +568,17 @@
public final static App(ILandroidx/compose/Composer;)V
public final static synthetic Wrap(Lkotlin/jvm/functions/Function1;)V
public final static synthetic App(I)V
- final static INNERCLASS TestKt%Wrap%1 null null
+ final static INNERCLASS TestKt%Wrap%3 null null
final static INNERCLASS TestKt%App%1 null null
final static INNERCLASS TestKt%App%4 null null
}
- final class TestKt%Wrap%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
+ final class TestKt%Wrap%3 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function0 {
synthetic <init>(Lkotlin/jvm/functions/Function2;Landroidx/compose/Composer;)V
public final invoke()V
private final synthetic Lkotlin/jvm/functions/Function2; %children
private final synthetic Landroidx/compose/Composer; %%composer
public synthetic bridge invoke()Ljava/lang/Object;
- final static INNERCLASS TestKt%Wrap%1 null null
+ final static INNERCLASS TestKt%Wrap%3 null null
OUTERCLASS TestKt Wrap (Lkotlin/jvm/functions/Function2;Landroidx/compose/Composer;)V
}
final class TestKt%App%1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function2 {
@@ -713,6 +735,7 @@
}
"""
)
+
@Test
fun testComposableProperty(): Unit = checkApi(
"""
@@ -729,6 +752,105 @@
}
"""
)
+
+ @Test
+ fun testTableLambdaThing(): Unit = validateBytecode(
+ """
+ @Composable
+ fun Foo() {
+ val c: @Composable() () -> Unit = with(123) {
+ val x = @Composable {}
+ x
+ }
+ }
+ """
+ ) {
+ // TODO(lmr): test
+ }
+
+ @Test
+ fun testDefaultArgs(): Unit = validateBytecode(
+ """
+ @Composable
+ fun Scaffold(
+ topAppBar: @Composable() (() -> Unit)? = null
+ ) {}
+ """
+ ) {
+ // TODO(lmr): test
+ }
+
+
+ @Test
+ fun testSyntheticAccessFunctions(): Unit = validateBytecode(
+ """
+ class Foo {
+ @Composable private fun Bar() {}
+ }
+ """
+ ) {
+ // TODO(lmr): test
+ }
+
+
+ @Test
+ fun testLambdaMemoization(): Unit = validateBytecode(
+ """
+ fun subcompose(block: @Composable() () -> Unit) {}
+ private class Foo {
+ var children: @Composable() (Double) -> Unit = {}
+ fun subcompose() {
+ val constraints = Math.random()
+ subcompose {
+ children(constraints)
+ }
+ }
+ }
+ """
+ ) {
+ // TODO(lmr): test
+ }
+
+ @Test
+ fun testStartRestartGroupsInKickoff(): Unit = validateBytecode(
+ """
+ fun kickoff(block: @Composable() () -> Unit) {}
+ fun simpleSquareColorAndSizeTest() {
+ kickoff {
+ print("abc")
+ }
+ }
+ """
+ ) { assert(it.contains("INVOKEVIRTUAL androidx/compose/Composer.startRestartGroup")) }
+
+
+ @Test
+ fun testCustomComposerCall(): Unit = validateBytecode(
+ """
+ class VectorScope(val composer: VectorComposer)
+
+ @Composable fun VectorScope.Test(children: @Composable VectorScope.() -> Unit) {
+ children()
+ }
+
+ internal class AnyApplyAdapter : ApplyAdapter<Any> {
+ override fun Any.start(instance: Any) {}
+ override fun Any.insertAt(index: Int, instance: Any) {}
+ override fun Any.removeAt(index: Int, count: Int) {}
+ override fun Any.move(from: Int, to: Int, count: Int) {}
+ override fun Any.end(instance: Any, parent: Any) {}
+ }
+
+ class VectorComposer(
+ val root: Any,
+ slotTable: SlotTable,
+ recomposer: Recomposer
+ ) : Composer<Any>(slotTable, Applier(root, AnyApplyAdapter()), recomposer)
+ """
+ ) {
+ it.contains("INVOKEVIRTUAL androidx/compose/Composer.startGroup")
+ }
+
@Test
fun testCallingProperties(): Unit = checkApi(
"""
@@ -1091,14 +1213,4 @@
}
"""
)
-
- override fun setUp() {
- ComposeFlags.COMPOSER_PARAM = true
- super.setUp()
- }
-
- override fun tearDown() {
- super.tearDown()
- ComposeFlags.COMPOSER_PARAM = false
- }
}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt
index c9f4cf9..16eb338 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/FcsCodegenTests.kt
@@ -42,7 +42,7 @@
class FcsCodegenTests : AbstractCodegenTest() {
@Test
- fun testReturnValue(): Unit = forComposerParam(/*true, */false) {
+ fun testReturnValue(): Unit = forComposerParam(true, false) {
compose("""
var a = 0
var b = 0
@@ -107,7 +107,7 @@
}
@Test
- fun testReorderedArgsReturnValue(): Unit = forComposerParam(/*true, */false) {
+ fun testReorderedArgsReturnValue(): Unit = forComposerParam(true, false) {
compose(
"""
@Composable
@@ -291,7 +291,7 @@
}
@Test
- fun testObservableLambda(): Unit = forComposerParam(/*true, */false) {
+ fun testObservableLambda(): Unit = forComposerParam(true, false) {
compose(
"""
@Model
@@ -329,7 +329,7 @@
}
@Test
- fun testObservableGenericFunction(): Unit = forComposerParam(/*true, */false) {
+ fun testObservableGenericFunction(): Unit = forComposerParam(true, false) {
compose("""
@Model
class Counter() {
@@ -1621,7 +1621,7 @@
}
@Test
- fun testEffects1(): Unit = forComposerParam(/*true, */false) {
+ fun testEffects1(): Unit = forComposerParam(true, false) {
compose(
"""
import androidx.ui.androidview.adapters.*
@@ -1655,7 +1655,7 @@
}
@Test
- fun testEffects2(): Unit = forComposerParam(/*true, */false) {
+ fun testEffects2(): Unit = forComposerParam(true, false) {
compose(
"""
import androidx.ui.androidview.adapters.*
@@ -1691,7 +1691,7 @@
}
@Test
- fun testEffects3(): Unit = forComposerParam(/*true, */false) {
+ fun testEffects3(): Unit = forComposerParam(true, false) {
val log = StringBuilder()
compose(
"""
@@ -1736,7 +1736,7 @@
}
@Test
- fun testEffects4(): Unit = forComposerParam(/*true, */false) {
+ fun testEffects4(): Unit = forComposerParam(true, false) {
val log = StringBuilder()
compose(
"""
@@ -1943,7 +1943,7 @@
}
@Test
- fun testMovement(): Unit = forComposerParam(/*true, */false) {
+ fun testMovement(): Unit = forComposerParam(true, false) {
val tvId = 50
val btnIdAdd = 100
val btnIdUp = 200
@@ -2030,7 +2030,7 @@
}
@Test
- fun testObserveKtxWithInline(): Unit = forComposerParam(/*true, */false) {
+ fun testObserveKtxWithInline(): Unit = forComposerParam(true, false) {
compose(
"""
@Composable
@@ -2066,7 +2066,7 @@
}
@Test
- fun testKeyTag(): Unit = forComposerParam(/*true, */false) {
+ fun testKeyTag(): Unit = forComposerParam(true, false) {
compose(
"""
val list = mutableListOf(0,1,2,3)
@@ -2469,7 +2469,7 @@
}
@Test
- fun testRecomposeScope_Method(): Unit = forComposerParam(/*true, */false) {
+ fun testRecomposeScope_Method(): Unit = forComposerParam(true, false) {
compose("""
@Model
class M { var count = 0 }
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxCrossModuleTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxCrossModuleTests.kt
index 961acba..6fc6d9c 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxCrossModuleTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxCrossModuleTests.kt
@@ -75,6 +75,35 @@
}
@Test
+ fun testConstCrossModule(): Unit = forComposerParam(true, false) {
+ compile(
+ "TestG", mapOf(
+ "library module" to mapOf(
+ "x/A.kt" to """
+ package x
+
+ const val MyConstant: String = ""
+ """
+ ),
+ "Main" to mapOf(
+ "b/B.kt" to """
+ package b
+
+ import x.MyConstant
+
+ fun Test(foo: String = MyConstant) {
+ print(foo)
+ }
+ """
+ )
+ )
+ ) {
+ assert(it.contains("LDC \"\""))
+ assert(!it.contains("INVOKESTATIC x/AKt.getMyConstant"))
+ }
+ }
+
+ @Test
fun testNonCrossinlineComposable(): Unit = forComposerParam(true, false) {
compile(
"TestG", mapOf(
@@ -140,7 +169,7 @@
"""
)
)
- , dumpClasses = true)
+ )
}
@Test
@@ -512,7 +541,34 @@
}
@Test
- fun testCrossModule_SimpleComposition(): Unit = forComposerParam(/*true, */false) {
+ fun testXModuleCtorComposableParam(): Unit = forComposerParam(true, false) {
+ compile(
+ "TestJ", mapOf(
+ "library module" to mapOf(
+ "a/Foo.kt" to """
+ package a
+
+ import androidx.compose.*
+
+ class Foo(val bar: @Composable() () -> Unit)
+ """
+ ),
+ "Main" to mapOf(
+ "B.kt" to """
+ import a.Foo
+ import androidx.compose.*
+
+ @Composable fun Example(bar: @Composable() () -> Unit) {
+ val foo = Foo(bar)
+ }
+ """
+ )
+ )
+ )
+ }
+
+ @Test
+ fun testCrossModule_SimpleComposition(): Unit = forComposerParam(true, false) {
val tvId = 29
compose(
@@ -573,7 +629,7 @@
}
@Test
- fun testCrossModule_ComponentFunction(): Unit = forComposerParam(/*true, */false) {
+ fun testCrossModule_ComponentFunction(): Unit = forComposerParam(true, false) {
val tvName = 101
val tvAge = 102
@@ -644,7 +700,7 @@
}
@Test
- fun testCrossModule_ObjectFunction(): Unit = forComposerParam(/*true, */false) {
+ fun testCrossModule_ObjectFunction(): Unit = forComposerParam(true, false) {
val tvName = 101
val tvAge = 102
@@ -719,7 +775,8 @@
fun compile(
mainClassName: String,
modules: Map<String, Map<String, String>>,
- dumpClasses: Boolean = false
+ dumpClasses: Boolean = false,
+ validate: ((String) -> Unit)? = null
): List<OutputFile> {
val libraryClasses = (modules.filter { it.key != "Main" }.map {
// Setup for compile
@@ -744,9 +801,15 @@
?: error("No Main module specified"), dumpClasses).allGeneratedFiles
// Load the files looking for mainClassName
- return (libraryClasses + appClasses).filter {
+ val outputFiles = (libraryClasses + appClasses).filter {
it.relativePath.endsWith(".class")
}
+
+ if (validate != null) {
+ validate(outputFiles.joinToString("\n") { it.asText().replace('$', '%') })
+ }
+
+ return outputFiles
}
fun compose(
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
index 392d51be..8e2468b 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
@@ -16,15 +16,10 @@
package androidx.compose.plugins.kotlin
-import android.app.Activity
-import android.os.Bundle
-import android.view.ViewGroup
-import android.widget.LinearLayout
import android.widget.TextView
import androidx.compose.FrameManager
-import androidx.compose.Compose
-import androidx.compose.ViewComposer
-import androidx.compose.runWithCurrent
+import androidx.compose.Composer
+import androidx.compose.currentComposerNonNull
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
@@ -339,9 +334,18 @@
val instanceOfClass = instanceClass.newInstance()
val advanceMethod = instanceClass.getMethod("advance", *parameterTypes)
- val composeMethod = instanceClass.getMethod("compose")
+ val composeMethod = if (ComposeFlags.COMPOSER_PARAM)
+ instanceClass.getMethod("compose", Composer::class.java)
+ else
+ instanceClass.getMethod("compose")
- return composeMulti({ composeMethod.invoke(instanceOfClass) }) {
+ return composeMulti({
+ if (ComposeFlags.COMPOSER_PARAM) {
+ composeMethod.invoke(instanceOfClass, currentComposerNonNull)
+ } else {
+ composeMethod.invoke(instanceOfClass)
+ }
+ }) {
val values = valuesFactory()
val arguments = values.map { it.value }.toTypedArray()
advanceMethod.invoke(instanceOfClass, *arguments)
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/RobolectricComposeTester.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/RobolectricComposeTester.kt
index c14e511..0c9489d 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/RobolectricComposeTester.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/RobolectricComposeTester.kt
@@ -21,8 +21,15 @@
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.compose.Compose
+import androidx.compose.Composer
+import androidx.compose.Composition
+import androidx.compose.Recomposer
import org.robolectric.Robolectric
import org.robolectric.RuntimeEnvironment
+import kotlin.reflect.full.findParameterByName
+import kotlin.reflect.full.functions
+import kotlin.reflect.full.isSubtypeOf
+import kotlin.reflect.full.starProjectedType
const val ROOT_ID = 18284847
@@ -65,7 +72,23 @@
val activity = controller.create().get()
val root = activity.root
scheduler.advanceToLastPostedRunnable()
- val composition = Compose.composeInto(root, null, composable)
+ val composition = if (ComposeFlags.COMPOSER_PARAM) {
+ val composeInto = Compose::class.java.methods.first {
+ if (it.name != "composeInto") false
+ else {
+ val param = it.parameters.getOrNull(2)
+ param?.type == Function1::class.java
+ }
+ }
+ composeInto.invoke(
+ Compose,
+ root,
+ null,
+ { composer: Composer<*> -> composable() }
+ ) as Composition
+ } else {
+ Compose.composeInto(root, null, composable)
+ }
scheduler.advanceToLastPostedRunnable()
block(activity)
val advanceFn = advance ?: { composition.compose() }
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt
index 075eeed..be3952b 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposeFlags.kt
@@ -19,5 +19,5 @@
object ComposeFlags {
var FRAMED_COMPONENTS = false
var FRAMED_MODEL_CLASSES = true
- var COMPOSER_PARAM = false
+ var COMPOSER_PARAM = true
}
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeWritableSlices.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeWritableSlices.kt
index 320dfee..8ecd958 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeWritableSlices.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeWritableSlices.kt
@@ -56,6 +56,8 @@
BasicWritableSlice(RewritePolicy.DO_NOTHING)
val IS_COMPOSABLE_CALL: WritableSlice<IrAttributeContainer, Boolean> =
BasicWritableSlice(RewritePolicy.DO_NOTHING)
+ val IS_INLINE_COMPOSABLE_CALL: WritableSlice<IrAttributeContainer, Boolean> =
+ BasicWritableSlice(RewritePolicy.DO_NOTHING)
}
private val REWRITES_ALLOWED = object : RewritePolicy {
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableCallTransformer.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableCallTransformer.kt
index c7ef889..124193c 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableCallTransformer.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableCallTransformer.kt
@@ -4,10 +4,8 @@
import androidx.compose.plugins.kotlin.ComposableCallableDescriptor
import androidx.compose.plugins.kotlin.ComposableEmitDescriptor
import androidx.compose.plugins.kotlin.ComposableEmitMetadata
-import androidx.compose.plugins.kotlin.ComposableFunctionDescriptor
import androidx.compose.plugins.kotlin.ComposeFlags
import androidx.compose.plugins.kotlin.ComposeFqNames
-import androidx.compose.plugins.kotlin.ComposerMetadata
import androidx.compose.plugins.kotlin.EmitChildrenValueParameterDescriptor
import androidx.compose.plugins.kotlin.KtxNameConventions
import androidx.compose.plugins.kotlin.ValidatedAssignment
@@ -232,14 +230,14 @@
if (expression.isTransformedComposableCall()) {
val descriptor = expression.descriptor
val returnType = descriptor.returnType
- return if ((returnType == null || returnType.isUnit()) && !descriptor.isInline) {
- val meta = context.state.irTrace[
- ComposeWritableSlices.COMPOSER_IR_METADATA,
- expression
- ]
- if (meta == null) error("Couldn't find Composer Metadata")
+ val isUnit = returnType == null || returnType.isUnit() || expression.type.isUnit()
+ val isInline = descriptor.isInline || context.state.irTrace[
+ ComposeWritableSlices.IS_INLINE_COMPOSABLE_CALL,
+ expression
+ ] == true
+ return if (isUnit && !isInline) {
context.createIrBuilder(declarationStack.last().symbol).irBlock {
- +irComposableCall(expression.transformChildren(), meta)
+ +irComposableCall(expression.transformChildren())
}
} else {
context
@@ -247,18 +245,42 @@
.irComposableExpr(expression.transformChildren())
}
}
+
val emitMetadata = context.state.irTrace[
ComposeWritableSlices.COMPOSABLE_EMIT_METADATA,
expression
]
- if(emitMetadata != null) {
+ if (emitMetadata != null) {
return context.createIrBuilder(declarationStack.last().symbol).irBlock {
+irComposableEmit(expression.transformChildren(), emitMetadata)
}
}
+
+ for (i in 0 until expression.valueArgumentsCount) {
+ val arg = expression.getValueArgument(i)
+ if (arg is IrFunctionExpression && arg.origin == IrStatementOrigin.LAMBDA) {
+ if (arg.function.valueParameters.lastOrNull()?.isComposerParam() == true) {
+ return convertCallWithComposableParams(expression.transformChildren())
+ }
+ }
+ }
return super.visitCall(expression)
}
+ private fun convertCallWithComposableParams(expression: IrCall): IrExpression {
+ return context.createIrBuilder(declarationStack.last().symbol).irBlock {
+ for (i in 0 until expression.valueArgumentsCount) {
+ val arg = expression.getValueArgument(i)
+ if (arg is IrFunctionExpression && arg.origin == IrStatementOrigin.LAMBDA) {
+ if (arg.function.valueParameters.lastOrNull()?.isComposerParam() == true) {
+ expression.putValueArgument(i, covertLambdaIfNecessary(arg))
+ }
+ }
+ }
+ +expression
+ }
+ }
+
override fun visitBlock(expression: IrBlock): IrExpression {
if (ComposeFlags.COMPOSER_PARAM) return super.visitBlock(expression)
if (expression.origin != COMPOSABLE_EMIT_OR_CALL) {
@@ -276,7 +298,7 @@
val returnType = descriptor.returnType
return if ((returnType == null || returnType.isUnit()) && !descriptor.isInline) {
context.createIrBuilder(declarationStack.last().symbol).irBlock {
- +irComposableCall(transformedComposerCall, transformed, descriptor)
+ +irComposableCall(transformedComposerCall, transformed)
}
} else {
context
@@ -337,8 +359,7 @@
}
private fun IrBlockBuilder.irComposableCall(
- original: IrCall,
- meta: ComposerMetadata
+ original: IrCall
): IrExpression {
assert(ComposeFlags.COMPOSER_PARAM)
val composerArg = original.getValueArgument(original.valueArgumentsCount - 1)!!
@@ -346,30 +367,25 @@
val getComposer = { composerArg.deepCopyWithVariables() }
return irComposableCallBase(
original,
- getComposer,
- meta
+ getComposer
)
}
private fun IrBlockBuilder.irComposableCall(
composerCall: IrCall,
- original: IrCall,
- descriptor: ComposableFunctionDescriptor
+ original: IrCall
): IrExpression {
assert(!ComposeFlags.COMPOSER_PARAM)
val composerTemp = irTemporary(composerCall)
- val meta = descriptor.composerMetadata
return irComposableCallBase(
original,
- { irGet(composerTemp) },
- meta
+ { irGet(composerTemp) }
)
}
private fun IrBlockBuilder.irComposableCallBase(
original: IrCall,
- getComposer: () -> IrExpression,
- meta: ComposerMetadata
+ getComposer: () -> IrExpression
): IrExpression {
/*
@@ -400,11 +416,11 @@
val tmpDispatchReceiver = original.dispatchReceiver?.let { irTemporary(it) }
val tmpExtensionReceiver = original.extensionReceiver?.let { irTemporary(it) }
- // TODO(lmr): when we move to function body skipping, we can remove the need for this
- // entirely which means we will no longer need the ComposerMetadata concept.
- val callDescriptor = meta
- .callDescriptors
- .first { it.typeParametersCount == 0 }
+ val callDescriptor = composerTypeDescriptor
+ .unsubstitutedMemberScope
+ .findFirstFunction(KtxNameConventions.CALL.identifier) {
+ it.valueParameters.size == 3
+ }
val joinKeyDescriptor = composerTypeDescriptor
.unsubstitutedMemberScope
@@ -447,9 +463,16 @@
.memberScope
.findFirstFunction("changed") { it.typeParametersCount == 1 }
- val validatedArguments: List<IrExpression> =
+ val validatedArguments = if (ComposeFlags.COMPOSER_PARAM)
irGetArguments
- .filter { (desc, _) -> !desc.isComposerParam() }
+ .take(irGetArguments.size - 1)
+ .mapNotNull { (_, getExpr) -> getExpr() } +
+ listOfNotNull(
+ tmpDispatchReceiver?.let { irGet(it) },
+ tmpExtensionReceiver?.let { irGet(it) }
+ )
+ else
+ irGetArguments
.mapNotNull { (_, getExpr) -> getExpr() } +
listOfNotNull(
tmpDispatchReceiver?.let { irGet(it) },
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableTypeRemapper.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableTypeRemapper.kt
index 85d2e1a..db1536a 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableTypeRemapper.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposableTypeRemapper.kt
@@ -19,11 +19,16 @@
import androidx.compose.plugins.kotlin.ComposeFqNames
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
+import org.jetbrains.kotlin.builtins.getFunctionalClassKind
+import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
+import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.declarations.IrClass
+import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
+import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrMetadataSourceOwner
@@ -32,14 +37,17 @@
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.declarations.copyAttributes
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
+import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionBase
+import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
+import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
@@ -49,7 +57,9 @@
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrTypeAbbreviationImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
+import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.types.toKotlinType
+import org.jetbrains.kotlin.ir.types.withHasQuestionMark
import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper
import org.jetbrains.kotlin.ir.util.SymbolRemapper
@@ -61,6 +71,7 @@
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
+import org.jetbrains.kotlin.psi2ir.findFirstFunction
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.replace
@@ -70,6 +81,7 @@
val context: JvmBackendContext,
val symbolRemapper: DeepCopySymbolRemapper,
val typeRemapper: TypeRemapper,
+ val typeTranslator: TypeTranslator,
symbolRenamer: SymbolRenamer = SymbolRenamer.DEFAULT
) : DeepCopyIrTreeWithSymbols(symbolRemapper, typeRemapper, symbolRenamer) {
@@ -88,6 +100,12 @@
}
}
+ override fun visitField(declaration: IrField): IrField {
+ return super.visitField(declaration).also {
+ (it as IrFieldImpl).metadata = declaration.metadata
+ }
+ }
+
override fun visitProperty(declaration: IrProperty): IrProperty {
return super.visitProperty(declaration).also { it.copyMetadataFrom(declaration) }
}
@@ -105,8 +123,90 @@
}
}
+ override fun visitConstructorCall(expression: IrConstructorCall): IrConstructorCall {
+ val ownerFn = expression.symbol.owner as? IrConstructor
+ // If we are calling an external constructor, we want to "remap" the types of its signature
+ // as well, since if it they are @Composable it will have its unmodified signature. These
+ // types won't be traversed by default by the DeepCopyIrTreeWithSymbols so we have to
+ // do it ourself here.
+ if (
+ ownerFn != null &&
+ ownerFn.origin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB
+ ) {
+ symbolRemapper.visitConstructor(ownerFn)
+ val newFn = super.visitConstructor(ownerFn).also {
+ it.parent = ownerFn.parent
+ it.patchDeclarationParents(it.parent)
+ }
+ val newCallee = symbolRemapper.getReferencedConstructor(newFn.symbol)
+
+ return IrConstructorCallImpl(
+ expression.startOffset, expression.endOffset,
+ expression.type.remapType(),
+ newCallee,
+ newCallee.descriptor,
+ expression.typeArgumentsCount,
+ expression.constructorTypeArgumentsCount,
+ expression.valueArgumentsCount,
+ mapStatementOrigin(expression.origin)
+ ).apply {
+ copyRemappedTypeArgumentsFrom(expression)
+ transformValueArguments(expression)
+ }.copyAttributes(expression)
+ }
+ return super.visitConstructorCall(expression)
+ }
+
override fun visitCall(expression: IrCall): IrCall {
val ownerFn = expression.symbol.owner as? IrSimpleFunction
+ val containingClass = expression.descriptor.containingDeclaration as? ClassDescriptor
+
+ // Any virtual calls on composable functions we want to make sure we update the call to
+ // the right function base class (of n+1 arity). The most often virtual call to make on
+ // a function instance is `invoke`, which we *already* do in the ComposeParamTransformer.
+ // There are others that can happen though as well, such as `equals` and `hashCode`. In this
+ // case, we want to update those calls as well.
+ if (
+ ownerFn != null &&
+ ownerFn.origin == IrDeclarationOrigin.FAKE_OVERRIDE &&
+ containingClass != null &&
+ containingClass.defaultType.isFunctionType &&
+ expression.dispatchReceiver?.type?.isComposable() == true
+ ) {
+ val typeArguments = containingClass.defaultType.arguments
+ val newFnClass = context.irIntrinsics.symbols.getFunction(typeArguments.size)
+ val newDescriptor = newFnClass
+ .descriptor
+ .unsubstitutedMemberScope
+ .findFirstFunction(ownerFn.name.identifier) { true }
+
+ var newFn: IrSimpleFunction = IrFunctionImpl(
+ ownerFn.startOffset,
+ ownerFn.endOffset,
+ ownerFn.origin,
+ newDescriptor,
+ expression.type
+ )
+ symbolRemapper.visitSimpleFunction(newFn)
+ newFn = super.visitSimpleFunction(newFn).also { fn ->
+ fn.parent = newFnClass.owner
+ ownerFn.overriddenSymbols.mapTo(fn.overriddenSymbols) { it }
+ fn.dispatchReceiverParameter = ownerFn.dispatchReceiverParameter
+ fn.extensionReceiverParameter = ownerFn.extensionReceiverParameter
+ newDescriptor.valueParameters.forEach { p ->
+ fn.addValueParameter(p.name.identifier, p.type.toIrType())
+ }
+ fn.patchDeclarationParents(fn.parent)
+ assert(fn.body == null) { "expected body to be null" }
+ }
+
+ val newCallee = symbolRemapper.getReferencedSimpleFunction(newFn.symbol)
+ return shallowCopyCall(expression, newCallee).apply {
+ copyRemappedTypeArgumentsFrom(expression)
+ transformValueArguments(expression)
+ }
+ }
+
// If we are calling an external function, we want to "remap" the types of its signature
// as well, since if it is @Composable it will have its unmodified signature. These
// functions won't be traversed by default by the DeepCopyIrTreeWithSymbols so we have to
@@ -188,6 +288,12 @@
is IrClassImpl -> metadata = owner.metadata
}
}
+
+ private fun IrType.isComposable(): Boolean {
+ return annotations.hasAnnotation(ComposeFqNames.Composable)
+ }
+
+ private fun KotlinType.toIrType(): IrType = typeTranslator.translateType(this)
}
class ComposerTypeRemapper(
@@ -241,7 +347,8 @@
.getFunction(oldArguments.size) // return type is an argument, so this is n + 1
.defaultType
.replace(newArguments)
- .toIrType() as IrSimpleType
+ .toIrType()
+ .withHasQuestionMark(type.hasQuestionMark) as IrSimpleType
return underlyingRemapType(transformedComposableType)
}
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeObservePatcher.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeObservePatcher.kt
index 9508bb1..ee75aa0 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeObservePatcher.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeObservePatcher.kt
@@ -336,18 +336,13 @@
)
}
descriptor.dispatchReceiverParameter?.let {
- receiverDescriptor ->
// Ensure we get the correct type by trying to avoid
// going through a KotlinType if possible.
- val receiverType = (receiverDescriptor as?
- WrappedReceiverParameterDescriptor)?.owner?.type
- ?: receiverDescriptor.type.toIrType()
+ val parameter = original.dispatchReceiverParameter
+ ?: error("Expected dispatch receiver on declaration")
val receiver = irGet(
- receiverType,
- original.dispatchReceiverParameter?.symbol
- ?: error(
- "Expected dispatch receiver on declaration"
- )
+ parameter.type,
+ parameter.symbol
)
// Save the dispatch receiver into a temporary created in
@@ -357,7 +352,7 @@
val tmp = outerBuilder.irTemporary(
value = receiver,
nameHint = "rcvr",
- irType = receiverType
+ irType = parameter.type
)
dispatchReceiver = irGet(tmp)
}
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeResolutionMetadataTransformer.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeResolutionMetadataTransformer.kt
index 6da6f9e..321126b 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeResolutionMetadataTransformer.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposeResolutionMetadataTransformer.kt
@@ -46,14 +46,6 @@
val descriptor = expression.descriptor
- if (descriptor is ComposableCallableDescriptor) {
- context.state.irTrace.record(
- ComposeWritableSlices.COMPOSER_IR_METADATA,
- expression,
- descriptor.composerMetadata
- )
- }
-
if (descriptor is ComposableEmitDescriptor) {
context.state.irTrace.record(
ComposeWritableSlices.COMPOSABLE_EMIT_METADATA,
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerParamTransformer.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerParamTransformer.kt
index 5e6fec1..3e7d099 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerParamTransformer.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/compiler/lower/ComposerParamTransformer.kt
@@ -28,18 +28,15 @@
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
+import org.jetbrains.kotlin.backend.common.ir.isExpect
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irThrow
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
+import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
-import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
-import org.jetbrains.kotlin.descriptors.SourceElement
-import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
-import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
-import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
@@ -61,7 +58,6 @@
import org.jetbrains.kotlin.ir.declarations.copyAttributes
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrCall
-import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
@@ -91,18 +87,13 @@
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.load.java.JvmAbi
-import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi2ir.findFirstFunction
import org.jetbrains.kotlin.resolve.DescriptorUtils
-import org.jetbrains.kotlin.resolve.constants.ConstantValue
-import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
-import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
-import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
private const val DEBUG_LOG = false
@@ -132,7 +123,8 @@
val transformer = DeepCopyIrTreeWithSymbolsPreservingMetadata(
context,
symbolRemapper,
- typeRemapper
+ typeRemapper,
+ typeTranslator
).also { typeRemapper.deepCopy = it }
module.transformChildren(
transformer,
@@ -309,6 +301,10 @@
// TODO(b/147250515)
if (isNonComposableInlinedLambda()) return this
+ // we don't bother transforming expect functions. They exist only for type resolution and
+ // don't need to be transformed to have a composer parameter
+ if (isExpect) return this
+
// cache the transformed function with composer parameter
return transformedFunctions[this] ?: copyWithComposerParam()
}
@@ -430,12 +426,33 @@
fn.copyTypeParametersFrom(this)
fn.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(fn)
fn.extensionReceiverParameter = extensionReceiverParameter?.copyTo(fn)
- valueParameters.mapTo(fn.valueParameters) { p -> p.copyTo(fn) }
+ valueParameters.mapTo(fn.valueParameters) { p ->
+ // Composable lambdas will always have `IrGet`s of all of their parameters
+ // generated, since they are passed into the restart lambda. This causes an
+ // interesting corner case with "anonymous parameters" of composable functions.
+ // If a parameter is anonymous (using the name `_`) in user code, you can usually
+ // make the assumption that it is never used, but this is technically not the
+ // case in composable lambdas. The synthetic name that kotlin generates for
+ // anonymous parameters has an issue where it is not safe to dex, so we sanitize
+ // the names here to ensure that dex is always safe.
+ p.copyTo(fn, name = dexSafeName(p.name))
+ }
annotations.mapTo(fn.annotations) { a -> a }
fn.body = body?.deepCopyWithSymbols(this)
}
}
+ private fun dexSafeName(name: Name): Name {
+ return if (name.isSpecial && name.asString().contains(' ')) {
+ val sanitized = name
+ .asString()
+ .replace(' ', '$')
+ .replace('<', '$')
+ .replace('>', '$')
+ Name.identifier(sanitized)
+ } else name
+ }
+
private fun jvmNameAnnotation(name: String): IrConstructorCall {
val jvmName = getTopLevelClass(DescriptorUtils.JVM_NAME)
val type = jvmName.createType(false, emptyList())
@@ -553,8 +570,21 @@
}
override fun visitCall(expression: IrCall): IrExpression {
- val expr = if (!isNestedScope)
- expression.withComposerParamIfNeeded(composerParam)
+ val expr = if (!isNestedScope) {
+ expression.withComposerParamIfNeeded(composerParam).also { call ->
+ if (
+ fn.isInline &&
+ call !== expression &&
+ call.isInlineParameterLambdaInvoke()
+ ) {
+ context.state.irTrace.record(
+ ComposeWritableSlices.IS_INLINE_COMPOSABLE_CALL,
+ call,
+ true
+ )
+ }
+ }
+ }
else
expression
return super.visitCall(expr)
@@ -563,6 +593,13 @@
}
}
+ fun IrCall.isInlineParameterLambdaInvoke(): Boolean {
+ if (origin != IrStatementOrigin.INVOKE) return false
+ val lambda = dispatchReceiver as? IrGetValue
+ val valueParameter = lambda?.symbol?.owner as? IrValueParameter
+ return valueParameter?.isInlineParameter() == true
+ }
+
fun IrCall.isComposableLambdaInvoke(): Boolean {
return origin == IrStatementOrigin.INVOKE &&
dispatchReceiver?.type?.hasComposableAnnotation() == true
@@ -636,7 +673,8 @@
val transformer = DeepCopyIrTreeWithSymbolsPreservingMetadata(
context,
symbolRemapper,
- typeRemapper
+ typeRemapper,
+ typeTranslator
).also { typeRemapper.deepCopy = it }
val result = d.transform(
transformer,
diff --git a/compose/compose-runtime/api/0.1.0-dev05.txt b/compose/compose-runtime/api/0.1.0-dev05.txt
index ef9a60a..b6d57aa 100644
--- a/compose/compose-runtime/api/0.1.0-dev05.txt
+++ b/compose/compose-runtime/api/0.1.0-dev05.txt
@@ -91,13 +91,15 @@
method public static androidx.compose.Composition setViewContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
}
- public class Composer<N> {
+ public class Composer<N> implements androidx.compose.ComposerValidator {
ctor public Composer(androidx.compose.SlotTable slotTable, androidx.compose.Applier<N> applier, androidx.compose.Recomposer recomposer);
method public final void abortRoot();
method public final <V, T> void apply(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
method public final void applyChanges();
method public final androidx.compose.CompositionReference buildReference();
- method public final <T> boolean changed(T? value);
+ method public final inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> boolean changed(T? value);
+ method public boolean changed(int value);
method public final void collectKeySourceInformation();
method protected final void composeRoot(kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public final <T extends N> void createNode(kotlin.jvm.functions.Function0<? extends T> factory);
@@ -148,6 +150,11 @@
method public inline <reified V> void update(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
}
+ public interface ComposerValidator {
+ method public boolean changed(int value);
+ method public <T> boolean changed(T? value);
+ }
+
public class Composition {
ctor public Composition(kotlin.jvm.functions.Function2<? super androidx.compose.SlotTable,? super androidx.compose.Recomposer,? extends androidx.compose.Composer<?>> composerFactory, androidx.compose.CompositionReference? parent);
method public final void compose(kotlin.jvm.functions.Function0<kotlin.Unit> content);
@@ -463,7 +470,6 @@
public final class ViewComposer extends androidx.compose.Composer<java.lang.Object> {
ctor public ViewComposer(android.content.Context context, Object root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer, androidx.compose.ViewAdapters? adapters);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public inline <T extends android.view.View> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
method public inline <T extends android.view.ViewGroup> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public inline <T extends androidx.compose.Emittable> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
@@ -484,23 +490,6 @@
method public static <T> T! runWithCurrent(androidx.compose.Composer<?>, kotlin.jvm.functions.Function0<? extends T> block);
}
- public final class ViewValidator {
- ctor public ViewValidator(androidx.compose.Composer<?> composer);
- method public boolean changed(int value);
- method public <T> boolean changed(T? value);
- method public <T> boolean changedUnchecked(T? value);
- method public androidx.compose.Composer<?> getComposer();
- method public operator boolean plus(boolean, boolean other);
- method public inline boolean set(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean set(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean setUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline boolean update(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean update(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean updateUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public boolean updated(int value);
- method public <T> boolean updated(T? value);
- }
-
}
package androidx.compose.adapters {
diff --git a/compose/compose-runtime/api/current.txt b/compose/compose-runtime/api/current.txt
index ef9a60a..b6d57aa 100644
--- a/compose/compose-runtime/api/current.txt
+++ b/compose/compose-runtime/api/current.txt
@@ -91,13 +91,15 @@
method public static androidx.compose.Composition setViewContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
}
- public class Composer<N> {
+ public class Composer<N> implements androidx.compose.ComposerValidator {
ctor public Composer(androidx.compose.SlotTable slotTable, androidx.compose.Applier<N> applier, androidx.compose.Recomposer recomposer);
method public final void abortRoot();
method public final <V, T> void apply(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
method public final void applyChanges();
method public final androidx.compose.CompositionReference buildReference();
- method public final <T> boolean changed(T? value);
+ method public final inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> boolean changed(T? value);
+ method public boolean changed(int value);
method public final void collectKeySourceInformation();
method protected final void composeRoot(kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public final <T extends N> void createNode(kotlin.jvm.functions.Function0<? extends T> factory);
@@ -148,6 +150,11 @@
method public inline <reified V> void update(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
}
+ public interface ComposerValidator {
+ method public boolean changed(int value);
+ method public <T> boolean changed(T? value);
+ }
+
public class Composition {
ctor public Composition(kotlin.jvm.functions.Function2<? super androidx.compose.SlotTable,? super androidx.compose.Recomposer,? extends androidx.compose.Composer<?>> composerFactory, androidx.compose.CompositionReference? parent);
method public final void compose(kotlin.jvm.functions.Function0<kotlin.Unit> content);
@@ -463,7 +470,6 @@
public final class ViewComposer extends androidx.compose.Composer<java.lang.Object> {
ctor public ViewComposer(android.content.Context context, Object root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer, androidx.compose.ViewAdapters? adapters);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public inline <T extends android.view.View> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
method public inline <T extends android.view.ViewGroup> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public inline <T extends androidx.compose.Emittable> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
@@ -484,23 +490,6 @@
method public static <T> T! runWithCurrent(androidx.compose.Composer<?>, kotlin.jvm.functions.Function0<? extends T> block);
}
- public final class ViewValidator {
- ctor public ViewValidator(androidx.compose.Composer<?> composer);
- method public boolean changed(int value);
- method public <T> boolean changed(T? value);
- method public <T> boolean changedUnchecked(T? value);
- method public androidx.compose.Composer<?> getComposer();
- method public operator boolean plus(boolean, boolean other);
- method public inline boolean set(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean set(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean setUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline boolean update(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean update(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean updateUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public boolean updated(int value);
- method public <T> boolean updated(T? value);
- }
-
}
package androidx.compose.adapters {
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev05.txt b/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev05.txt
index ef9a60a..b6d57aa 100644
--- a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev05.txt
+++ b/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev05.txt
@@ -91,13 +91,15 @@
method public static androidx.compose.Composition setViewContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
}
- public class Composer<N> {
+ public class Composer<N> implements androidx.compose.ComposerValidator {
ctor public Composer(androidx.compose.SlotTable slotTable, androidx.compose.Applier<N> applier, androidx.compose.Recomposer recomposer);
method public final void abortRoot();
method public final <V, T> void apply(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
method public final void applyChanges();
method public final androidx.compose.CompositionReference buildReference();
- method public final <T> boolean changed(T? value);
+ method public final inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> boolean changed(T? value);
+ method public boolean changed(int value);
method public final void collectKeySourceInformation();
method protected final void composeRoot(kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public final <T extends N> void createNode(kotlin.jvm.functions.Function0<? extends T> factory);
@@ -148,6 +150,11 @@
method public inline <reified V> void update(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
}
+ public interface ComposerValidator {
+ method public boolean changed(int value);
+ method public <T> boolean changed(T? value);
+ }
+
public class Composition {
ctor public Composition(kotlin.jvm.functions.Function2<? super androidx.compose.SlotTable,? super androidx.compose.Recomposer,? extends androidx.compose.Composer<?>> composerFactory, androidx.compose.CompositionReference? parent);
method public final void compose(kotlin.jvm.functions.Function0<kotlin.Unit> content);
@@ -463,7 +470,6 @@
public final class ViewComposer extends androidx.compose.Composer<java.lang.Object> {
ctor public ViewComposer(android.content.Context context, Object root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer, androidx.compose.ViewAdapters? adapters);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public inline <T extends android.view.View> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
method public inline <T extends android.view.ViewGroup> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public inline <T extends androidx.compose.Emittable> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
@@ -484,23 +490,6 @@
method public static <T> T! runWithCurrent(androidx.compose.Composer<?>, kotlin.jvm.functions.Function0<? extends T> block);
}
- public final class ViewValidator {
- ctor public ViewValidator(androidx.compose.Composer<?> composer);
- method public boolean changed(int value);
- method public <T> boolean changed(T? value);
- method public <T> boolean changedUnchecked(T? value);
- method public androidx.compose.Composer<?> getComposer();
- method public operator boolean plus(boolean, boolean other);
- method public inline boolean set(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean set(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean setUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline boolean update(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean update(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean updateUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public boolean updated(int value);
- method public <T> boolean updated(T? value);
- }
-
}
package androidx.compose.adapters {
diff --git a/compose/compose-runtime/api/public_plus_experimental_current.txt b/compose/compose-runtime/api/public_plus_experimental_current.txt
index ef9a60a..b6d57aa 100644
--- a/compose/compose-runtime/api/public_plus_experimental_current.txt
+++ b/compose/compose-runtime/api/public_plus_experimental_current.txt
@@ -91,13 +91,15 @@
method public static androidx.compose.Composition setViewContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
}
- public class Composer<N> {
+ public class Composer<N> implements androidx.compose.ComposerValidator {
ctor public Composer(androidx.compose.SlotTable slotTable, androidx.compose.Applier<N> applier, androidx.compose.Recomposer recomposer);
method public final void abortRoot();
method public final <V, T> void apply(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
method public final void applyChanges();
method public final androidx.compose.CompositionReference buildReference();
- method public final <T> boolean changed(T? value);
+ method public final inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> boolean changed(T? value);
+ method public boolean changed(int value);
method public final void collectKeySourceInformation();
method protected final void composeRoot(kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public final <T extends N> void createNode(kotlin.jvm.functions.Function0<? extends T> factory);
@@ -148,6 +150,11 @@
method public inline <reified V> void update(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
}
+ public interface ComposerValidator {
+ method public boolean changed(int value);
+ method public <T> boolean changed(T? value);
+ }
+
public class Composition {
ctor public Composition(kotlin.jvm.functions.Function2<? super androidx.compose.SlotTable,? super androidx.compose.Recomposer,? extends androidx.compose.Composer<?>> composerFactory, androidx.compose.CompositionReference? parent);
method public final void compose(kotlin.jvm.functions.Function0<kotlin.Unit> content);
@@ -463,7 +470,6 @@
public final class ViewComposer extends androidx.compose.Composer<java.lang.Object> {
ctor public ViewComposer(android.content.Context context, Object root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer, androidx.compose.ViewAdapters? adapters);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public inline <T extends android.view.View> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
method public inline <T extends android.view.ViewGroup> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public inline <T extends androidx.compose.Emittable> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
@@ -484,23 +490,6 @@
method public static <T> T! runWithCurrent(androidx.compose.Composer<?>, kotlin.jvm.functions.Function0<? extends T> block);
}
- public final class ViewValidator {
- ctor public ViewValidator(androidx.compose.Composer<?> composer);
- method public boolean changed(int value);
- method public <T> boolean changed(T? value);
- method public <T> boolean changedUnchecked(T? value);
- method public androidx.compose.Composer<?> getComposer();
- method public operator boolean plus(boolean, boolean other);
- method public inline boolean set(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean set(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean setUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline boolean update(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean update(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean updateUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public boolean updated(int value);
- method public <T> boolean updated(T? value);
- }
-
}
package androidx.compose.adapters {
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev05.txt b/compose/compose-runtime/api/restricted_0.1.0-dev05.txt
index ef9a60a..b6d57aa 100644
--- a/compose/compose-runtime/api/restricted_0.1.0-dev05.txt
+++ b/compose/compose-runtime/api/restricted_0.1.0-dev05.txt
@@ -91,13 +91,15 @@
method public static androidx.compose.Composition setViewContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
}
- public class Composer<N> {
+ public class Composer<N> implements androidx.compose.ComposerValidator {
ctor public Composer(androidx.compose.SlotTable slotTable, androidx.compose.Applier<N> applier, androidx.compose.Recomposer recomposer);
method public final void abortRoot();
method public final <V, T> void apply(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
method public final void applyChanges();
method public final androidx.compose.CompositionReference buildReference();
- method public final <T> boolean changed(T? value);
+ method public final inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> boolean changed(T? value);
+ method public boolean changed(int value);
method public final void collectKeySourceInformation();
method protected final void composeRoot(kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public final <T extends N> void createNode(kotlin.jvm.functions.Function0<? extends T> factory);
@@ -148,6 +150,11 @@
method public inline <reified V> void update(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
}
+ public interface ComposerValidator {
+ method public boolean changed(int value);
+ method public <T> boolean changed(T? value);
+ }
+
public class Composition {
ctor public Composition(kotlin.jvm.functions.Function2<? super androidx.compose.SlotTable,? super androidx.compose.Recomposer,? extends androidx.compose.Composer<?>> composerFactory, androidx.compose.CompositionReference? parent);
method public final void compose(kotlin.jvm.functions.Function0<kotlin.Unit> content);
@@ -463,7 +470,6 @@
public final class ViewComposer extends androidx.compose.Composer<java.lang.Object> {
ctor public ViewComposer(android.content.Context context, Object root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer, androidx.compose.ViewAdapters? adapters);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public inline <T extends android.view.View> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
method public inline <T extends android.view.ViewGroup> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public inline <T extends androidx.compose.Emittable> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
@@ -484,23 +490,6 @@
method public static <T> T! runWithCurrent(androidx.compose.Composer<?>, kotlin.jvm.functions.Function0<? extends T> block);
}
- public final class ViewValidator {
- ctor public ViewValidator(androidx.compose.Composer<?> composer);
- method public boolean changed(int value);
- method public <T> boolean changed(T? value);
- method public <T> boolean changedUnchecked(T? value);
- method public androidx.compose.Composer<?> getComposer();
- method public operator boolean plus(boolean, boolean other);
- method public inline boolean set(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean set(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean setUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline boolean update(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean update(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean updateUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public boolean updated(int value);
- method public <T> boolean updated(T? value);
- }
-
}
package androidx.compose.adapters {
diff --git a/compose/compose-runtime/api/restricted_current.txt b/compose/compose-runtime/api/restricted_current.txt
index ef9a60a..b6d57aa 100644
--- a/compose/compose-runtime/api/restricted_current.txt
+++ b/compose/compose-runtime/api/restricted_current.txt
@@ -91,13 +91,15 @@
method public static androidx.compose.Composition setViewContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
}
- public class Composer<N> {
+ public class Composer<N> implements androidx.compose.ComposerValidator {
ctor public Composer(androidx.compose.SlotTable slotTable, androidx.compose.Applier<N> applier, androidx.compose.Recomposer recomposer);
method public final void abortRoot();
method public final <V, T> void apply(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
method public final void applyChanges();
method public final androidx.compose.CompositionReference buildReference();
- method public final <T> boolean changed(T? value);
+ method public final inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public <T> boolean changed(T? value);
+ method public boolean changed(int value);
method public final void collectKeySourceInformation();
method protected final void composeRoot(kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public final <T extends N> void createNode(kotlin.jvm.functions.Function0<? extends T> factory);
@@ -148,6 +150,11 @@
method public inline <reified V> void update(V? value, kotlin.jvm.functions.Function2<? super T,? super V,kotlin.Unit> block);
}
+ public interface ComposerValidator {
+ method public boolean changed(int value);
+ method public <T> boolean changed(T? value);
+ }
+
public class Composition {
ctor public Composition(kotlin.jvm.functions.Function2<? super androidx.compose.SlotTable,? super androidx.compose.Recomposer,? extends androidx.compose.Composer<?>> composerFactory, androidx.compose.CompositionReference? parent);
method public final void compose(kotlin.jvm.functions.Function0<kotlin.Unit> content);
@@ -463,7 +470,6 @@
public final class ViewComposer extends androidx.compose.Composer<java.lang.Object> {
ctor public ViewComposer(android.content.Context context, Object root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer, androidx.compose.ViewAdapters? adapters);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
method public inline <T extends android.view.View> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
method public inline <T extends android.view.ViewGroup> void emit(Object key, kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public inline <T extends androidx.compose.Emittable> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<java.lang.Object,T>,kotlin.Unit> update);
@@ -484,23 +490,6 @@
method public static <T> T! runWithCurrent(androidx.compose.Composer<?>, kotlin.jvm.functions.Function0<? extends T> block);
}
- public final class ViewValidator {
- ctor public ViewValidator(androidx.compose.Composer<?> composer);
- method public boolean changed(int value);
- method public <T> boolean changed(T? value);
- method public <T> boolean changedUnchecked(T? value);
- method public androidx.compose.Composer<?> getComposer();
- method public operator boolean plus(boolean, boolean other);
- method public inline boolean set(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean set(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean setUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline boolean update(int value, kotlin.jvm.functions.Function1<? super java.lang.Integer,kotlin.Unit> block);
- method public inline <reified T> boolean update(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public inline <T> boolean updateUnchecked(T? value, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
- method public boolean updated(int value);
- method public <T> boolean updated(T? value);
- }
-
}
package androidx.compose.adapters {
diff --git a/compose/compose-runtime/build.gradle b/compose/compose-runtime/build.gradle
index 353b4ad..d85dc83 100644
--- a/compose/compose-runtime/build.gradle
+++ b/compose/compose-runtime/build.gradle
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
import static androidx.build.dependencies.DependenciesKt.*
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
@@ -25,7 +28,9 @@
id("com.android.library")
id("kotlin-multiplatform")
}
-
+dependencies {
+ kotlinPlugin project(path: ":compose:compose-compiler")
+}
kotlin {
android()
@@ -89,3 +94,9 @@
inceptionYear = "2019"
description = "Contains support code for tree composition"
}
+
+tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ useIR = true
+ }
+}
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt
index e8d4697..27e7349 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt
@@ -21,7 +21,7 @@
import androidx.compose.Composable
import androidx.compose.Composer
import androidx.compose.FrameManager
-import androidx.compose.composer
+import androidx.compose.currentComposerIntrinsic
import androidx.compose.disposeComposition
import androidx.compose.runWithCurrent
import androidx.test.rule.ActivityTestRule
@@ -56,7 +56,7 @@
val activity = activityRule.activity
activity.setContent {
- activeComposer = composer
+ activeComposer = currentComposerIntrinsic
receiver.composeCb()
}
diff --git a/compose/compose-runtime/integration-tests/samples/build.gradle b/compose/compose-runtime/integration-tests/samples/build.gradle
index dad3437..ad41b84 100644
--- a/compose/compose-runtime/integration-tests/samples/build.gradle
+++ b/compose/compose-runtime/integration-tests/samples/build.gradle
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
import static androidx.build.dependencies.DependenciesKt.*
plugins {
@@ -34,3 +37,9 @@
implementation project(":ui:ui-layout")
implementation project(":ui:ui-material")
}
+
+tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ useIR = true
+ }
+}
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/AmbientTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/AmbientTests.kt
index e0626b5..ce8cc49 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/AmbientTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/AmbientTests.kt
@@ -43,7 +43,6 @@
val someStaticInt = staticAmbientOf { 40 }
@RunWith(AndroidJUnit4::class)
-@Suppress("PLUGIN_ERROR")
class AmbientTests : BaseComposeTest() {
@get:Rule
@@ -94,9 +93,7 @@
Providers(
someTextAmbient provides someText
) {
- call(107, { false }) {
- ReadStringAmbient(ambient = someTextAmbient, id = tvId)
- }
+ ReadStringAmbient(ambient = someTextAmbient, id = tvId)
}
}.then { activity ->
assertEquals(someText, activity.findViewById<TextView>(100).text)
@@ -120,9 +117,7 @@
Providers(
staticStringAmbient provides someText
) {
- call(114, { false }) {
- ReadStringAmbient(ambient = staticStringAmbient, id = tvId)
- }
+ ReadStringAmbient(ambient = staticStringAmbient, id = tvId)
}
}.then { activity ->
assertEquals(someText, activity.findViewById<TextView>(100).text)
@@ -148,10 +143,7 @@
someTextAmbient provides someText,
someIntAmbient provides 0
) {
- call(150, { false }) {
- ReadStringAmbient(ambient = someTextAmbient, id = tvId)
- }
-
+ ReadStringAmbient(ambient = someTextAmbient, id = tvId)
subCompose {
assertEquals(someText, someTextAmbient.current)
assertEquals(0, someIntAmbient.current)
@@ -192,9 +184,7 @@
assertEquals(someText, staticSomeTextAmbient.current)
assertEquals(0, staticSomeIntAmbient.current)
- call(150, { false }) {
- ReadStringAmbient(ambient = staticSomeTextAmbient, id = tvId)
- }
+ ReadStringAmbient(ambient = staticSomeTextAmbient, id = tvId)
subCompose {
assertEquals(someText, staticSomeTextAmbient.current)
@@ -233,9 +223,7 @@
someTextAmbient provides someText,
someIntAmbient provides 0
) {
- call(150, { false }) {
- ReadStringAmbient(ambient = someTextAmbient, id = tvId)
- }
+ ReadStringAmbient(ambient = someTextAmbient, id = tvId)
doSubCompose = deferredSubCompose {
assertEquals(someText, someTextAmbient.current)
@@ -281,9 +269,7 @@
assertEquals(someText, staticSomeTextAmbient.current)
assertEquals(0, staticSomeIntAmbient.current)
- call(150, { false }) {
- ReadStringAmbient(ambient = staticSomeTextAmbient, id = tvId)
- }
+ ReadStringAmbient(ambient = staticSomeTextAmbient, id = tvId)
doSubCompose = deferredSubCompose {
assertEquals(someText, staticSomeTextAmbient.current)
@@ -342,11 +328,9 @@
val someDataAmbient = ambientOf(StructurallyEqual) { SomeData() }
var composed = false
- fun ViewComposer.ReadSomeDataAmbient(ambient: Ambient<SomeData>, id: Int = 100) {
- startRestartGroup(316)
+ @Composable fun ReadSomeDataAmbient(ambient: Ambient<SomeData>, id: Int = 100) {
composed = true
Text(value = ambient.current.value, id = id)
- endRestartGroup()?.updateScope { ReadSomeDataAmbient(ambient = ambient, id = id) }
}
compose {
@@ -355,9 +339,7 @@
Providers(
someDataAmbient provides SomeData("provided")
) {
- call(354, { false }) {
- ReadSomeDataAmbient(someDataAmbient)
- }
+ ReadSomeDataAmbient(someDataAmbient)
}
}
}.then {
@@ -380,24 +362,20 @@
}
}
- fun ViewComposer.subCompose(block: ViewComposer.() -> Unit) {
- startRestartGroup(139)
- val container = remember { Container() }
- val reference = composer.buildReference()
+ @Composable fun subCompose(block: @Composable() () -> Unit) {
+ val container = remember { escapeCompose { Container() } }
+ val reference = compositionReference()
Compose.subcomposeInto(container, activityRule.activity, reference) {
- (currentComposerNonNull as ViewComposer).block()
+ block()
}
- endRestartGroup()?.updateScope { subCompose(block) }
}
- fun ViewComposer.deferredSubCompose(block: ViewComposer.() -> Unit): () -> Unit {
- startRestartGroup(234)
- val container = remember { Container() }
- val reference = composer.buildReference()
- endRestartGroup()?.updateScope { deferredSubCompose(block) }
+ @Composable fun deferredSubCompose(block: @Composable() () -> Unit): () -> Unit {
+ val container = remember { escapeCompose { Container() } }
+ val reference = compositionReference()
return {
Compose.subcomposeInto(container, activityRule.activity, reference) {
- (currentComposerNonNull as ViewComposer).block()
+ block()
}
}
}
@@ -405,24 +383,14 @@
private data class SomeData(val value: String = "default")
-@Suppress("PLUGIN_ERROR")
@Composable
-fun ViewComposer.Text(value: String, id: Int = 100) {
- startRestartGroup(87)
- emit(
- 168,
- { context -> TextView(context).apply { this.id = id } },
- { set(value) { text = it } }
- )
- endRestartGroup()?.updateScope { Text(value, id) }
+fun Text(value: String, id: Int = 100) {
+ TextView(id = id, text = value)
}
-@Suppress("PLUGIN_ERROR")
@Composable
-fun ViewComposer.ReadStringAmbient(ambient: Ambient<String>, id: Int = 100) {
- startRestartGroup(80)
+fun ReadStringAmbient(ambient: Ambient<String>, id: Int = 100) {
Text(value = ambient.current, id = id)
- endRestartGroup()?.updateScope { ReadStringAmbient(ambient = ambient, id = id) }
}
class Container : Emittable {
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/BaseComposeTest.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/BaseComposeTest.kt
index 8355c85..e7342bb 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/BaseComposeTest.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/BaseComposeTest.kt
@@ -119,13 +119,13 @@
val activity get() = activityRule.activity
fun compose(
- composable: ViewComposer.() -> Unit
+ composable: @Composable() () -> Unit
) = ComposeTester(
activity,
composable
)
- class ComposeTester(val activity: Activity, val composable: ViewComposer.() -> Unit) {
+ class ComposeTester(val activity: Activity, val composable: @Composable() () -> Unit) {
lateinit var invalidateRoot: () -> Unit
inner class ActiveTest(val activity: Activity, val composition: Composition) {
fun recomposeRoot(): ActiveTest {
@@ -145,17 +145,11 @@
}
fun then(block: ComposeTester.(activity: Activity) -> Unit): ActiveTest {
- var realComposable: () -> Unit = {}
- realComposable = {
- with(composer) {
- startRestartGroup(0)
- invalidateRoot = invalidate
- composable()
- endRestartGroup()?.updateScope { realComposable() }
- }
- }
val composition = activity.show {
- realComposable()
+ Recompose {
+ invalidateRoot = it
+ composable()
+ }
}
activity.waitForAFrame()
activity.uiThread {
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/ComposeModelTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/ComposeModelTests.kt
index fcc73cc..f72ee4e 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/ComposeModelTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/ComposeModelTests.kt
@@ -132,11 +132,7 @@
fun testModelView_Simple() {
val tvId = 67
compose {
- emit(62, { context ->
- TextView(context).apply {
- text = "Hello world!"; id = tvId
- }
- }) { }
+ TextView(text = "Hello world!", id = tvId)
}.then { activity ->
val tv = activity.root.findViewById(tvId) as TextView
assertEquals("Hello world!", tv.text)
@@ -147,11 +143,7 @@
fun testModelView_Simple_Recompose() {
val tvId = 71
compose {
- emit(73, { context ->
- TextView(context).apply {
- text = "Hello world!"; id = tvId
- }
- }) { }
+ TextView(text = "Hello world!", id = tvId)
}.then { activity ->
val tv = activity.root.findViewById(tvId) as TextView
assertEquals("Hello world!", tv.text)
@@ -172,19 +164,9 @@
)
}
- @Suppress("PLUGIN_WARNING")
compose {
- call(147, { true }) {
-
- (Observe {
- emit(93, { context -> TextView(context).apply { id = tvIdName } }) {
- set(president.name) { text = it }
- }
- emit(94, { context -> TextView(context).apply { id = tvIdAge } }) {
- set(president.age) { text = it.toString() }
- }
- })
- }
+ TextView(id = tvIdName, text = president.name)
+ TextView(id = tvIdAge, text = president.age)
}.then {
val tvName = it.findViewById(tvIdName) as TextView
val tvAge = it.findViewById(tvIdAge) as TextView
@@ -217,30 +199,16 @@
}
val displayLincoln = frame { TestState(true) }
- @Suppress("PLUGIN_WARNING")
- fun ViewComposer.display(person: Person) {
- call(167, { true }) {
- @Suppress("PLUGIN_ERROR")
- (Observe {
- emit(93, { context -> TextView(context) }) {
- set(person.name) { text = it }
- }
- emit(94, { context -> TextView(context) }) {
- set(person.age) { text = it.toString() }
- }
- })
- }
+ @Composable fun display(person: Person) {
+ TextView(text = person.name)
+ TextView(text = person.age)
}
- @Suppress("PLUGIN_WARNING")
compose {
- call(185, { true }) {
- @Suppress("PLUGIN_ERROR")
- (Observe {
- display(washington)
- if (displayLincoln.value)
- display(lincoln)
- })
+ Observe {
+ display(washington)
+ if (displayLincoln.value)
+ display(lincoln)
}
}.then {
displayLincoln.value = false
@@ -253,7 +221,6 @@
// b/122548164
@Test
- @Suppress("PLUGIN_WARNING")
fun testObserverEntering() {
val president = frame {
Person(
@@ -263,35 +230,17 @@
}
val tvName = 204
- fun ViewComposer.display(person: Person) {
- call(167, { true }) {
- (Observe {
- emit(93, { context -> TextView(context).apply { id = tvName } }) {
- set(person.name) { text = it }
- }
- emit(94, { context -> TextView(context) }) {
- set(person.age) { text = it.toString() }
- }
- })
- if (person.name == PRESIDENT_NAME_16) {
- (Observe {
- emit(211, { context -> TextView(context) }) {
- set(person.name) { text = it }
- }
- emit(211, { context -> TextView(context) }) {
- set(person.age) { text = it.toString() }
- }
- })
- }
+ @Composable fun display(person: Person) {
+ TextView(id = tvName, text = person.name)
+ TextView(text = person.age)
+ if (person.name == PRESIDENT_NAME_16) {
+ TextView(text = person.name)
+ TextView(text = person.age)
}
}
compose {
- call(219, { true }) {
- (Observe {
- display(president)
- })
- }
+ display(president)
}.then { activity ->
assertEquals(PRESIDENT_NAME_1, (activity.findViewById(tvName) as TextView).text)
president.name = PRESIDENT_NAME_16
@@ -301,7 +250,6 @@
}
@Test
- @Suppress("PLUGIN_WARNING")
fun testModelUpdatesNextFrameVisibility() {
val president = frame {
Person(
@@ -311,37 +259,17 @@
}
val tvName = 204
- fun ViewComposer.display(person: Person) {
- call(167, { true }) {
- (Observe {
- emit(93, { context -> TextView(context).apply { id = tvName } }) {
- set(person.name) { text = it }
- }
- emit(94, { context -> TextView(context) }) {
- set(person.age) {
- text = it.toString()
- }
- }
- })
- if (person.name == PRESIDENT_NAME_16) {
- (Observe {
- emit(211, { context -> TextView(context) }) {
- set(person.name) { text = it }
- }
- emit(211, { context -> TextView(context) }) {
- set(person.age) { text = it.toString() }
- }
- })
- }
+ @Composable fun display(person: Person) {
+ TextView(id = tvName, text = person.name)
+ TextView(text = person.age)
+ if (person.name == PRESIDENT_NAME_16) {
+ TextView(text = person.name)
+ TextView(text = person.age)
}
}
compose {
- call(219, { true }) {
- (Observe {
- display(president)
- })
- }
+ display(president)
}.then { activity ->
assertEquals(PRESIDENT_NAME_1, (activity.findViewById(tvName) as TextView).text)
// schedule commit and recompose by this change, all for next frame
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/ComposerExtensions.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/ComposerExtensions.kt
deleted file mode 100644
index e0d881b..0000000
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/ComposerExtensions.kt
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose
-
-import android.content.Context
-import android.view.View
-import android.view.ViewGroup
-
-inline fun ViewComposer.group(key: Int, block: () -> Unit) {
- try {
- startGroup(key)
- block()
- } finally {
- endGroup()
- }
-}
-
-fun ViewComposer.emitComponent(
- loc: Int,
- block: @Composable() () -> Unit
-): Unit = emitComponent(loc, null, block)
-
-fun ViewComposer.emitComponent(
- loc: Int,
- key: Int?,
- block: @Composable() () -> Unit
-): Unit = emitComponent(loc, key, { true }, block)
-
-fun ViewComposer.emitComponent(
- loc: Int,
- key: Int?,
- invalid: ViewValidator.() -> Boolean,
- block: @Composable() () -> Unit
-): Unit = call(joinKey(loc, key), invalid, block)
-
-inline fun <reified T : View> ViewComposer.emitView(
- loc: Int,
- ctor: (context: Context) -> T,
- noinline updater: ViewUpdater<T>.() -> Unit
-): Unit = emitView(loc, null, ctor, updater)
-
-inline fun <reified T : View> ViewComposer.emitView(
- loc: Int,
- ctor: (context: Context) -> T
-): Unit = emitView(loc, null, ctor, {})
-
-inline fun <reified T : View> ViewComposer.emitView(
- loc: Int,
- key: Int?,
- ctor: (context: Context) -> T
-): Unit = emitView(loc, key, ctor, {})
-
-inline fun <reified T : View> ViewComposer.emitView(
- loc: Int,
- key: Int?,
- ctor: (context: Context) -> T,
- noinline updater: ViewUpdater<T>.() -> Unit
-): Unit = emit(
- joinKey(loc, key),
- ctor,
- updater
-)
-
-inline fun <reified T : ViewGroup> ViewComposer.emitViewGroup(
- loc: Int,
- ctor: (context: Context) -> T,
- noinline updater: ViewUpdater<T>.() -> Unit,
- block: @Composable() () -> Unit
-) = emitViewGroup(loc, null, ctor, updater, block)
-
-inline fun <reified T : ViewGroup> ViewComposer.emitViewGroup(
- loc: Int,
- key: Int?,
- ctor: (context: Context) -> T,
- noinline updater: ViewUpdater<T>.() -> Unit,
- block: @Composable() () -> Unit
-) = emit(
- joinKey(loc, key),
- ctor,
- updater,
- block
-)
-
-inline fun <reified T : Emittable> ViewComposer.emitEmittable(
- loc: Int,
- ctor: () -> T,
- noinline updater: ViewUpdater<T>.() -> Unit
-) = emitEmittable(loc, null, ctor, updater, {})
-
-inline fun <reified T : Emittable> ViewComposer.emitEmittable(
- loc: Int,
- ctor: () -> T,
- noinline updater: ViewUpdater<T>.() -> Unit,
- block: @Composable() () -> Unit
-) = emitEmittable(loc, null, ctor, updater, block)
-
-inline fun <reified T : Emittable> ViewComposer.emitEmittable(
- loc: Int,
- key: Int?,
- ctor: () -> T,
- noinline updater: ViewUpdater<T>.() -> Unit,
- block: @Composable() () -> Unit
-) = emit(
- joinKey(loc, key),
- ctor,
- updater,
- block
-)
-
-@Suppress("PLUGIN_ERROR")
-inline fun <reified T> ViewComposer.provideAmbient(
- key: ProvidableAmbient<T>,
- value: T,
- noinline children: @Composable() () -> Unit
-) = call(
- 0,
- { changed(key) + changed(value) + changed(children) },
- { Providers(key provides value, children = children) }
-)
\ No newline at end of file
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/DisposeTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/DisposeTests.kt
index b46b8c1..0b163c1 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/DisposeTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/DisposeTests.kt
@@ -38,21 +38,16 @@
val log = mutableListOf<String>()
val composable = @Composable {
- val cc = composer
- cc.call(1, { true }) {
- onPreCommit {
- log.add("onPreCommit")
- onDispose {
- log.add("onPreCommitDispose")
- }
+ onPreCommit {
+ log.add("onPreCommit")
+ onDispose {
+ log.add("onPreCommitDispose")
}
}
- cc.call(2, { true }) {
- onActive {
- log.add("onActive")
- onDispose {
- log.add("onActiveDispose")
- }
+ onActive {
+ log.add("onActive")
+ onDispose {
+ log.add("onActiveDispose")
}
}
}
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/EffectsTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/EffectsTests.kt
index cb8d6ba..0f95165 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/EffectsTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/EffectsTests.kt
@@ -29,7 +29,6 @@
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
-@Suppress("PLUGIN_WARNING")
class EffectsTests : BaseComposeTest() {
@After
fun teardown() {
@@ -95,11 +94,7 @@
compose {
local = state { "Hello world! ${inc++}" }
- emit(
- 168,
- { context -> TextView(context).apply { id = tv1Id } },
- { set(local.value) { text = it } }
- )
+ TextView(id=tv1Id, text = local.value)
}.then { activity ->
val helloText = activity.findViewById(tv1Id) as TextView
assertEquals("Hello world! 0", helloText.text)
@@ -127,16 +122,8 @@
compose {
local1 = state { "First" }
local2 = state { "Second" }
- emit(
- 168,
- { context -> TextView(context).apply { id = tv1Id } },
- { set(local1.value) { text = it } }
- )
- emit(
- 169,
- { context -> TextView(context).apply { id = tv2Id } },
- { set(local2.value) { text = it } }
- )
+ TextView(id=tv1Id, text = local1.value)
+ TextView(id=tv2Id, text = local2.value)
}.then { activity ->
val tv1 = activity.findViewById(tv1Id) as TextView
val tv2 = activity.findViewById(tv2Id) as TextView
@@ -185,11 +172,7 @@
compose {
log("compose:start")
if (mount) {
- call(
- 168,
- { true },
- { @Suppress("PLUGIN_ERROR") Unmountable() }
- )
+ Unmountable()
}
log("compose:end")
}.then { _ ->
@@ -230,46 +213,34 @@
@Composable
fun Unmountable() {
- composer.call(123, { true }) {
- onPreCommit {
- log("onPreCommit:a2")
- onDispose {
- log("onDispose:a2")
- }
+ onPreCommit {
+ log("onPreCommit:a2")
+ onDispose {
+ log("onDispose:a2")
}
}
- composer.call(234, { true }) {
- onPreCommit {
- log("onPreCommit:b2")
- onDispose {
- log("onDispose:b2")
- }
+ onPreCommit {
+ log("onPreCommit:b2")
+ onDispose {
+ log("onDispose:b2")
}
}
}
compose {
- call(345, { true }) {
- onPreCommit {
- log("onPreCommit:a1")
- onDispose {
- log("onDispose:a1")
- }
+ onPreCommit {
+ log("onPreCommit:a1")
+ onDispose {
+ log("onDispose:a1")
}
}
if (mount) {
- call(
- 168,
- { true },
- { @Suppress("PLUGIN_ERROR") Unmountable() }
- )
+ Unmountable()
}
- call(456, { true }) {
- onPreCommit {
- log("onPreCommit:b1")
- onDispose {
- log("onDispose:b1")
- }
+ onPreCommit {
+ log("onPreCommit:b1")
+ onDispose {
+ log("onDispose:b1")
}
}
}.then { _ ->
@@ -454,11 +425,7 @@
}
}
- call(
- 1234,
- { true },
- { @Suppress("PLUGIN_ERROR") Sub() }
- )
+ Sub()
}.then { _ ->
log("recompose")
}.recomposeRoot().then { _ ->
@@ -487,24 +454,14 @@
val logHistory = mutableListOf<String>()
fun log(x: String) = logHistory.add(x)
- fun DisposeLogger(msg: String) {
+ @Composable fun DisposeLogger(msg: String) {
onDispose { log(msg) }
}
compose {
- with(composer) {
- call(
- 168,
- { true },
- { @Suppress("PLUGIN_ERROR") DisposeLogger(msg = "onDispose:1") }
- )
- if (mount) {
- call(
- 169,
- { true },
- { @Suppress("PLUGIN_ERROR") DisposeLogger(msg = "onDispose:2") }
- )
- }
+ DisposeLogger(msg = "onDispose:1")
+ if (mount) {
+ DisposeLogger(msg = "onDispose:2")
}
}.then { _ ->
assertArrayEquals(
@@ -553,17 +510,11 @@
}
compose {
- with(composer) {
log("compose:start")
if (mount) {
- call(
- 168,
- { true },
- { @Suppress("PLUGIN_ERROR") Unmountable() }
- )
+ Unmountable()
}
log("compose:end")
- }
}.then { _ ->
assertArrayEquals(
listOf(
@@ -608,30 +559,13 @@
@Composable
fun Bar() {
- composer.call(
- 21323,
- { true },
- {
- @Suppress("PLUGIN_ERROR")
- (Observe {
- val foo = Foo.current
- composer.emit(
- 168,
- { context -> TextView(context).apply { id = tv1Id } },
- { set(foo) { text = it } }
- )
- })
- }
- )
+ val foo = Foo.current
+ TextView(id = tv1Id, text = foo)
}
compose {
- provideAmbient(Foo, current) {
- call(
- 123,
- { false },
- { @Suppress("PLUGIN_ERROR") Bar() }
- )
+ Providers(Foo provides current) {
+ Bar()
}
}.then { activity ->
val helloText = activity.findViewById(tv1Id) as TextView
@@ -649,54 +583,41 @@
val MyAmbient = ambientOf<Int> { throw Exception("not set") }
var requestRecompose: (() -> Unit)? = null
- var buttonCreated = false
val ambientValue = mutableStateOf(1)
- fun SimpleComposable2() {
- Observe {
- with(composer) {
- val value = MyAmbient.current
- emit(534, { context -> TextView(context) }, {
- set("$value") { text = it }
- })
+ @Composable fun SimpleComposable2() {
+ val value = MyAmbient.current
+ TextView(text = "$value")
+ }
+
+ @Composable fun SimpleComposable() {
+ Recompose {
+ requestRecompose = it
+ Providers(MyAmbient provides ambientValue.value++) {
+ SimpleComposable2()
+ Button(id=123)
}
}
}
- fun SimpleComposable() {
- composer.call(531, { true }) {
- Recompose {
- requestRecompose = it
- composer.provideAmbient(MyAmbient, ambientValue.value++) {
- composer.call(523, { false }) { SimpleComposable2() }
- composer.emitView(525) { context ->
- Button(context).also {
- buttonCreated = true
- }
- }
- }
- }
- }
+ @Composable fun Root() {
+ SimpleComposable()
}
- fun Root() {
- with(composer) {
- call(547, { false }) {
- SimpleComposable()
- }
- }
- }
+ var firstButton: Button? = null
compose {
- call(556, { false }) {
- Root()
- }
+ Root()
}.then {
- assertTrue("Expected button to be created", buttonCreated)
- buttonCreated = false
+ firstButton = it.findViewById<Button>(123)
+ assertTrue("Expected button to be created", firstButton != null)
requestRecompose?.invoke()
}.then {
- assertFalse("Expected button to not be recreated", buttonCreated)
+ assertEquals(
+ "Expected button to not be recreated",
+ it.findViewById<Button>(123),
+ firstButton
+ )
}
}
@@ -706,59 +627,45 @@
val MyAmbient = ambientOf<Int> { throw Exception("not set") }
var requestRecompose: (() -> Unit)? = null
- var buttonCreated = false
var componentComposed = false
val ambientValue = mutableStateOf(1)
- fun SimpleComposable2() {
- with(composer) {
- startRestartGroup(712)
- componentComposed = true
- val value = MyAmbient.current
- emit(534, { context -> TextView(context) }, {
- set("$value") { text = it }
- })
- endRestartGroup()?.updateScope { SimpleComposable2() }
+ @Composable fun SimpleComposable2() {
+ componentComposed = true
+ val value = MyAmbient.current
+ TextView(text="$value")
+ }
+
+ @Composable fun SimpleComposable() {
+ requestRecompose = invalidate
+ Providers(MyAmbient provides ambientValue.value++) {
+ SimpleComposable2()
+ Button(id=123)
}
}
- fun SimpleComposable() {
- composer.call(531, { true }) {
- Recompose {
- requestRecompose = it
- composer.provideAmbient(MyAmbient, ambientValue.value++) {
- composer.call(523, { false }) { SimpleComposable2() }
- composer.emitView(525) { context ->
- Button(context).also {
- buttonCreated = true
- }
- }
- }
- }
- }
+ @Composable fun Root() {
+ SimpleComposable()
}
- fun Root() {
- with(composer) {
- call(547, { false }) {
- SimpleComposable()
- }
- }
- }
+ var firstButton: Button? = null
compose {
- call(556, { false }) {
- Root()
- }
+ Root()
}.then {
assertTrue("Expected component to be composed", componentComposed)
- assertTrue("Expected button to be created", buttonCreated)
- buttonCreated = false
+ firstButton = it.findViewById<Button>(123)
+ assertTrue("Expected button to be created", firstButton != null)
componentComposed = false
requestRecompose?.invoke()
}.then {
assertTrue("Expected component to be composed", componentComposed)
- assertFalse("Expected button to not be recreated", buttonCreated)
+
+ assertEquals(
+ "Expected button to not be recreated",
+ firstButton,
+ it.findViewById<Button>(123)
+ )
}
}
@@ -769,11 +676,7 @@
compose {
val local = state { "Hello world! ${inc++}" }
- emit(
- 168,
- { context -> TextView(context).apply { id = tv1Id } },
- { set(local.value) { text = it } }
- )
+ TextView(id = tv1Id, text=local.value)
}.then { activity ->
val helloText = activity.findViewById(tv1Id) as TextView
assertEquals("Hello world! 0", helloText.text)
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/HotReloadTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/HotReloadTests.kt
index b40c3be..016316d 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/HotReloadTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/HotReloadTests.kt
@@ -104,48 +104,22 @@
}
}
-fun text(text: String, id: Int = -1) {
- composer.emit(
- 48,
- { context ->
- TextView(context).apply {
- if (id >= 0) this.id = id
- }
- },
- {
- set(text) { this.text = it }
- }
- )
+@Composable fun text(text: String, id: Int = -1) {
+ TextView(id=id, text=text)
}
-fun column(children: () -> Unit) {
- composer.emit(
- key = 59,
- ctor = { context ->
- LinearLayout(context)
- },
- update = { },
- children = children as (@Composable() () -> Unit)
- )
+@Composable fun column(children: @Composable() () -> Unit) {
+ LinearLayout { children() }
}
-fun textNode(text: String) {
- composer.emit(
- key = 93,
- ctor = { Node("Text") } as () -> Node,
- update = {
- set(text) { this.value = it }
- }
- )
+@Composable fun textNode(text: String) {
+ Node(name="Text", value=text)
}
-fun columnNode(children: () -> Unit) {
- composer.emit(
- key = 93,
- ctor = { Node("Text") } as () -> Node,
- update = { },
- children = children as (@Composable() () -> Unit)
- )
+@Composable fun columnNode(children: @Composable() () -> Unit) {
+ Node(name="Text") {
+ children()
+ }
}
class Node(val name: String, var value: String = "") : Emittable {
@@ -172,14 +146,14 @@
}
}
-fun Activity.setContent(content: () -> Unit) {
+fun Activity.setContent(content: @Composable() () -> Unit) {
val composeView = contentView as? ViewEmitWrapper
?: ViewEmitWrapper(this).also {
setContentView(it)
}
val root = Node("Root")
composeView.emittable = root
- Compose.composeInto(root, this, null, content as (@Composable() () -> Unit))
+ Compose.composeInto(root, this, null, content)
}
val Activity.contentView: View get() =
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/NewCodeGenTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/NewCodeGenTests.kt
index a10cf8a..fe4c2a4 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/NewCodeGenTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/NewCodeGenTests.kt
@@ -42,22 +42,9 @@
val tv2Id = 200
compose {
- emit(168, { context ->
- TextView(context).apply {
- text = "Hello world!"; id = tv1Id
- }
- }) { }
-
- emit(170, { context ->
- LinearLayout(context).apply {
- orientation = LinearLayout.HORIZONTAL
- }
- }, { }) {
- emit(171, { context ->
- TextView(context).apply {
- text = "Yellow world"; id = tv2Id
- }
- }) { }
+ TextView(id=tv1Id, text="Hello world!")
+ LinearLayout(orientation = LinearLayout.HORIZONTAL) {
+ TextView(id=tv2Id, text="Yellow world")
}
}.then { activity ->
val helloText = activity.findViewById(tv1Id) as TextView
@@ -79,19 +66,9 @@
var text2 by mutableStateOf("Yellow world")
compose {
- emit(168, { context -> TextView(context)
- .apply { id = tv1Id } }) {
- set(text1) { text = it }
- }
- emit(170, { context ->
- LinearLayout(context).apply {
- orientation = LinearLayout.HORIZONTAL
- }
- }, { }) {
- emit(171, { context -> TextView(context)
- .apply { id = tv2Id } }) {
- set(text2) { text = it }
- }
+ TextView(id=tv1Id, text=text1)
+ LinearLayout(orientation = LinearLayout.HORIZONTAL) {
+ TextView(id=tv2Id, text=text2)
}
}.then { activity ->
val helloText = activity.findViewById(tv1Id) as TextView
@@ -117,10 +94,7 @@
compose {
// <TextView text id=tvId />
- emit(242, { context -> TextView(context)
- .apply { id = tvId } }) {
- set(text) { this.text = it }
- }
+ TextView(id=tvId, text=text)
}.then { activity ->
val tv = activity.findViewById(tvId) as TextView
TestCase.assertEquals("Hello world", tv.text)
@@ -143,15 +117,8 @@
// <LinearLayout>
// <TextView text />
// </LinearLayout
- emit(264, { context: Context -> LinearLayout(
- context
- ).apply { id = llId } }, {
- set(orientation) { this.orientation = it }
- }) {
- emit(265, { context -> TextView(context)
- .apply { id = tvId } }) {
- set(text) { this.text = it }
- }
+ LinearLayout(id = llId, orientation=orientation) {
+ TextView(id=tvId, text=text)
}
}.then { activity ->
val tv = activity.findViewById(tvId) as TextView
@@ -185,20 +152,16 @@
// phoneCalled++
// TextView(text="...")
// }
- fun PhoneView(phone: Phone) {
+ @Composable fun PhoneView(phone: Phone) {
phoneCalled++
- emit(225, { context -> TextView(context) }) {
- set(
- "${if (phone.area.isBlank()) ""
- else "(${phone.area}) "}${phone.prefix}-${phone.number}"
- ) { text = it }
- }
+ TextView(
+ text="${if (phone.area.isBlank()) ""
+ else "(${phone.area}) "}${phone.prefix}-${phone.number}"
+ )
}
// <PhoneView phone />
- call(453, { changed(phone) }) {
- PhoneView(phone)
- }
+ PhoneView(phone)
}.then { _ ->
TestCase.assertEquals(1, phoneCalled)
}.recomposeRoot().then { _ ->
@@ -224,92 +187,13 @@
// addCalled++
// <TextView text="$left + $right = ${left + right}" />
// }
- fun AddView(left: Int, right: Int) {
+ @Composable fun AddView(left: Int, right: Int) {
addCalled++
- emit(292, { context -> TextView(context)
- .apply { id = tvId } }) {
- set("$left + $right = ${left + right}") { text = it }
- }
+ TextView(id=tvId, text="$left + $right = ${left + right}")
}
// <AddView left right />
- call(491, { changed(left) + changed(right) }) {
- AddView(left, right)
- }
- }.then { activity ->
- TestCase.assertEquals(1, addCalled)
- val tv = activity.findViewById(tvId) as TextView
- TestCase.assertEquals(
- "$left + $right = ${left + right}",
- tv.text
- )
- }.recomposeRoot().then { activity ->
- TestCase.assertEquals(1, addCalled)
- val tv = activity.findViewById(tvId) as TextView
- TestCase.assertEquals(
- "$left + $right = ${left + right}",
- tv.text
- )
-
- left = 1
- }.then { activity ->
- TestCase.assertEquals(2, addCalled)
-
- val tv = activity.findViewById(tvId) as TextView
- TestCase.assertEquals(
- "$left + $right = ${left + right}",
- tv.text
- )
- }.recomposeRoot().then { activity ->
- TestCase.assertEquals(2, addCalled)
-
- val tv = activity.findViewById(tvId) as TextView
- TestCase.assertEquals(
- "$left + $right = ${left + right}",
- tv.text
- )
-
- right = 41
- }.then { activity ->
- TestCase.assertEquals(3, addCalled)
-
- val tv = activity.findViewById(tvId) as TextView
- TestCase.assertEquals(
- "$left + $right = ${left + right}",
- tv.text
- )
- }
- }
-
- @Test
- fun testStatelessComposableClassInvocationParameters() {
- val tvId = 338
- var addCalled = 0
-
- var left by mutableStateOf(0)
- var right by mutableStateOf(0)
-
- compose {
- // TODO: The composition field is a work-around for an IR bug. The IR doesn't support a
- // local class capturing a variable so this make the capture explicit
- class AddView(val composition: ViewComposer) {
-
- operator fun invoke(left: Int, right: Int) {
- with(composition) {
- // <TextView "$left + $right = ${left + right}" />
- emit(350, { context -> TextView(context)
- .apply { id = tvId } }) {
- addCalled++
- set("$left + $right = ${left + right}") { text = it }
- }
- }
- }
- }
-
- // <AddView left right />
- call(612, { changed(left) + changed(right) }) {
- AddView(this@compose)(left, right)
- }
+ AddView(left, right)
}.then { activity ->
TestCase.assertEquals(1, addCalled)
val tv = activity.findViewById(tvId) as TextView
@@ -360,9 +244,9 @@
val data = mutableListOf(1, 2, 3, 4, 5)
compose {
for (item in data) {
- emit(joinKey(560, item), { context ->
- TextView(context).apply { text = "$item View" }
- }) { }
+ key(item) {
+ TextView(text="$item View")
+ }
}
}.then {
data.add(data.removeAt(0))
@@ -391,9 +275,9 @@
var hello by mutableStateOf("Hello world!")
compose {
// <MyTextView someText=hello />
- emit(joinKey(760, hello), { context ->
- MyTextView(context, hello).apply { id = tvId }
- }) { }
+ key(hello) {
+ MyTextView(id=tvId, someText=hello)
+ }
}.then { activity ->
val tv = activity.findViewById(tvId) as TextView
TestCase.assertEquals("Hello world!", tv.text)
@@ -415,10 +299,7 @@
var value by mutableStateOf("Unmodified")
compose {
// <MyTextView someText=hello />
- emit(760, { context -> MyTextView(context, value).apply { id = tvId } }) {
- update(value) { someValue = it }
- set(hello) { this.text = it }
- }
+ MyTextView(id=tvId, someValue=value, text=hello)
}.then { activity ->
val tv = activity.findViewById(tvId) as MyTextView
TestCase.assertEquals("Hello world!", tv.text)
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RecomposerTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RecomposerTests.kt
index 1817d20..8a781a4 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RecomposerTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RecomposerTests.kt
@@ -44,11 +44,7 @@
@Test
fun testNativeViewWithAttributes() {
compose {
- // TextView(id=456 text="some text")
- emitView(123, ::TextView) {
- set(456) { id = it }
- set("some text") { text = it }
- }
+ TextView(id=456, text="some text")
}.then { activity ->
assertEquals(1, activity.root.childCount)
@@ -67,10 +63,8 @@
// this should cause the textview to get recreated on every compose
i++
- // TextView(id=456 text="some text")
- emitView(i, ::TextView) {
- set(456) { id = it }
- set("some text") { text = it }
+ key(i) {
+ TextView(id=456, text="some text")
}
}.then { activity ->
tv1 = activity.findViewById(456) as TextView
@@ -95,20 +89,9 @@
@Test
fun testViewWithViewChildren() {
compose {
- // LinearLayout(id = 345) {>
- emitViewGroup(100, ::LinearLayout, {
- set(345) { id = it }
- }) {
- // TextView(id = 456, text="some text")
- emitView(101, ::TextView) {
- set(456) { id = it }
- set("some text") { text = it }
- }
- // TextView(id = 567, text="some text")
- emitView(102, ::TextView) {
- set(567) { id = it }
- set("some text") { text = it }
- }
+ LinearLayout(id = 345) {
+ TextView(id = 456, text="some text")
+ TextView(id = 567, text="some text")
}
}.then { activity ->
val ll = activity.findViewById(345) as LinearLayout
@@ -133,16 +116,9 @@
fun testForLoop() {
val items = listOf(1, 2, 3, 4, 5, 6)
compose {
- // this should cause the TextView to get recreated on every compose
- emitViewGroup(100, ::LinearLayout, {
- set(345) { id = it }
- }) {
+ LinearLayout(id = 345) {
for (i in items) {
- // TextView(id=456, text="some text")
- emitView(101, ::TextView) {
- set(456) { id = it }
- set("some text $i") { text = it }
- }
+ TextView(id=456, text="some text $i")
}
}
}.then { activity ->
@@ -165,13 +141,10 @@
val counter = Counter()
compose {
- // <A />
- emitComponent(123) {
- RecomposeTestComponents.A(
- counter,
- RecomposeTestComponents.ClickAction.Recompose
- )
- }
+ RecomposeTestComponents.A(
+ counter,
+ RecomposeTestComponents.ClickAction.Recompose
+ )
}.then { activity ->
// everything got rendered once
assertEquals(1, counter["A"])
@@ -218,13 +191,10 @@
}
compose {
- // <A />
- emitComponent(123) {
- RecomposeTestComponents.A(
- counter,
- listener
- )
- }
+ RecomposeTestComponents.A(
+ counter,
+ listener
+ )
}.then { activity ->
invalidate = invalidateRoot
// everything got rendered once
@@ -269,60 +239,34 @@
}
@Composable fun B(counter: Counter, listener: ClickAction, id: Int = 0) {
- with(composer) {
- startRestartGroup(0)
- counter.inc("$id")
+ counter.inc("$id")
- val recompose = invalidate
+ val recompose = invalidate
- // <TextView id={id} clickAction() }} />
- emitView(24, ::TextView) {
- set(id) { this.id = it }
- set(View.OnClickListener {
- @Suppress("DEPRECATION")
- when (listener) {
- is ClickAction.Recompose -> recompose()
- is ClickAction.PerformOnView -> listener.action.invoke(it)
- }
- }) { setOnClickListener(it) }
+ TextView(id=id, >
+ @Suppress("DEPRECATION")
+ when (listener) {
+ is ClickAction.Recompose -> recompose()
+ is ClickAction.PerformOnView -> listener.action.invoke(it)
}
- endRestartGroup()?.updateScope { B(counter, listener, id) }
- }
+ })
}
@Composable fun A(counter: Counter, listener: ClickAction) {
- with(composer) {
- startRestartGroup(0)
- counter.inc("A")
- val recompose = invalidate
- // LinearLayout( clickAction() }. id=99) {
- // B(id=100)
- // B(id=101)
- // B(id=102)
- // }
-
- // LinearLayout(id=99, clickAction() }) { />
- emitViewGroup(897, ::LinearLayout, {
- set(99) { id = it }
- set(View.OnClickListener {
- @Suppress("DEPRECATION")
- when (listener) {
- is ClickAction.Recompose -> recompose()
- is ClickAction.PerformOnView -> listener.action.invoke(it)
- }
- }) { setOnClickListener(it) }
- }) {
- for (id in 100..102) {
- // B(key=id, id=id)
- emitComponent(
- 878983,
- id,
- { false },
- { B(counter, listener, id) }
- )
+ counter.inc("A")
+ val recompose = invalidate
+ LinearLayout(id=99, >
+ @Suppress("DEPRECATION")
+ when (listener) {
+ is ClickAction.Recompose -> recompose()
+ is ClickAction.PerformOnView -> listener.action.invoke(it)
+ }
+ }) {
+ for (id in 100..102) {
+ key(id) {
+ B(counter, listener, id)
}
}
- endRestartGroup()?.updateScope { A(counter, listener) }
}
}
}
@@ -330,17 +274,11 @@
@Test
fun testCorrectViewTree() {
compose {
- // LinearLayout {
- // LinearLayout { }
- // LinearLayout { }
- // }
- // LinearLayout { }
-
- emitViewGroup(123, ::LinearLayout, {}) {
- emitView(123, ::LinearLayout)
- emitView(123, ::LinearLayout)
- }
- emitView(123, ::LinearLayout)
+ LinearLayout {
+ LinearLayout { }
+ LinearLayout { }
+ }
+ LinearLayout { }
}.then { activity ->
assertChildHierarchy(activity.root) {
"""
@@ -358,30 +296,18 @@
fun testCorrectViewTreeWithComponents() {
@Composable fun B() {
- with(composer) {
- // TextView()
- emitView(123, ::TextView)
- }
+ TextView()
}
compose {
- // LinearLayout {
- // LinearLayout {
- // B()
- // }
- // LinearLayout {
- // B()
- // }
- // }
-
- emitViewGroup(123, ::LinearLayout, {}) {
- emitViewGroup(123, ::LinearLayout, {}) {
- emitComponent(123, { B() })
- }
- emitViewGroup(123, ::LinearLayout, {}) {
- emitComponent(123, { B() })
- }
- }
+ LinearLayout {
+ LinearLayout {
+ B()
+ }
+ LinearLayout {
+ B()
+ }
+ }
}.then { activity ->
assertChildHierarchy(activity.root) {
@@ -403,32 +329,19 @@
fun testCorrectViewTreeWithComponentWithMultipleRoots() {
@Composable fun B() {
- with(composer) {
- // TextView()
- emitView(123, ::TextView)
- // TextView()
- emitView(124, ::TextView)
- }
+ TextView()
+ TextView()
}
compose {
- // LinearLayout {
- // LinearLayout {
- // B()
- // }
- // LinearLayout {
- // B()
- // }
- // }
-
- emitViewGroup(123, ::LinearLayout, {}) {
- emitViewGroup(123, ::LinearLayout, {}) {
- emitComponent(123, { B() })
- }
- emitViewGroup(123, ::LinearLayout, {}) {
- emitComponent(123, { B() })
- }
- }
+ LinearLayout {
+ LinearLayout {
+ B()
+ }
+ LinearLayout {
+ B()
+ }
+ }
}.then {
assertChildHierarchy(activity.root) {
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RestartTests.kt b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RestartTests.kt
index c1b2fec..6747f4c 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RestartTests.kt
+++ b/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/RestartTests.kt
@@ -47,22 +47,10 @@
)
}
- @Suppress("PLUGIN_WARNING")
compose {
- call(147, { true }) {
-
- RestartGroup(object : Function0<Unit> {
- override fun invoke() {
- startRestartGroup(54)
- emit(93, { context -> TextView(context).apply { id = tvIdName } }) {
- set(president.name) { text = it }
- }
- emit(94, { context -> TextView(context).apply { id = tvIdAge } }) {
- set(president.age) { text = it.toString() }
- }
- endRestartGroup()?.updateScope(this)
- }
- })
+ RestartGroup {
+ TextView(id=tvIdName, text=president.name)
+ TextView(id=tvIdAge, text=president.age)
}
}.then {
val tvName = it.findViewById(tvIdName) as TextView
@@ -91,26 +79,10 @@
)
}
- @Suppress("PLUGIN_WARNING")
compose {
- call(147, { true }) {
-
- Repeat(5, object : Function1<Int, Unit> {
- override fun invoke(index: Int) {
- startRestartGroup(98)
- emit(93, { context -> TextView(context).apply {
- id = tvIdNameBase + index
- } }) {
- set(president.name) { text = it }
- }
- emit(94, { context -> TextView(context).apply {
- id = tvIdAgeBase + index
- } }) {
- set(president.age) { text = it.toString() }
- }
- endRestartGroup()?.updateScope { this(index) }
- }
- })
+ Repeat(5) { index ->
+ TextView(id=tvIdNameBase + index, text=president.name)
+ TextView(id=tvIdAgeBase + index, text=president.age.toString())
}
}.then { activity ->
repeat(5) { index ->
@@ -143,21 +115,13 @@
)
}
- fun ViewComposer.PersonView() {
- startRestartGroup(145)
- emit(93, { context -> TextView(context).apply { id = tvIdName } }) {
- set(president.name) { text = it }
- }
- emit(94, { context -> TextView(context).apply { id = tvIdAge } }) {
- set(president.age) { text = it.toString() }
- }
- endRestartGroup()?.updateScope { PersonView() }
+ @Composable fun PersonView() {
+ TextView(id=tvIdName, text=president.name)
+ TextView(id=tvIdAge, text=president.age.toString())
}
compose {
- call(145, { true }) {
- PersonView()
- }
+ PersonView()
}.then {
val tvName = it.findViewById(tvIdName) as TextView
val tvAge = it.findViewById(tvIdAge) as TextView
@@ -181,22 +145,16 @@
mutableStateOf(true)
}
- fun ViewComposer.ShowSomething() {
- startRestartGroup(183)
- emit(181, { context -> TextView(context).apply { id = tvStateId } }) {
- set("State = ${state.value}") { text = it }
- }
- endRestartGroup()?.updateScope { ShowSomething() }
+ @Composable fun ShowSomething() {
+ TextView(id=tvStateId, text="State = ${state.value}")
}
- fun ViewComposer.View() {
- startRestartGroup(191)
+ @Composable fun View() {
if (state.value) {
// This is not correct code generation as this should be called in a call function, however, this
// tests the assumption that calling a function should produce an item (a key followed by a group).
ShowSomething()
}
- endRestartGroup()?.updateScope { View() }
}
compose {
@@ -229,23 +187,14 @@
)
}
- fun ViewComposer.PersonView(index: Int) {
- startRestartGroup(231)
- emit(93, { context -> TextView(context).apply { id = tvIdNameBase + index } }) {
- set(president.name) { text = it }
- }
- emit(94, { context -> TextView(context).apply { id = tvIdAgeBase + index } }) {
- set(president.age) { text = it.toString() }
- }
- endRestartGroup()?.updateScope { PersonView(index) }
+ @Composable fun PersonView(index: Int) {
+ TextView(id=tvIdNameBase + index, text=president.name)
+ TextView(id=tvIdAgeBase + index, text=president.age.toString())
}
- @Suppress("PLUGIN_WARNING")
compose {
- call(147, { true }) {
- Repeat(5) { index ->
- PersonView(index)
- }
+ Repeat(5) { index ->
+ PersonView(index)
}
}.then { activity ->
repeat(5) { index ->
@@ -269,12 +218,12 @@
}
@Composable
-fun RestartGroup(block: () -> Unit) {
+fun RestartGroup(block: @Composable() () -> Unit) {
block()
}
@Composable
-fun Repeat(count: Int, block: (index: Int) -> Unit) {
+fun Repeat(count: Int, block: @Composable() (index: Int) -> Unit) {
for (i in 0 until count) {
block(i)
}
diff --git a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ViewComposer.kt b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ViewComposer.kt
index e3cfe6c..10ff800 100644
--- a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ViewComposer.kt
+++ b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ViewComposer.kt
@@ -171,13 +171,13 @@
endNode()
}
- @Suppress("PLUGIN_ERROR", "UNCHECKED_CAST")
+ @Suppress("UNCHECKED_CAST")
inline fun <T : ViewGroup> emit(
key: Any,
/*crossinline*/
ctor: (context: Context) -> T,
update: ViewUpdater<T>.() -> Unit,
- children: @Composable() () -> Unit
+ children: () -> Unit
) {
startNode(key)
val node = if (inserting) ctor(context).also { emitNode(it) }
@@ -201,13 +201,13 @@
endNode()
}
- @Suppress("PLUGIN_ERROR", "UNCHECKED_CAST")
+ @Suppress("UNCHECKED_CAST")
inline fun <T : Emittable> emit(
key: Any,
/*crossinline*/
ctor: () -> T,
update: ViewUpdater<T>.() -> Unit,
- children: @Composable() () -> Unit
+ children: () -> Unit
) {
startNode(key)
val node = if (inserting) ctor().also { emitNode(it) }
@@ -216,102 +216,6 @@
children()
endNode()
}
-
- @Suppress("PLUGIN_ERROR")
- inline fun call(
- key: Any,
- invalid: ViewValidator.() -> Boolean,
- block: @Composable() () -> Unit
- ) {
- startGroup(key)
- if (ViewValidator(this).invalid() || !skipping) {
- startGroup(invocation)
- block()
- endGroup()
- } else {
- skipCurrentGroup()
- }
- endGroup()
- }
-}
-
-/* inline */ class ViewValidator(val composer: Composer<*>) {
- // TODO: Add more overloads for common primitive types like String and Float etc to avoid boxing
- // and the immutable check
- @Suppress("NOTHING_TO_INLINE")
- fun changed(value: Int) = with(composer) {
- if ((nextSlot() as? Int)?.let { value != it } ?: true || inserting) {
- updateValue(value)
- true
- } else {
- skipValue()
- false
- }
- }
-
- fun <T> changed(value: T) = with(composer) {
- if (nextSlot() != value || inserting) {
- updateValue(value)
- true
- } else {
- skipValue()
- false
- }
- }
-
- @Suppress("NOTHING_TO_INLINE")
- fun updated(value: Int) = with(composer) {
- inserting.let { inserting ->
- if (((nextSlot() as? Int)?.let { it != value } ?: true) || inserting) {
- updateValue(value)
- !inserting
- } else {
- skipValue()
- false
- }
- }
- }
-
- fun <T> updated(value: T) = with(composer) {
- inserting.let { inserting ->
- if (nextSlot() != value || inserting) {
- updateValue(value)
- !inserting
- } else {
- skipValue()
- false
- }
- }
- }
-
- inline fun set(value: Int, /*crossinline*/ block: (value: Int) -> Unit): Boolean =
- changed(value).also { if (it) block(value) }
-
- inline fun <reified T> set(value: T, /*crossinline*/ block: (value: T) -> Unit): Boolean =
- changed(value).also { if (it) block(value) }
-
- inline fun update(value: Int, /*crossinline*/ block: (value: Int) -> Unit): Boolean =
- updated(value).also { if (it) block(value) }
-
- inline fun <reified T> update(value: T, /*crossinline*/ block: (value: T) -> Unit): Boolean =
- updated(value).also { if (it) block(value) }
-
- @Suppress("UNUSED")
- fun <T> changedUnchecked(@Suppress("UNUSED_PARAMETER") value: T) = true
-
- @Suppress("UNUSED")
- inline fun <T> setUnchecked(value: T, block: (value: T) -> Unit): Boolean {
- block(value)
- return true
- }
-
- @Suppress("UNUSED")
- inline fun <T> updateUnchecked(value: T, block: (value: T) -> Unit): Boolean {
- block(value)
- return true
- }
-
- /*inline*/ operator fun Boolean.plus(other: Boolean) = this || other
}
@Suppress("UNCHECKED_CAST")
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Ambient.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Ambient.kt
index 1642242..bef667b 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Ambient.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Ambient.kt
@@ -69,7 +69,7 @@
* @sample androidx.compose.samples.consumeAmbient
*/
@Composable
- inline val current: T get() = currentComposerNonNull.consume(this)
+ inline val current: T get() = currentComposerIntrinsic.consume(this)
}
/**
@@ -165,9 +165,7 @@
*/
@Composable
fun Providers(vararg values: ProvidedValue<*>, children: @Composable() () -> Unit) {
- with(currentComposerNonNull) {
- startProviders(values)
- children()
- endProviders()
- }
+ currentComposerIntrinsic.startProviders(values)
+ children()
+ currentComposerIntrinsic.endProviders()
}
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
index a099dcb..784a058 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
@@ -224,6 +224,7 @@
@Suppress("UNCHECKED_CAST")
internal fun <T> AmbientMap.getValueOf(key: Ambient<T>) = this[key as Ambient<Any?>]?.value as T
+@Composable
private fun ambientMapOf(values: Array<out ProvidedValue<*>>): AmbientMap {
val result: AmbientMap = buildableMapOf()
return result.mutate {
@@ -234,6 +235,11 @@
}
}
+interface ComposerValidator {
+ fun changed(value: Int): Boolean
+ fun <T> changed(value: T): Boolean
+}
+
// TODO(lmr): this could be named MutableTreeComposer
/**
* Implementation of a composer for mutable tree.
@@ -253,7 +259,7 @@
* Manager for scheduling recompositions.
*/
private val recomposer: Recomposer
-) {
+) : ComposerValidator {
private val changes = mutableListOf<Change<N>>()
private val lifecycleObservers = mutableMapOf<
CompositionLifecycleObserverHolder,
@@ -310,6 +316,22 @@
endRoot()
}
+ inline fun call(
+ key: Any,
+ invalid: ComposerValidator.() -> Boolean,
+ block: () -> Unit
+ ) {
+ startGroup(key)
+ if (this.invalid() || !skipping) {
+ startGroup(invocation)
+ block()
+ endGroup()
+ } else {
+ skipCurrentGroup()
+ }
+ endGroup()
+ }
+
/**
* Start the composition. This should be called, and only be called, as the first group in
* the composition.
@@ -587,7 +609,18 @@
*
* @param value the value to be compared.
*/
- fun <T> changed(value: T): Boolean {
+ override fun <T> changed(value: T): Boolean {
+ return if (nextSlot() != value || inserting) {
+ updateValue(value)
+ true
+ } else {
+ skipValue()
+ false
+ }
+ }
+
+ // TODO: Add more overloads for common primitive types like String and Float etc to avoid boxing
+ override fun changed(value: Int): Boolean {
return if (nextSlot() != value || inserting) {
updateValue(value)
true
@@ -687,7 +720,7 @@
// slots consumed depending on the content of values to remember, for example, the value
// holders used last time.
startGroup(providerValues)
- val currentProviders = ambientMapOf(values)
+ val currentProviders = invokeComposableForResult(this) { ambientMapOf(values) }
endGroup()
val providersStackSize = providersStack.size
val invalid = if (inserting) {
@@ -1761,7 +1794,21 @@
inline fun <T> escapeCompose(block: NullCompilationScope.() -> T) = NullCompilationScope.block()
@Composable
-@Suppress("UNUSED")
val currentComposerIntrinsic: Composer<*> get() {
throw NotImplementedError("Implemented as an intrinsic")
-}
\ No newline at end of file
+}
+
+internal fun invokeComposable(composer: Composer<*>, composable: @Composable() () -> Unit) {
+ @Suppress("UNCHECKED_CAST")
+ val realFn = composable as Function1<Composer<*>, Unit>
+ realFn(composer)
+}
+
+internal fun <T> invokeComposableForResult(
+ composer: Composer<*>,
+ composable: @Composable() () -> T
+): T {
+ @Suppress("UNCHECKED_CAST")
+ val realFn = composable as Function1<Composer<*>, T>
+ return realFn(composer)
+}
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Effects.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Effects.kt
index af305a0..b375be4 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Effects.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Effects.kt
@@ -162,7 +162,7 @@
*/
@Composable
fun onCommit(callback: CommitScope.() -> Unit) {
- currentComposerNonNull.changed(PostCommitScopeImpl(callback))
+ currentComposerIntrinsic.changed(PostCommitScopeImpl(callback))
}
/**
@@ -245,7 +245,7 @@
*/
@Composable
fun onPreCommit(callback: CommitScope.() -> Unit) {
- currentComposerNonNull.changed(PreCommitScopeImpl(callback))
+ currentComposerIntrinsic.changed(PreCommitScopeImpl(callback))
}
/**
@@ -356,11 +356,9 @@
*/
@Composable
val invalidate: () -> Unit get() {
- return currentComposerNonNull.let {
- val scope = it.currentRecomposeScope ?: error("no recompose scope found")
- scope.used = true
- return@let { scope.invalidate() }
- }
+ val scope = currentComposerIntrinsic.currentRecomposeScope ?: error("no recompose scope found")
+ scope.used = true
+ return { scope.invalidate() }
}
/**
@@ -370,7 +368,7 @@
*/
@Composable
fun compositionReference(): CompositionReference {
- return currentComposerNonNull.buildReference()
+ return currentComposerIntrinsic.buildReference()
}
/**
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
index 3aeacb5..e52d143 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
@@ -192,7 +192,6 @@
* @see [state]
* @see [stateFor]
*/
-@Model
private class ModelMutableState<T>(
value: T,
val areEquivalent: (old: T, new: T) -> Boolean
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
index 71d837d..a03ae9d 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
@@ -30,14 +30,4 @@
* @see Recompose
*/
@Composable
-fun Observe(body: @Composable() () -> Unit) {
- currentComposerNonNull.let { composer ->
- trace("Compose:Observe") {
- composer.startRestartGroup(observer)
- body()
- composer.endRestartGroup()?.updateScope { Observe(body) }
- }
- }
-}
-
-private val observer = Any()
\ No newline at end of file
+fun Observe(body: @Composable() () -> Unit) = body()
\ No newline at end of file
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
index 1d79067..3d01ced 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
@@ -36,13 +36,4 @@
* @see invalidate
*/
@Composable
-fun Recompose(body: @Composable() (recompose: () -> Unit) -> Unit) {
- val composer = currentComposerNonNull
- composer.startRestartGroup(recompose)
- body(invalidate)
- composer.endRestartGroup()?.updateScope {
- Recompose(body)
- }
-}
-
-private val recompose = Any()
+fun Recompose(body: @Composable() (recompose: () -> Unit) -> Unit) = body(invalidate)
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recomposer.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recomposer.kt
index 7280db0..2f4a5c6 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recomposer.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recomposer.kt
@@ -58,7 +58,7 @@
try {
composer.startRoot()
composer.startGroup(invocation)
- composable()
+ invokeComposable(composer, composable)
composer.endGroup()
composer.endRoot()
complete = true
@@ -81,7 +81,7 @@
private fun performRecompose(composer: Composer<*>): Boolean {
if (composer.isComposing) return false
return composer.runWithCurrent {
- var hadChanges: Boolean
+ val hadChanges: Boolean
try {
composer.isComposing = true
hadChanges = FrameManager.composing {
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Remember.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Remember.kt
index 06221bc..9b2ac06 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Remember.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Remember.kt
@@ -23,17 +23,16 @@
@Composable
inline fun <T> remember(calculation: () -> T): T =
- currentComposerNonNull.cache(true, calculation)
+ currentComposerIntrinsic.cache(true, calculation)
/**
* Remember the value returned by [calculation] if [v1] is equal to the previous composition, otherwise
* produce and remember a new value by calling [calculation].
*/
@Composable
-inline fun <T, /*reified*/ V1> remember(v1: V1, calculation: () -> T) = currentComposerNonNull
- .let {
- it.cache(!it.changed(v1), calculation)
- }
+inline fun <T, /*reified*/ V1> remember(v1: V1, calculation: () -> T): T {
+ return currentComposerIntrinsic.cache(!currentComposerIntrinsic.changed(v1), calculation)
+}
/**
* Remember the value returned by [calculation] if [v1] and [v2] are equal to the previous composition,
@@ -45,11 +44,9 @@
v2: V2,
calculation: () -> T
): T {
- return currentComposerNonNull.let {
- var valid = !it.changed(v1)
- valid = !it.changed(v2) && valid
- it.cache(valid, calculation)
- }
+ var valid = !currentComposerIntrinsic.changed(v1)
+ valid = !currentComposerIntrinsic.changed(v2) && valid
+ return currentComposerIntrinsic.cache(valid, calculation)
}
/**
@@ -63,12 +60,10 @@
v3: V3,
calculation: () -> T
): T {
- return currentComposerNonNull.let {
- var valid = !it.changed(v1)
- valid = !it.changed(v2) && valid
- valid = !it.changed(v3) && valid
- it.cache(valid, calculation)
- }
+ var valid = !currentComposerIntrinsic.changed(v1)
+ valid = !currentComposerIntrinsic.changed(v2) && valid
+ valid = !currentComposerIntrinsic.changed(v3) && valid
+ return currentComposerIntrinsic.cache(valid, calculation)
}
/**
@@ -77,11 +72,9 @@
*/
@Composable
inline fun <V> remember(vararg inputs: Any?, block: () -> V): V {
- return currentComposerNonNull.let {
- var valid = true
- for (input in inputs) valid = !it.changed(input) && valid
- it.cache(valid, block)
- }
+ var valid = true
+ for (input in inputs) valid = !currentComposerIntrinsic.changed(input) && valid
+ return currentComposerIntrinsic.cache(valid, block)
}
/**
diff --git a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/CompositionTests.kt b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/CompositionTests.kt
index 8e54777..bb9727459 100644
--- a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/CompositionTests.kt
+++ b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/CompositionTests.kt
@@ -13,23 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:Suppress("PLUGIN_ERROR")
package androidx.compose
-import androidx.compose.mock.Compose
import androidx.compose.mock.Contact
import androidx.compose.mock.ContactModel
+import androidx.compose.mock.MockComposeScope
import androidx.compose.mock.MockViewComposer
-import androidx.compose.mock.MockViewComposition
import androidx.compose.mock.MockViewValidator
import androidx.compose.mock.Point
import androidx.compose.mock.Report
import androidx.compose.mock.View
-import androidx.compose.mock.ViewComponent
-import androidx.compose.mock.call
import androidx.compose.mock.contact
import androidx.compose.mock.edit
-import androidx.compose.mock.join
import androidx.compose.mock.linear
import androidx.compose.mock.memoize
import androidx.compose.mock.points
@@ -37,12 +32,11 @@
import androidx.compose.mock.reportsReport
import androidx.compose.mock.reportsTo
import androidx.compose.mock.selectContact
-import androidx.compose.mock.set
import androidx.compose.mock.skip
import androidx.compose.mock.text
-import androidx.compose.mock.update
import androidx.compose.mock.validate
import org.junit.After
+import org.junit.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
@@ -52,15 +46,15 @@
@After
fun teardown() {
- androidx.compose.Compose.clearRoots()
+ Compose.clearRoots()
}
@Test
fun testComposeAModel() {
val model = testModel()
- val composer = compose(model)
+ val myComposer = compose(model)
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
linear {
text("Filter:")
@@ -81,11 +75,11 @@
@Test
fun testRecomposeWithoutChanges() {
val model = testModel()
- val composer = compose(model)
+ val myComposer = compose(model)
- compose(model, composer, expectChanges = false)
+ compose(model, myComposer, expectChanges = false)
- validate(composer.root) {
+ validate(myComposer.root) {
selectContact(model)
}
}
@@ -94,9 +88,9 @@
fun testInsertAContact() {
val model =
testModel(mutableListOf(bob, jon))
- val composer = compose(model)
+ val myComposer = compose(model)
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
skip()
linear {
@@ -110,9 +104,9 @@
}
model.add(steve, after = bob)
- compose(model, composer)
+ compose(model, myComposer)
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
skip()
linear {
@@ -136,12 +130,12 @@
jon
)
)
- val composer = compose(model)
+ val myComposer = compose(model)
model.move(steve, after = jon)
- compose(model, composer)
+ compose(model, myComposer)
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
skip()
linear {
@@ -165,12 +159,12 @@
jon
)
)
- val composer = compose(model)
+ val myComposer = compose(model)
model.filter = "Jon"
- compose(model, composer)
+ compose(model, myComposer)
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
skip()
linear {
@@ -191,11 +185,11 @@
clark_reports_to_lois
)
- val composer = compose {
+ val myComposer = compose {
reportsReport(reports)
}
- validate(composer.root) {
+ validate(myComposer.root) {
reportsReport(reports)
}
}
@@ -207,7 +201,7 @@
rob_reports_to_alice,
clark_reports_to_lois
)
- val composer = compose {
+ val myComposer = compose {
reportsReport(reports)
}
@@ -216,11 +210,11 @@
clark_reports_to_lois,
rob_reports_to_alice
)
- compose(composer) {
+ compose(myComposer) {
reportsReport(newReports)
}
- validate(composer.root) {
+ validate(myComposer.root) {
reportsReport(newReports)
}
}
@@ -228,7 +222,7 @@
@Test
fun testReplace() {
var includeA = true
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
text("Before")
if (includeA) {
linear {
@@ -250,24 +244,24 @@
}
text("After")
}
- val composer = compose {
+ val myComposer = compose {
composition()
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition()
}
includeA = false
- compose(composer) {
+ compose(myComposer) {
composition()
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition()
}
includeA = true
- compose(composer) {
+ compose(myComposer) {
composition()
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition()
}
}
@@ -276,7 +270,7 @@
fun testInsertWithMultipleRoots() {
val chars = listOf('a', 'b', 'c')
- fun MockViewComposition.textOf(c: Char) {
+ @Composable fun MockComposeScope.textOf(c: Char) {
text(c.toString())
}
@@ -284,51 +278,52 @@
text(c.toString())
}
- fun MockViewComposition.chars(chars: Iterable<Char>) {
+ @Composable fun MockComposeScope.chars(chars: Iterable<Char>) {
repeat(of = chars) { c -> textOf(c) }
}
- fun MockViewValidator.chars(chars: Iterable<Char>) {
+ fun MockViewValidator.validatechars(chars: Iterable<Char>) {
repeat(of = chars) { c -> textOf(c) }
}
- val composer = compose {
+ val myComposer = compose {
chars(chars)
chars(chars)
chars(chars)
}.apply { applyChanges() }
- validate(composer.root) {
- chars(chars)
- chars(chars)
- chars(chars)
+ validate(myComposer.root) {
+ validatechars(chars)
+ validatechars(chars)
+ validatechars(chars)
}
val newChars = listOf('a', 'b', 'x', 'c')
- compose(composer) {
+ compose(myComposer) {
chars(newChars)
chars(newChars)
chars(newChars)
}.apply { applyChanges() }
- validate(composer.root) {
- chars(newChars)
- chars(newChars)
- chars(newChars)
+ validate(myComposer.root) {
+ validatechars(newChars)
+ validatechars(newChars)
+ validatechars(newChars)
}
}
+ @Ignore("b/148896187")
@Test
fun testSimpleMemoize() {
val points = listOf(Point(1, 2), Point(2, 3))
- val composer = compose {
+ val myComposer = compose {
points(points)
}.apply { applyChanges() }
- validate(composer.root) { points(points) }
+ validate(myComposer.root) { points(points) }
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
points(points)
}
}
@@ -341,11 +336,11 @@
Point(4, 5),
Point(6, 7)
)
- val composer = compose {
+ val myComposer = compose {
points(points)
}
- validate(composer.root) { points(points) }
+ validate(myComposer.root) { points(points) }
val modifiedPoints = listOf(
Point(1, 2),
@@ -353,41 +348,32 @@
Point(2, 3),
Point(6, 7)
)
- compose(composer) {
+ compose(myComposer) {
points(modifiedPoints)
}
- validate(composer.root) { points(modifiedPoints) }
+ validate(myComposer.root) { points(modifiedPoints) }
}
+ @Ignore("b/148896187")
@Test
fun testComponent() {
val slReportReports = object {}
- class Reporter : ViewComponent() {
- var report: Report? = null
-
- override fun compose() {
- val r = report
- if (r != null) {
- text(r.from)
- text("reports to")
- text(r.to)
- } else {
- text("no report to report")
- }
+ @Composable fun MockComposeScope.Reporter(report: Report? = null) {
+ if (report != null) {
+ text(report.from)
+ text("reports to")
+ text(report.to)
+ } else {
+ text("no report to report")
}
}
- fun MockViewComposition.reportsReport(reports: Iterable<Report>) {
+ @Composable fun MockComposeScope.reportsReport(reports: Iterable<Report>) {
linear {
repeat(of = reports) { report ->
- call(
- slReportReports,
- { Reporter() },
- { set(report) { this.report = it } },
- { it() }
- )
+ Reporter(report)
}
}
}
@@ -397,11 +383,11 @@
rob_reports_to_alice,
clark_reports_to_lois
)
- val composer = compose {
+ val myComposer = compose {
reportsReport(reports)
}
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -409,21 +395,16 @@
}
}
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
reportsReport(reports)
}
}
@Test
fun testComposeTwoAttributeComponent() {
- class Two : ViewComponent() {
- var first: Int = 1
- var second: Int = 2
-
- override fun compose() {
- linear {
- text("$first $second")
- }
+ @Composable fun MockComposeScope.Two(first: Int = 1, second: Int = 2) {
+ linear {
+ text("$first $second")
}
}
@@ -433,35 +414,20 @@
}
}
- val two = object {}
- val composer = compose {
- call(
- two,
- { Two() },
- {
- set(41) { this.first = it }
- set(42) { this.second = it }
- },
- { it() }
- )
+ val myComposer = compose {
+ Two(41, 42)
}
- validate(composer.root) {
+ validate(myComposer.root) {
two(41, 42)
}
}
@Test
fun testComposeThreeAttributeComponent() {
- class Three : ViewComponent() {
- var first: Int = 1
- var second: Int = 2
- var third: Int = 3
-
- override fun compose() {
- linear {
- text("$first $second $third")
- }
+ @Composable fun MockComposeScope.Three(first: Int = 1, second: Int = 2, third: Int = 3) {
+ linear {
+ text("$first $second $third")
}
}
@@ -471,37 +437,25 @@
}
}
- val three = object {}
- val composer = compose {
- call(
- three,
- { Three() },
- {
- set(41) { this.first = it }
- set(42) { this.second = it }
- set(43) { this.third = it }
- },
- { it() }
- )
+ val myComposer = compose {
+ Three(41, 42, 43)
}
- validate(composer.root) {
+ validate(myComposer.root) {
three(41, 42, 43)
}
}
@Test
fun testComposeFourOrMoreAttributeComponent() {
- class Four : ViewComponent() {
- var first: Int = 1
- var second: Int = 2
- var third: Int = 3
- var fourth: Int = 4
-
- override fun compose() {
- linear {
- text("$first $second $third $fourth")
- }
+ @Composable fun MockComposeScope.Four(
+ first: Int = 1,
+ second: Int = 2,
+ third: Int = 3,
+ fourth: Int = 4
+ ) {
+ linear {
+ text("$first $second $third $fourth")
}
}
@@ -511,22 +465,11 @@
}
}
- val four = object {}
- val composer = compose {
- call(
- four,
- { Four() },
- {
- set(41) { this.first = it }
- set(42) { this.second = it }
- set(43) { this.third = it }
- set(44) { this.fourth = it }
- },
- { it() }
- )
+ val myComposer = compose {
+ Four(41, 42, 43, 44)
}
- validate(composer.root) {
+ validate(myComposer.root) {
four(41, 42, 43, 44)
}
}
@@ -534,7 +477,7 @@
@Test
fun testSkippingACall() {
- fun MockViewComposition.show(value: Int) {
+ @Composable fun MockComposeScope.show(value: Int) {
linear {
text("$value")
}
@@ -552,17 +495,11 @@
}
}
- fun MockViewComposition.test(showThree: Boolean) {
- call(537, { false }) {
- show(1)
- }
- call(540, { false }) {
- show(2)
- }
+ @Composable fun MockComposeScope.test(showThree: Boolean) {
+ show(1)
+ show(2)
if (showThree) {
- call(544, { false }) {
- show(3)
- }
+ show(3)
}
}
@@ -570,11 +507,9 @@
var recomposeTest: () -> Unit = { }
- class Test : ViewComponent() {
- override fun compose() {
- recomposeTest = { recompose() }
- test(showThree)
- }
+ @Composable fun MockComposeScope.Test() {
+ recomposeTest = invalidate
+ test(showThree)
}
fun MockViewValidator.test(showThree: Boolean) {
@@ -585,145 +520,117 @@
}
}
- val composition: MockViewComposition.() -> Unit = {
- call(579, { Test() }, { }, {
- it()
- })
+ val composition: @Composable MockComposeScope.() -> Unit = {
+ Test()
}
val validation: MockViewValidator.() -> Unit = {
test(showThree)
}
- val composer = compose(block = composition)
- validate(composer.root, block = validation)
+ val myComposer = compose(block = composition)
+ validate(myComposer.root, block = validation)
showThree = true
recomposeTest()
- composer.recomposeWithCurrent()
- composer.applyChanges()
- validate(composer.root, block = validation)
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
+ validate(myComposer.root, block = validation)
}
@Test
fun testComponentWithVarCtorParameter() {
- class One(var first: Int) : ViewComponent() {
- override fun compose() {
- text("$first")
- }
+ @Composable fun MockComposeScope.One(first: Int) {
+ text("$first")
}
fun MockViewValidator.one(first: Int) {
text("$first")
}
- val key = object {}
- fun MockViewComposition.callOne(value: Int) {
- call(
- key,
- { One(first = value) },
- {
- update(value) { this.first = it }
- },
- { it() }
- )
+ @Composable fun MockComposeScope.callOne(value: Int) {
+ One(first = value)
}
var value = 42
- val composer = compose {
+ val myComposer = compose {
callOne(value)
}
- validate(composer.root) {
+ validate(myComposer.root) {
one(42)
}
value = 43
- compose(composer) {
+ compose(myComposer) {
callOne(value)
}
- validate(composer.root) {
+ validate(myComposer.root) {
one(43)
}
}
+ @Ignore("b/148896187")
@Test
fun testComponentWithValCtorParameter() {
- class One(val first: Int) : ViewComponent() {
- override fun compose() {
- text("$first")
- }
+ @Composable fun MockComposeScope.One(first: Int) {
+ text("$first")
}
fun MockViewValidator.one(first: Int) {
text("$first")
}
- val key = object {}
- fun MockViewComposition.callOne(value: Int) {
- call(
- cc.joinKey(key, value),
- { One(first = value) },
- { },
- { it() }
- )
+ @Composable fun MockComposeScope.callOne(value: Int) {
+ One(first = value)
}
var value = 42
- val composer = compose {
+ val myComposer = compose {
callOne(value)
}
- validate(composer.root) {
+ validate(myComposer.root) {
one(42)
}
value = 43
- compose(composer) {
+ compose(myComposer) {
callOne(value)
}
- validate(composer.root) {
+ validate(myComposer.root) {
one(43)
}
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
callOne(value)
}
}
+ @Ignore("b/148896187")
@Test
fun testComposePartOfTree() {
val slReportReports = object {}
var recomposeLois: (() -> Unit)? = null
- class Reporter : ViewComponent() {
- var report: Report? = null
-
- override fun compose() {
- val r = report
- if (r != null) {
- if (r.from == "Lois" || r.to == "Lois") recomposeLois = { recompose() }
- text(r.from)
- text("reports to")
- text(r.to)
- } else {
- text("no report to report")
- }
+ @Composable fun MockComposeScope.Reporter(report: Report? = null) {
+ if (report != null) {
+ if (report.from == "Lois" || report.to == "Lois") recomposeLois = invalidate
+ text(report.from)
+ text("reports to")
+ text(report.to)
+ } else {
+ text("no report to report")
}
}
- fun MockViewComposition.reportsReport(reports: Iterable<Report>) {
+ @Composable fun MockComposeScope.reportsReport(reports: Iterable<Report>) {
linear {
repeat(of = reports) { report ->
- call(
- slReportReports,
- { Reporter() },
- { set(report) { this.report = it } },
- { it() }
- )
+ Reporter(report)
}
}
}
@@ -733,11 +640,11 @@
jim_reports_to_sally,
rob_reports_to_alice,
clark_reports_to_lois, r)
- val composer = compose {
+ val myComposer = compose {
reportsReport(reports)
}.apply { applyChanges() }
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -746,7 +653,7 @@
}
}
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
reportsReport(reports)
}
@@ -757,10 +664,10 @@
// Compose only the Lois report
recomposeLois?.let { it() }
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -770,39 +677,31 @@
}
}
+ @Ignore("b/148896187")
@Test
fun testRecomposeWithReplace() {
val slReportReports = object {}
var recomposeLois: (() -> Unit)? = null
var key = 0
- class Reporter : ViewComponent() {
- var report: Report? = null
-
- override fun compose() {
- val r = report
- if (r != null) {
- if (r.from == "Lois" || r.to == "Lois") recomposeLois = { recompose() }
- cc.startGroup(key)
+ @Composable fun MockComposeScope.Reporter(report: Report? = null) {
+ val r = report
+ if (r != null) {
+ if (r.from == "Lois" || r.to == "Lois") recomposeLois = invalidate
+ key(key) {
text(r.from)
text("reports to")
text(r.to)
- cc.endGroup()
- } else {
- text("no report to report")
}
+ } else {
+ text("no report to report")
}
}
- fun MockViewComposition.reportsReport(reports: Iterable<Report>) {
+ @Composable fun MockComposeScope.reportsReport(reports: Iterable<Report>) {
linear {
repeat(of = reports) { report ->
- call(
- slReportReports,
- { Reporter() },
- { set(report) { this.report = it } },
- { it() }
- )
+ Reporter(report)
}
}
}
@@ -812,11 +711,11 @@
jim_reports_to_sally,
rob_reports_to_alice,
clark_reports_to_lois, r)
- val composer = compose {
+ val myComposer = compose {
reportsReport(reports)
}.apply { applyChanges() }
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -825,7 +724,7 @@
}
}
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
reportsReport(reports)
}
@@ -839,10 +738,10 @@
// Compose only the Lois report
recomposeLois?.let { it() }
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -858,37 +757,28 @@
var recomposeLois: (() -> Unit)? = null
val key = 0
- class Reporter : ViewComponent() {
- var report: Report? = null
-
- override fun compose() {
- val r = report
- if (r != null) {
- if (r.from == "Lois" || r.to == "Lois") recomposeLois = { recompose() }
- cc.startGroup(key)
- text(r.from)
+ @Composable fun MockComposeScope.Reporter(report: Report? = null) {
+ if (report != null) {
+ val callback = invalidate
+ if (report.from == "Lois" || report.to == "Lois") recomposeLois = callback
+ key(key) {
+ text(report.from)
text("reports to")
- text(r.to)
- cc.endGroup()
- } else {
- text("no report to report")
+ text(report.to)
}
+ } else {
+ text("no report to report")
}
}
- fun MockViewComposition.reportsReport(
+ @Composable fun MockComposeScope.reportsReport(
reports: Iterable<Report>,
include: (report: Report) -> Boolean
) {
linear {
repeat(of = reports) { report ->
if (include(report)) {
- call(
- slReportReports,
- { Reporter() },
- { set(report) { this.report = it } },
- { it() }
- )
+ Reporter(report)
}
}
}
@@ -903,11 +793,11 @@
)
val all: (report: Report) -> Boolean = { true }
val notLois: (report: Report) -> Boolean = { it.from != "Lois" && it.to != "Lois" }
- val composer = compose {
+ val myComposer = compose {
reportsReport(reports, all)
}.apply { applyChanges() }
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -916,11 +806,11 @@
}
}
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
reportsReport(reports, notLois)
}
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -930,10 +820,10 @@
// Invalidate Lois which is now removed.
recomposeLois?.let { it() }
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) {
+ validate(myComposer.root) {
linear {
reportsTo(jim_reports_to_sally)
reportsTo(rob_reports_to_alice)
@@ -943,6 +833,7 @@
// remember()
+ @Ignore("b/148896187")
@Test
fun testSimpleRemember() {
var count = 0
@@ -953,7 +844,7 @@
}
}
- fun MockViewComposition.test(value: Int) {
+ @Composable fun MockComposeScope.test(value: Int) {
val w = remember { Wrapper(value) }
text("value = ${w.value}")
}
@@ -962,15 +853,15 @@
text("value = $value")
}
- val composer = compose {
+ val myComposer = compose {
test(1)
}
- validate(composer.root) { test(1) }
+ validate(myComposer.root) { test(1) }
assertEquals(1, count)
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
test(1)
}
@@ -978,6 +869,7 @@
assertEquals(1, count)
}
+ @Ignore("b/148896187")
@Test
fun testRememberOneParameter() {
var count = 0
@@ -988,7 +880,7 @@
}
}
- fun MockViewComposition.test(value: Int) {
+ @Composable fun MockComposeScope.test(value: Int) {
val w = remember(value) { Wrapper(value) }
text("value = ${w.value}")
}
@@ -997,27 +889,28 @@
text("value = $value")
}
- val composer = compose {
+ val myComposer = compose {
test(1)
}
- validate(composer.root) { test(1) }
+ validate(myComposer.root) { test(1) }
- compose(composer) {
+ compose(myComposer) {
test(2)
}
- validate(composer.root) { test(2) }
+ validate(myComposer.root) { test(2) }
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
test(2)
}
- validate(composer.root) { test(2) }
+ validate(myComposer.root) { test(2) }
assertEquals(2, count)
}
+ @Ignore("b/148896187")
@Test
fun testRememberTwoParameters() {
var count = 0
@@ -1028,7 +921,7 @@
}
}
- fun MockViewComposition.test(a: Int, b: Int) {
+ @Composable fun MockComposeScope.test(a: Int, b: Int) {
val w = remember(a, b) { Wrapper(a, b) }
text("a = ${w.a} b = ${w.b}")
}
@@ -1037,27 +930,28 @@
text("a = $a b = $b")
}
- val composer = compose {
+ val myComposer = compose {
test(1, 2)
}
- validate(composer.root) { test(1, 2) }
+ validate(myComposer.root) { test(1, 2) }
- compose(composer) {
+ compose(myComposer) {
test(2, 3)
}
- validate(composer.root) { test(2, 3) }
+ validate(myComposer.root) { test(2, 3) }
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
test(2, 3)
}
- validate(composer.root) { test(2, 3) }
+ validate(myComposer.root) { test(2, 3) }
assertEquals(2, count)
}
+ @Ignore("b/148896187")
@Test
fun testRememberThreeParameters() {
var count = 0
@@ -1068,7 +962,7 @@
}
}
- fun MockViewComposition.test(a: Int, b: Int, c: Int) {
+ @Composable fun MockComposeScope.test(a: Int, b: Int, c: Int) {
val w = remember(a, b, c) { Wrapper(a, b, c) }
text("a = ${w.a} b = ${w.b} c = ${w.c}")
}
@@ -1077,27 +971,28 @@
text("a = $a b = $b c = $c")
}
- val composer = compose {
+ val myComposer = compose {
test(1, 2, 3)
}
- validate(composer.root) { test(1, 2, 3) }
+ validate(myComposer.root) { test(1, 2, 3) }
- compose(composer) {
+ compose(myComposer) {
test(1, 2, 4)
}
- validate(composer.root) { test(1, 2, 4) }
+ validate(myComposer.root) { test(1, 2, 4) }
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
test(1, 2, 4)
}
- validate(composer.root) { test(1, 2, 4) }
+ validate(myComposer.root) { test(1, 2, 4) }
assertEquals(2, count)
}
+ @Ignore("b/148896187")
@Test
fun testRememberFourParameters() {
var count = 0
@@ -1108,7 +1003,7 @@
}
}
- fun MockViewComposition.test(a: Int, b: Int, c: Int, d: Int) {
+ @Composable fun MockComposeScope.test(a: Int, b: Int, c: Int, d: Int) {
val w = remember(a, b, c, d) { Wrapper(a, b, c, d) }
text("a = ${w.a} b = ${w.b} c = ${w.c} d = ${w.d}")
}
@@ -1117,27 +1012,28 @@
text("a = $a b = $b c = $c d = $d")
}
- val composer = compose {
+ val myComposer = compose {
test(1, 2, 3, 4)
}
- validate(composer.root) { test(1, 2, 3, 4) }
+ validate(myComposer.root) { test(1, 2, 3, 4) }
- compose(composer) {
+ compose(myComposer) {
test(1, 2, 4, 5)
}
- validate(composer.root) { test(1, 2, 4, 5) }
+ validate(myComposer.root) { test(1, 2, 4, 5) }
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
test(1, 2, 4, 5)
}
- validate(composer.root) { test(1, 2, 4, 5) }
+ validate(myComposer.root) { test(1, 2, 4, 5) }
assertEquals(2, count)
}
+ @Ignore("b/148896187")
@Test
fun testRememberFiveParameters() {
var count = 0
@@ -1148,7 +1044,7 @@
}
}
- fun MockViewComposition.test(a: Int, b: Int, c: Int, d: Int, e: Int) {
+ @Composable fun MockComposeScope.test(a: Int, b: Int, c: Int, d: Int, e: Int) {
val w = remember(a, b, c, d, e) { Wrapper(a, b, c, d, e) }
text("a = ${w.a} b = ${w.b} c = ${w.c} d = ${w.d} e = ${w.e}")
}
@@ -1157,23 +1053,23 @@
text("a = $a b = $b c = $c d = $d e = $e")
}
- val composer = compose {
+ val myComposer = compose {
test(1, 2, 3, 4, 5)
}
- validate(composer.root) { test(1, 2, 3, 4, 5) }
+ validate(myComposer.root) { test(1, 2, 3, 4, 5) }
- compose(composer) {
+ compose(myComposer) {
test(1, 2, 4, 5, 6)
}
- validate(composer.root) { test(1, 2, 4, 5, 6) }
+ validate(myComposer.root) { test(1, 2, 4, 5, 6) }
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
test(1, 2, 4, 5, 6)
}
- validate(composer.root) { test(1, 2, 4, 5, 6) }
+ validate(myComposer.root) { test(1, 2, 4, 5, 6) }
assertEquals(2, count)
}
@@ -1182,7 +1078,7 @@
fun testInsertGroupInContainer() {
val values = mutableListOf(0)
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
linear {
for (value in values) {
memoize(value, value) {
@@ -1199,14 +1095,14 @@
}
}
- val composer = compose { composition() }
+ val myComposer = compose { composition() }
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
for (i in 1..10) {
values.add(i)
- compose(composer) { composition() }
- validate(composer.root) { composition() }
+ compose(myComposer) { composition() }
+ validate(myComposer.root) { composition() }
}
}
@@ -1216,7 +1112,7 @@
var threeVisible = false
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
linear {
text("one")
text("two")
@@ -1244,26 +1140,24 @@
}
}
- val composer = compose { composition() }
- validate(composer.root) { composition() }
+ val myComposer = compose { composition() }
+ validate(myComposer.root) { composition() }
threeVisible = true
- compose(composer) { composition() }
+ compose(myComposer) { composition() }
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
}
@Test
fun testStartJoin() {
var text = "Starting"
- var invalidate: (() -> Unit)? = null
- fun MockViewComposition.composition() {
+ var myInvalidate: (() -> Unit)? = null
+ @Composable fun MockComposeScope.composition() {
linear {
- join(860) { myInvalidate ->
- invalidate = { myInvalidate() }
- text(text)
- }
+ myInvalidate = invalidate
+ text(text)
}
}
@@ -1273,17 +1167,17 @@
}
}
- val composer = compose { composition() }
+ val myComposer = compose { composition() }
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
text = "Ending"
- invalidate?.let { it() }
+ myInvalidate?.let { it() }
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
}
@Test
@@ -1293,17 +1187,13 @@
var invalidate1: (() -> Unit)? = null
var invalidate2: (() -> Unit)? = null
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
linear {
- join(860) { myInvalidate ->
- invalidate1 = { myInvalidate() }
- text(text)
- if (includeNested) {
- join(899) { joinInvalidate ->
- invalidate2 = { joinInvalidate() }
- text("Nested in $text")
- }
- }
+ invalidate1 = invalidate
+ text(text)
+ if (includeNested) {
+ invalidate2 = invalidate
+ text("Nested in $text")
}
}
}
@@ -1317,24 +1207,24 @@
}
}
- val composer = compose { composition() }
+ val myComposer = compose { composition() }
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
text = "Ending"
includeNested = false
invalidate1?.invoke()
invalidate2?.invoke()
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
}
@Test
@@ -1344,18 +1234,14 @@
var invalidate1: (() -> Unit)? = null
var invalidate2: (() -> Unit)? = null
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
linear {
- join(860) { myInvalidate ->
- invalidate1 = { myInvalidate() }
- if (includeNested) {
- join(899) { joinInvalidate ->
- invalidate2 = { joinInvalidate() }
- text("Nested in $text")
- }
- }
- text(text)
+ invalidate1 = invalidate
+ if (includeNested) {
+ invalidate2 = invalidate
+ text("Nested in $text")
}
+ text(text)
}
}
@@ -1368,24 +1254,24 @@
}
}
- val composer = compose { composition() }
+ val myComposer = compose { composition() }
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
text = "Ending"
includeNested = false
invalidate1?.invoke()
invalidate2?.invoke()
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
}
// b/132638679
@@ -1395,41 +1281,39 @@
var invalidateOuter: (() -> Unit)? = null
var invalidateInner: (() -> Unit)? = null
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
linear {
- join(1106) { outerInvalidate ->
- invalidateOuter = { outerInvalidate() }
- for (i in 1..texts) {
- text("Some text")
- }
+ invalidateOuter = invalidate
+ for (i in 1..texts) {
+ text("Some text")
+ }
- skip(1114) {
- join(1116) { innerInvalidate ->
- text("Some text")
+ Observe {
+ text("Some text")
- // Force the invalidation to survive the compose
- innerInvalidate()
- invalidateInner = { innerInvalidate() }
- }
- }
+ // Force the invalidation to survive the compose
+ val innerInvalidate = invalidate
+ innerInvalidate()
+ invalidateInner = innerInvalidate
}
}
}
- val composer = compose { composition() }
+ val myComposer = compose { composition() }
texts = 4
invalidateOuter?.invoke()
invalidateInner?.invoke()
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
texts = 3
invalidateOuter?.invoke()
- composer.recomposeWithCurrent()
- composer.applyChanges()
+ myComposer.recomposeWithCurrent()
+ myComposer.applyChanges()
}
+ @Ignore("b/148896187")
@Test
fun testLifecycle_Enter_Simple() {
val lifecycleObject = object : CompositionLifecycleObserver {
@@ -1443,7 +1327,7 @@
}
}
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
linear {
remember { lifecycleObject }
text("Some text")
@@ -1456,19 +1340,20 @@
}
}
- val composer = compose { composition() }
- validate(composer.root) { composition() }
+ val myComposer = compose { composition() }
+ validate(myComposer.root) { composition() }
assertEquals(1, lifecycleObject.count, "object should have been notified of an enter")
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
composition()
}
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
assertEquals(1, lifecycleObject.count, "Object should have only been notified once")
}
+ @Ignore("b/148896187")
@Test
fun testLifecycle_Enter_SingleNotification() {
val lifecycleObject = object : CompositionLifecycleObserver {
@@ -1482,7 +1367,7 @@
}
}
- fun MockViewComposition.composition() {
+ @Composable fun MockComposeScope.composition() {
linear {
val l = remember { lifecycleObject }
assertEquals(lifecycleObject, l, "Lifecycle object should be returned")
@@ -1504,19 +1389,20 @@
}
}
- val composer = compose { composition() }
- validate(composer.root) { composition() }
+ val myComposer = compose { composition() }
+ validate(myComposer.root) { composition() }
assertEquals(1, lifecycleObject.count, "object should have been notified of an enter")
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
composition()
}
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
assertEquals(1, lifecycleObject.count, "Object should have only been notified once")
}
+ @Ignore("b/148896187")
@Test
fun testLifecycle_Leave_Simple() {
val lifecycleObject = object : CompositionLifecycleObserver {
@@ -1530,7 +1416,7 @@
}
}
- fun MockViewComposition.composition(includeLifecycleObject: Boolean) {
+ @Composable fun MockComposeScope.composition(includeLifecycleObject: Boolean) {
linear {
if (includeLifecycleObject) {
linear {
@@ -1552,26 +1438,27 @@
}
}
- val composer = compose { composition(true) }
- validate(composer.root) { composition(true) }
+ val myComposer = compose { composition(true) }
+ validate(myComposer.root) { composition(true) }
assertEquals(1, lifecycleObject.count, "object should have been notified of an enter")
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
composition(true)
}
- validate(composer.root) { composition(true) }
+ validate(myComposer.root) { composition(true) }
assertEquals(1, lifecycleObject.count, "Object should have only been notified once")
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
composition(false)
}
- validate(composer.root) { composition(false) }
+ validate(myComposer.root) { composition(false) }
assertEquals(0, lifecycleObject.count, "Object should have been notified of a leave")
}
+ @Ignore("b/148896187")
@Test
fun testLifecycle_Leave_NoLeaveOnReenter() {
var expectedEnter = true
@@ -1589,28 +1476,28 @@
}
}
- fun MockViewComposition.composition(a: Boolean, b: Boolean, c: Boolean) {
+ @Composable fun MockComposeScope.composition(a: Boolean, b: Boolean, c: Boolean) {
linear {
if (a) {
- linear(1) {
+ key(1) { linear {
val l = remember { lifecycleObject }
assertEquals(lifecycleObject, l, "Lifecycle object should be returned")
text("a")
- }
+ } }
}
if (b) {
- linear(2) {
+ key(2) { linear {
val l = remember { lifecycleObject }
assertEquals(lifecycleObject, l, "Lifecycle object should be returned")
text("b")
- }
+ } }
}
if (c) {
- linear(3) {
+ key(3) { linear {
val l = remember { lifecycleObject }
assertEquals(lifecycleObject, l, "Lifecycle object should be returned")
text("c")
- }
+ } }
}
}
}
@@ -1637,8 +1524,8 @@
expectedEnter = true
expectedLeave = false
- val composer = compose { composition(a = true, b = false, c = false) }
- validate(composer.root) {
+ val myComposer = compose { composition(a = true, b = false, c = false) }
+ validate(myComposer.root) {
composition(
a = true,
b = false,
@@ -1654,10 +1541,10 @@
expectedEnter = false
expectedLeave = false
- compose(composer, expectChanges = false) {
+ compose(myComposer, expectChanges = false) {
composition(a = true, b = false, c = false)
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition(
a = true,
b = false,
@@ -1672,10 +1559,10 @@
expectedEnter = false
expectedLeave = false
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
composition(a = false, b = true, c = false)
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition(
a = false,
b = true,
@@ -1686,10 +1573,10 @@
expectedEnter = false
expectedLeave = false
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
composition(a = false, b = false, c = true)
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition(
a = false,
b = false,
@@ -1700,10 +1587,10 @@
expectedEnter = false
expectedLeave = false
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
composition(a = true, b = false, c = false)
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition(
a = true,
b = false,
@@ -1714,10 +1601,10 @@
expectedEnter = false
expectedLeave = true
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
composition(a = false, b = false, c = false)
}
- validate(composer.root) {
+ validate(myComposer.root) {
composition(
a = false,
b = false,
@@ -1751,12 +1638,12 @@
}
}
- fun MockViewComposition.composition(obj: Any) {
+ @Composable fun MockComposeScope.composition(obj: Any) {
linear {
- linear(1) {
+ key(1) { linear {
remember(obj) { obj }
text("Some value")
- }
+ } }
}
}
@@ -1768,22 +1655,22 @@
}
}
- val composer = compose { composition(obj = lifecycleObject1) }
- validate(composer.root) { composition() }
+ val myComposer = compose { composition(obj = lifecycleObject1) }
+ validate(myComposer.root) { composition() }
assertEquals(1, lifecycleObject1.count, "first object should enter")
assertEquals(0, lifecycleObject2.count, "second object should not have entered")
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
composition(lifecycleObject2)
}
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
assertEquals(0, lifecycleObject1.count, "first object should have left")
assertEquals(1, lifecycleObject2.count, "second object should have entered")
- compose(composer, expectChanges = true) {
+ compose(myComposer, expectChanges = true) {
composition(object {})
}
- validate(composer.root) { composition() }
+ validate(myComposer.root) { composition() }
assertEquals(0, lifecycleObject1.count, "first object should have left")
assertEquals(0, lifecycleObject2.count, "second object should have left")
}
@@ -1813,7 +1700,7 @@
}.also { objects.add(it) }
}
- fun MockViewComposition.lifecycleUser(name: String) {
+ @Composable fun MockComposeScope.lifecycleUser(name: String) {
linear {
remember(name) { newLifecycleObject(name) }
text(value = name)
@@ -1836,7 +1723,7 @@
Should leave as: J, I, H, G, F, E, D, C, B, A
*/
- fun MockViewComposition.tree() {
+ @Composable fun MockComposeScope.tree() {
linear {
lifecycleUser("A")
linear {
@@ -1859,20 +1746,20 @@
}
}
- fun MockViewComposition.composition(includeTree: Boolean) {
+ @Composable fun MockComposeScope.composition(includeTree: Boolean) {
linear {
if (includeTree) tree()
}
}
- val composer = compose { composition(true) }
+ val myComposer = compose { composition(true) }
assertTrue(
objects.mapNotNull { it as? Counted }.map { it.count == 1 }.all { it },
"All object should have entered"
)
- compose(composer) {
+ compose(myComposer) {
composition(false)
}
@@ -1912,11 +1799,11 @@
}
private fun compose(
- composer: MockViewComposer? = null,
+ myComposer: MockViewComposer? = null,
expectChanges: Boolean = true,
- block: Compose
+ block: @Composable MockComposeScope.() -> Unit
): MockViewComposer {
- val myComposer = composer ?: run {
+ val myComposer = myComposer ?: run {
val root = View().apply { name = "root" }
MockViewComposer(root)
}
@@ -1939,10 +1826,10 @@
private fun compose(
model: ContactModel,
- composer: MockViewComposer? = null,
+ myComposer: MockViewComposer? = null,
expectChanges: Boolean = true
): MockViewComposer =
- compose(composer = composer, expectChanges = expectChanges) {
+ compose(myComposer = myComposer, expectChanges = expectChanges) {
selectContact(model)
}
diff --git a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeContact.kt b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeContact.kt
index 7409e90..8870737 100644
--- a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeContact.kt
+++ b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeContact.kt
@@ -16,11 +16,14 @@
package androidx.compose.mock
+import androidx.compose.Composable
+
// <linear>
// <text text="Name: ${contact.name}" />
// <text text="email: ${contact.email" />
// </linear>
-fun MockViewComposition.contact(contact: Contact) {
+@Composable
+fun MockComposeScope.contact(contact: Contact) {
linear {
text(value = "Name: ${contact.name}")
text(value = "email: ${contact.email}")
@@ -41,7 +44,8 @@
// <selectBox>
// </repeat>
// </linear>
-fun MockViewComposition.contacts(contacts: Collection<Contact>, selected: Contact?) {
+@Composable
+fun MockComposeScope.contacts(contacts: Collection<Contact>, selected: Contact?) {
linear {
repeat(of = contacts) {
selectBox(it == selected) {
@@ -71,7 +75,8 @@
// <contacts contacts=model.filtered selected=model.selected />
// </linear>
// </linear>
-fun MockViewComposition.selectContact(model: ContactModel) {
+@Composable
+fun MockComposeScope.selectContact(model: ContactModel) {
linear {
linear {
text(value = "Filter:")
diff --git a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposePoints.kt b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposePoints.kt
index 8a62094..9851aa7 100644
--- a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposePoints.kt
+++ b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposePoints.kt
@@ -16,7 +16,10 @@
package androidx.compose.mock
-fun MockViewComposition.point(point: Point) {
+import androidx.compose.Composable
+
+@Composable
+fun MockComposeScope.point(point: Point) {
text("X: ${point.x} Y: ${point.y}")
}
@@ -26,7 +29,8 @@
object SLPoints
-fun MockViewComposition.points(points: Iterable<Point>) {
+@Composable
+fun MockComposeScope.points(points: Iterable<Point>) {
repeat(of = points) {
memoize(SLPoints, it) { point(it) }
}
diff --git a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeReport.kt b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeReport.kt
index cf50387..efb26bc 100644
--- a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeReport.kt
+++ b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ComposeReport.kt
@@ -16,18 +16,23 @@
package androidx.compose.mock
-fun MockViewComposition.reportsTo(report: Report) {
+import androidx.compose.Composable
+
+@Composable
+fun MockComposeScope.reportsTo(report: Report) {
text(report.from)
text("reports to")
text(report.to)
}
+
fun MockViewValidator.reportsTo(report: Report) {
text(report.from)
text("reports to")
text(report.to)
}
-fun MockViewComposition.reportsReport(reports: Iterable<Report>) {
+@Composable
+fun MockComposeScope.reportsReport(reports: Iterable<Report>) {
linear {
repeat(of = reports) { report ->
reportsTo(report)
diff --git a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/View.kt b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/View.kt
index fd36381..1951853 100644
--- a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/View.kt
+++ b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/View.kt
@@ -63,6 +63,26 @@
fun attribute(name: String, value: Any) { attributes[name] = value }
+ var value: String?
+ get() = attributes["value"] as? String
+ set(value) {
+ if (value != null) {
+ attributes["value"] = value
+ } else {
+ attributes.remove("value")
+ }
+ }
+
+ var text: String?
+ get() = attributes["text"] as? String
+ set(value) {
+ if (value != null) {
+ attributes["text"] = value
+ } else {
+ attributes.remove("text")
+ }
+ }
+
private val attributesAsString get() =
if (attributes.isEmpty()) ""
else attributes.map { " ${it.key}='${it.value}'" }.joinToString()
diff --git a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ViewComposer.kt b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ViewComposer.kt
index 5976440..ecd8d50 100644
--- a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ViewComposer.kt
+++ b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/ViewComposer.kt
@@ -18,43 +18,15 @@
import androidx.compose.Applier
import androidx.compose.ApplyAdapter
+import androidx.compose.Composable
import androidx.compose.Composer
+import androidx.compose.ComposerUpdater
import androidx.compose.Recomposer
import androidx.compose.SlotTable
-import androidx.compose.cache
-import androidx.compose.invalidate
+import androidx.compose.currentComposerIntrinsic
+import androidx.compose.invokeComposable
import androidx.compose.runWithCurrent
-interface MockViewComposition {
- val cc: Composer<View>
-}
-
-abstract class ViewComponent : MockViewComposition {
- private var recomposer: (() -> Unit)? = null
- private lateinit var composer: Composer<View>
- @PublishedApi
- internal fun setComposer(value: Composer<View>) {
- composer = value
- }
-
- override val cc: Composer<View> get() = composer
-
- fun recompose() {
- recomposer?.invoke()
- }
-
- operator fun invoke() {
- val cc = cc as MockViewComposer
- cc.startRestartGroup(0)
- recomposer = invalidate
- compose()
- cc.endRestartGroup()?.updateScope { invoke() }
- }
-
- abstract fun compose()
-}
-
-typealias Compose = MockViewComposition.() -> Unit
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
object ViewApplierAdapter :
@@ -66,6 +38,12 @@
override fun View.end(instance: View, parent: View) {}
}
+typealias Updater<T> = ComposerUpdater<View, T>
+
+interface MockComposeScope {
+ val composer: MockViewComposer
+}
+
class MockViewComposer(
val root: View
) : Composer<View>(
@@ -76,136 +54,64 @@
override fun scheduleChangesDispatch() {}
override fun hasPendingChanges(): Boolean = false
- }) {
- private val rootComposer: MockViewComposition by lazy {
- object : MockViewComposition {
- override val cc: Composer<View> get() = this@MockViewComposer
- }
- }
+ }), MockComposeScope {
+ override val composer: MockViewComposer get() = this
- fun compose(composition: MockViewComposition.() -> Unit) {
+ fun compose(composable: @Composable MockComposeScope.() -> Unit) {
composeRoot {
- rootComposer.composition()
+ invokeComposable(this) {
+ val c = currentComposerIntrinsic as MockViewComposer
+ c.composable()
+ }
}
}
fun recomposeWithCurrent() {
runWithCurrent { recompose() }
}
+
+ inline fun <V : View> emit(
+ key: Any,
+ ctor: () -> V,
+ update: Updater<V>.() -> Unit
+ ) {
+ startNode(key)
+ val node = if (inserting) ctor().also { emitNode(it) }
+ else useNode() as V
+ Updater(this, node).update()
+ endNode()
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ inline fun <V : View> emit(
+ key: Any,
+ ctor: () -> V,
+ update: Updater<V>.() -> Unit,
+ children: () -> Unit
+ ) {
+ startNode(key)
+ val node = if (inserting) ctor().also { emitNode(it) }
+ else useNode() as V
+ Updater(this, node).update()
+ children()
+ endNode()
+ }
}
-/* inline */ fun <N, /* reified */ V> Composer<N>.applyNeeded(value: V): Boolean =
- changed(value) && !inserting
-
-inline fun <reified P1> MockViewComposition.memoize(
+@Composable
+fun <P1> MockComposeScope.memoize(
key: Any,
p1: P1,
- block: MockViewComposition.(p1: P1) -> Unit
+ block: @Composable() (p1: P1) -> Unit
) {
- cc.startGroup(key)
- if (!cc.changed(p1)) {
- cc.skipCurrentGroup()
- } else {
- cc.startGroup(key)
- block(p1)
- cc.endGroup()
- }
- cc.endGroup()
-}
-
-inline fun <V : View> MockViewComposition.emit(
- key: Any,
- noinline factory: () -> V,
- block: MockViewComposition.() -> Unit
-) {
- cc.startNode(key)
- cc.emitNode(factory)
- block()
- cc.endNode()
-}
-
-inline fun <V : View, reified A1> MockViewComposition.emit(
- key: Any,
- noinline factory: () -> V,
- a1: A1,
- noinline set1: V.(A1) -> Unit
-) {
- cc.startNode(key)
- cc.emitNode(factory)
- if (cc.changed(a1)) {
- cc.apply(a1, set1)
- }
- cc.endNode()
-}
-
-val invocation = Any()
-
-inline fun MockViewComposition.call(
- key: Any,
- invalid: Composer<View>.() -> Boolean,
- block: () -> Unit
-) = with(cc) {
- startGroup(key)
- if (invalid() || inserting) {
- startGroup(invocation)
- block()
+ with (currentComposerIntrinsic as MockViewComposer) {
+ startGroup(key)
+ if (!changed(p1)) {
+ skipCurrentGroup()
+ } else {
+ startGroup(key)
+ block(p1)
+ endGroup()
+ }
endGroup()
- } else {
- (cc as Composer<*>).skipCurrentGroup()
- }
- endGroup()
-}
-
-inline fun <T : ViewComponent> MockViewComposition.call(
- key: Any,
- ctor: () -> T,
- invalid: ComponentUpdater<T>.() -> Unit,
- block: (f: T) -> Unit
-) = with(cc) {
- startGroup(key)
- val f = cache(true, ctor).apply { setComposer(this@with) }
- val updater = object : ComponentUpdater<T> {
- override val cc: Composer<View> = this@with
- override var changed: Boolean = false
- override val component = f
- }
- updater.invalid()
- if (updater.changed || inserting) {
- startGroup(invocation)
- block(f)
- endGroup()
- } else {
- skipCurrentGroup()
- }
- endGroup()
-}
-
-fun MockViewComposition.join(
- key: Any,
- block: (invalidate: () -> Unit) -> Unit
-) {
- val myCC = cc as MockViewComposer
- myCC.startRestartGroup(key)
- block(invalidate)
- myCC.endRestartGroup()?.updateScope { join(key, block) }
-}
-
-interface ComponentUpdater<C> : MockViewComposition {
- val component: C
- var changed: Boolean
-}
-
-inline fun <C, reified V> ComponentUpdater<C>.set(value: V, noinline block: C.(V) -> Unit) {
- if (cc.changed(value)) {
- cc.apply<V, C>(value) { component.block(it) }
- component.block(value)
- changed = true
- }
-}
-
-inline fun <C, reified V> ComponentUpdater<C>.update(value: V, noinline block: C.(V) -> Unit) {
- if (cc.applyNeeded(value)) {
- cc.apply<V, C>(value) { component.block(it) }
- component.block(value)
- changed = true
}
}
diff --git a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/Views.kt b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/Views.kt
index f86c36f..b808ed6 100644
--- a/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/Views.kt
+++ b/compose/compose-runtime/src/unitTest/kotlin/androidx/compose/mock/Views.kt
@@ -16,50 +16,51 @@
package androidx.compose.mock
-class SourceLocation(val name: String) {
- override fun toString(): String = "SL $name"
-}
+import androidx.compose.Composable
+import androidx.compose.currentComposerIntrinsic
+import androidx.compose.key
-val repeat = SourceLocation("repeat")
-inline fun <T : Any> MockViewComposition.repeat(
+@Composable
+fun <T : Any> MockComposeScope.repeat(
of: Iterable<T>,
- crossinline block: MockViewComposition.(value: T) -> Unit
+ block: @Composable MockComposeScope.(value: T) -> Unit
) {
for (value in of) {
- cc.startGroup(cc.joinKey(repeat, value))
- block(value)
- cc.endGroup()
+ key(value) {
+ block(value)
+ }
}
}
-val linear = SourceLocation("linear")
-fun MockViewComposition.linear(block: Compose) {
- emit(linear, { View().apply { name = "linear" } }, block)
+@Composable
+fun MockComposeScope.linear(block: @Composable MockComposeScope.() -> Unit) {
+ val c = currentComposerIntrinsic as MockViewComposer
+ View(name="linear") {
+ c.block()
+ }
}
-fun MockViewComposition.linear(key: Any, block: Compose) {
- emit(key, { View().apply { name = "linear" } }, block)
+@Composable
+fun MockComposeScope.text(value: String) {
+ View(name="text", text=value)
}
-val text = SourceLocation("text")
-fun MockViewComposition.text(value: String) {
- emit(text, { View().apply { name = "text" } }, value, { attribute("text", it) })
+@Composable
+fun MockComposeScope.edit(value: String) {
+ View(name="edit", value = value)
}
-val edit = SourceLocation("edit")
-fun MockViewComposition.edit(value: String) {
- emit(edit, { View().apply { name = "edit" } }, value, { attribute("value", it) })
-}
-
-val box = SourceLocation("box")
-fun MockViewComposition.selectBox(selected: Boolean, block: Compose) {
+@Composable
+fun MockComposeScope.selectBox(selected: Boolean, block: @Composable MockComposeScope.() -> Unit) {
if (selected) {
- emit(box, { View().apply { name = "box" } }, block)
+ View(name = "box") {
+ block()
+ }
} else {
block()
}
}
-fun MockViewComposition.skip(key: Any, block: Compose) {
- call(key, { false }) { block() }
-}
\ No newline at end of file
+//fun MockComposeScope.skip(key: Any, block: Compose) {
+// call(key, { false }) { block() }
+//}
\ No newline at end of file
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt
index 3658383..5ba41c7 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt
@@ -19,6 +19,7 @@
import android.graphics.Bitmap
import android.os.Build
import androidx.compose.Composable
+import androidx.compose.Observe
import androidx.compose.remember
import androidx.compose.state
import androidx.test.filters.SdkSuppress
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
index 774dd06..70393df 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
@@ -23,7 +23,6 @@
import androidx.animation.DefaultAnimationClock
import androidx.ui.core.input.FocusManager
import androidx.ui.input.TextInputService
-import androidx.compose.composer
import androidx.compose.Composable
import androidx.compose.Compose
import androidx.compose.Composition
@@ -32,8 +31,10 @@
import androidx.compose.Observe
import androidx.compose.Providers
import androidx.compose.StructurallyEqual
+import androidx.compose.ViewComposer
import androidx.compose.ambientOf
import androidx.compose.compositionReference
+import androidx.compose.currentComposerIntrinsic
import androidx.compose.invalidate
import androidx.compose.remember
import androidx.compose.onPreCommit
@@ -87,7 +88,7 @@
}
}
val rootLayoutNode = rootRef.value?.root ?: error("Failed to create root platform view")
- val context = rootRef.value?.context ?: composer.context
+ val context = rootRef.value?.context ?: (currentComposerIntrinsic as ViewComposer).context
// If this value is inlined where it is used, an error that includes 'Precise Reference:
// kotlinx.coroutines.Dispatchers' not instance of 'Precise Reference: androidx.compose.Ambient'.
@@ -145,7 +146,8 @@
context: Context,
content: @Composable() () -> Unit
): Composition = Compose.composeInto(composeView.root, context) {
- remember { composer.adapters?.register(AndroidViewAdapter) }
+ val currentComposer = currentComposerIntrinsic as ViewComposer
+ remember { currentComposer.adapters?.register(AndroidViewAdapter) }
WrapWithAmbients(composeView, context, Dispatchers.Main) {
WrapWithSelectionContainer(content)
}
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Table.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Table.kt
index 0337286..5fafea2 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Table.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Table.kt
@@ -482,9 +482,22 @@
var verticalOffsets by state { emptyArray<IntPx>() }
var horizontalOffsets by state { emptyArray<IntPx>() }
+ // NOTE(lmr): It is required that we read from verticalOffsets/horizontalOffsets so that the
+ // entire Table composable gets recomposed every time they change. This used to work before
+ // without us explicitly reading them here because of a compiler bug, but now that the bug is
+ // fixed, this is needed. This type of pattern where we are observing the composition of the
+ // children of table implicitly and building up a list of composables is a bit error prone
+ // and will likely break again in the future when we move to multithreaded composition. I
+ // suggest we reevaluate the architecture of this composable.
+
+ @Suppress("UNUSED_EXPRESSION")
+ verticalOffsets
+ @Suppress("UNUSED_EXPRESSION")
+ horizontalOffsets
+
val tableChildren: @Composable() () -> Unit = with(TableChildren()) {
- apply(children)
- val composable = @Composable {
+ apply(children);
+ @Composable {
val needDecorations = tableDecorationsUnderlay.isNotEmpty() ||
tableDecorationsOverlay.isNotEmpty()
val hasOffsets = verticalOffsets.isNotEmpty() && horizontalOffsets.isNotEmpty()
@@ -504,7 +517,6 @@
tableDecorationsOverlay.forEach { decorationsScope.it() }
}
}
- composable
}
Layout(
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt
index 338bc76..9b5791b 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt
@@ -261,6 +261,7 @@
assertFalse(createdLatch.await(500, TimeUnit.MILLISECONDS))
}
+ @Composable
private fun RippleButton(size: Dp? = null, color: Color? = null, enabled: Boolean = true) {
Ripple(bounded = false, color = color, enabled = enabled) {
Clickable( {
diff --git a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
index bbd5db0..7aacee1 100644
--- a/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/android/AndroidComposeTestRule.kt
@@ -186,7 +186,17 @@
// Dispose the content
if (disposeContentHook != null) {
runOnUiThread {
- disposeContentHook!!()
+ // NOTE: currently, calling dispose after an exception that happened during
+ // composition is not a safe call. Compose runtime should fix this, and then
+ // this call will be okay. At the moment, however, calling this could
+ // itself produce an exception which will then obscure the original
+ // exception. To fix this, we will just wrap this call in a try/catch of
+ // its own
+ try {
+ disposeContentHook!!()
+ } catch (e: Exception) {
+ // ignore
+ }
disposeContentHook = null
}
}
diff --git a/ui/ui-tooling/src/main/java/androidx/ui/tooling/Inspectable.kt b/ui/ui-tooling/src/main/java/androidx/ui/tooling/Inspectable.kt
index acbab2e..055f897 100644
--- a/ui/ui-tooling/src/main/java/androidx/ui/tooling/Inspectable.kt
+++ b/ui/ui-tooling/src/main/java/androidx/ui/tooling/Inspectable.kt
@@ -19,7 +19,7 @@
import androidx.compose.Composable
import androidx.compose.Providers
import androidx.compose.SlotTable
-import androidx.compose.composer
+import androidx.compose.currentComposerIntrinsic
import java.util.Collections
import java.util.WeakHashMap
@@ -29,8 +29,8 @@
*/
@Composable
fun Inspectable(children: @Composable() () -> Unit) {
- composer.collectKeySourceInformation()
- tables.add(composer.slotTable)
+ currentComposerIntrinsic.collectKeySourceInformation()
+ tables.add(currentComposerIntrinsic.slotTable)
Providers(InspectionMode provides true, children = children)
}
diff --git a/ui/ui-vector/api/0.1.0-dev05.txt b/ui/ui-vector/api/0.1.0-dev05.txt
index 169ed2e..253bea7 100644
--- a/ui/ui-vector/api/0.1.0-dev05.txt
+++ b/ui/ui-vector/api/0.1.0-dev05.txt
@@ -105,8 +105,6 @@
public final class VectorComposer extends androidx.compose.Composer<androidx.ui.graphics.vector.VNode> {
ctor public VectorComposer(androidx.ui.graphics.vector.VNode root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
- method public inline <T> void call(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function2<? super androidx.compose.ViewValidator,? super T,java.lang.Boolean> invalid, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
method public inline <T extends androidx.ui.graphics.vector.VNode> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.VNode>,kotlin.Unit> update);
method public inline void emit(Object key, kotlin.jvm.functions.Function0<androidx.ui.graphics.vector.GroupComponent> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.GroupComponent>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public androidx.ui.graphics.vector.VNode getRoot();
diff --git a/ui/ui-vector/api/current.txt b/ui/ui-vector/api/current.txt
index 169ed2e..253bea7 100644
--- a/ui/ui-vector/api/current.txt
+++ b/ui/ui-vector/api/current.txt
@@ -105,8 +105,6 @@
public final class VectorComposer extends androidx.compose.Composer<androidx.ui.graphics.vector.VNode> {
ctor public VectorComposer(androidx.ui.graphics.vector.VNode root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
- method public inline <T> void call(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function2<? super androidx.compose.ViewValidator,? super T,java.lang.Boolean> invalid, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
method public inline <T extends androidx.ui.graphics.vector.VNode> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.VNode>,kotlin.Unit> update);
method public inline void emit(Object key, kotlin.jvm.functions.Function0<androidx.ui.graphics.vector.GroupComponent> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.GroupComponent>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public androidx.ui.graphics.vector.VNode getRoot();
diff --git a/ui/ui-vector/api/public_plus_experimental_0.1.0-dev05.txt b/ui/ui-vector/api/public_plus_experimental_0.1.0-dev05.txt
index 169ed2e..253bea7 100644
--- a/ui/ui-vector/api/public_plus_experimental_0.1.0-dev05.txt
+++ b/ui/ui-vector/api/public_plus_experimental_0.1.0-dev05.txt
@@ -105,8 +105,6 @@
public final class VectorComposer extends androidx.compose.Composer<androidx.ui.graphics.vector.VNode> {
ctor public VectorComposer(androidx.ui.graphics.vector.VNode root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
- method public inline <T> void call(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function2<? super androidx.compose.ViewValidator,? super T,java.lang.Boolean> invalid, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
method public inline <T extends androidx.ui.graphics.vector.VNode> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.VNode>,kotlin.Unit> update);
method public inline void emit(Object key, kotlin.jvm.functions.Function0<androidx.ui.graphics.vector.GroupComponent> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.GroupComponent>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public androidx.ui.graphics.vector.VNode getRoot();
diff --git a/ui/ui-vector/api/public_plus_experimental_current.txt b/ui/ui-vector/api/public_plus_experimental_current.txt
index 169ed2e..253bea7 100644
--- a/ui/ui-vector/api/public_plus_experimental_current.txt
+++ b/ui/ui-vector/api/public_plus_experimental_current.txt
@@ -105,8 +105,6 @@
public final class VectorComposer extends androidx.compose.Composer<androidx.ui.graphics.vector.VNode> {
ctor public VectorComposer(androidx.ui.graphics.vector.VNode root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
- method public inline <T> void call(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function2<? super androidx.compose.ViewValidator,? super T,java.lang.Boolean> invalid, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
method public inline <T extends androidx.ui.graphics.vector.VNode> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.VNode>,kotlin.Unit> update);
method public inline void emit(Object key, kotlin.jvm.functions.Function0<androidx.ui.graphics.vector.GroupComponent> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.GroupComponent>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public androidx.ui.graphics.vector.VNode getRoot();
diff --git a/ui/ui-vector/api/restricted_0.1.0-dev05.txt b/ui/ui-vector/api/restricted_0.1.0-dev05.txt
index 169ed2e..253bea7 100644
--- a/ui/ui-vector/api/restricted_0.1.0-dev05.txt
+++ b/ui/ui-vector/api/restricted_0.1.0-dev05.txt
@@ -105,8 +105,6 @@
public final class VectorComposer extends androidx.compose.Composer<androidx.ui.graphics.vector.VNode> {
ctor public VectorComposer(androidx.ui.graphics.vector.VNode root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
- method public inline <T> void call(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function2<? super androidx.compose.ViewValidator,? super T,java.lang.Boolean> invalid, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
method public inline <T extends androidx.ui.graphics.vector.VNode> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.VNode>,kotlin.Unit> update);
method public inline void emit(Object key, kotlin.jvm.functions.Function0<androidx.ui.graphics.vector.GroupComponent> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.GroupComponent>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public androidx.ui.graphics.vector.VNode getRoot();
diff --git a/ui/ui-vector/api/restricted_current.txt b/ui/ui-vector/api/restricted_current.txt
index 169ed2e..253bea7 100644
--- a/ui/ui-vector/api/restricted_current.txt
+++ b/ui/ui-vector/api/restricted_current.txt
@@ -105,8 +105,6 @@
public final class VectorComposer extends androidx.compose.Composer<androidx.ui.graphics.vector.VNode> {
ctor public VectorComposer(androidx.ui.graphics.vector.VNode root, androidx.compose.SlotTable slotTable, androidx.compose.Recomposer recomposer);
- method public inline void call(Object key, kotlin.jvm.functions.Function1<? super androidx.compose.ViewValidator,java.lang.Boolean> invalid, kotlin.jvm.functions.Function0<kotlin.Unit> block);
- method public inline <T> void call(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function2<? super androidx.compose.ViewValidator,? super T,java.lang.Boolean> invalid, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> block);
method public inline <T extends androidx.ui.graphics.vector.VNode> void emit(Object key, kotlin.jvm.functions.Function0<? extends T> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.VNode>,kotlin.Unit> update);
method public inline void emit(Object key, kotlin.jvm.functions.Function0<androidx.ui.graphics.vector.GroupComponent> ctor, kotlin.jvm.functions.Function1<? super androidx.compose.ComposerUpdater<androidx.ui.graphics.vector.VNode,androidx.ui.graphics.vector.GroupComponent>,kotlin.Unit> update, kotlin.jvm.functions.Function0<kotlin.Unit> children);
method public androidx.ui.graphics.vector.VNode getRoot();
diff --git a/ui/ui-vector/build.gradle b/ui/ui-vector/build.gradle
index 7a109d3..6d80f94 100644
--- a/ui/ui-vector/build.gradle
+++ b/ui/ui-vector/build.gradle
@@ -53,7 +53,6 @@
tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
- // TODO(njawad): Temporary disabled, make it true when IR bug b/129076229 is fixed.
- useIR = false
+ useIR = true
}
}
diff --git a/ui/ui-vector/src/main/java/androidx/ui/graphics/vector/VectorComposeNonIR.kt b/ui/ui-vector/src/main/java/androidx/ui/graphics/vector/VectorComposeNonIR.kt
index dce20d4..cce95c6 100644
--- a/ui/ui-vector/src/main/java/androidx/ui/graphics/vector/VectorComposeNonIR.kt
+++ b/ui/ui-vector/src/main/java/androidx/ui/graphics/vector/VectorComposeNonIR.kt
@@ -25,9 +25,7 @@
import androidx.compose.CompositionReference
import androidx.compose.Recomposer
import androidx.compose.SlotTable
-import androidx.compose.ViewValidator
-import androidx.compose.cache
-import androidx.compose.currentComposerNonNull
+import androidx.compose.currentComposerIntrinsic
import java.util.WeakHashMap
private val VectorCompositions = WeakHashMap<VectorComponent, VectorComposition>()
@@ -56,7 +54,7 @@
content: @Composable VectorScope.(viewportWidth: Float, viewportHeight: Float) -> Unit
) {
super.compose {
- val composer = currentComposerNonNull as VectorComposer
+ val composer = currentComposerIntrinsic as VectorComposer
val scope = VectorScope(composer)
scope.content(container.viewportWidth, container.viewportHeight)
}
@@ -111,43 +109,6 @@
children()
endNode()
}
-
- inline fun call(
- key: Any,
- /*crossinline*/
- invalid: ViewValidator.() -> Boolean,
- block: () -> Unit
- ) {
- startGroup(key)
- if (ViewValidator(this).invalid() || inserting) {
- startGroup(0)
- block()
- endGroup()
- } else {
- skipCurrentGroup()
- }
- endGroup()
- }
-
- inline fun <T> call(
- key: Any,
- /*crossinline*/
- ctor: () -> T,
- /*crossinline*/
- invalid: ViewValidator.(f: T) -> Boolean,
- block: (f: T) -> Unit
- ) {
- startGroup(key)
- val f = cache(true, ctor)
- if (ViewValidator(this).invalid(f) || inserting) {
- startGroup(0)
- block(f)
- endGroup()
- } else {
- skipCurrentGroup()
- }
- endGroup()
- }
}
fun disposeVector(container: VectorComponent, parent: CompositionReference? = null) {