[go: nahoru, domu]

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) {