JetBrains / compose-multiplatform

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

Compose Compiler 1.4 Regression IR lowering failed #2683

Closed ccjernigan closed 1 month ago

ccjernigan commented 1 year ago

Steps to reproduce

  1. Have an inline class with a private constructor (instantiated with a companion object factory method)
  2. Use the inline object in a @Composable

I'm still narrowing down the exact steps to reproduce, but it is something like this:

@Serializable
@JvmInline
value class Email private constructor(@SerialName("email") val emailString: String) {
    init {
        require(EmailValidator.isValidLowercase(emailString))
        require(emailString.length <= MAX_EMAIL_LENGTH) { "Email must be <= $MAX_EMAIL_LENGTH but is ${emailString.length}" }
    }

    companion object {
        const val MAX_EMAIL_LENGTH = 320

        fun new(emailString: String): Email {
            val normalizedEmail = emailString.lowercase()

            return Email(normalizedEmail)
        }
    }
}

@Composable
@Suppress("LongMethod")
private fun SignUpForm(
    errorMessage: String?,
    prevEmail: Email,
    userBuilder: User.Builder?,
    action: (User.Builder) -> Unit
) {
    val (firstName, setFirstName) = remember { mutableStateOf(userBuilder?.firstName ?: "") }
    val (lastName, setLastName) = remember { mutableStateOf(userBuilder?.lastName ?: "") }
    val (password, setPassword) = remember { mutableStateOf(userBuilder?.password?.plaintext ?: "") }
    val submitForm = {
        val builder = User.Builder(firstName, lastName, prevEmail, Password(password)) // Commenting out this line will resolve the compile failure
        action(builder)
    }
}

Results

Compilation fails with an exception documented below.

Workarounds

Remove inline keyword from the class OR make the constructor non-private.

Notes

This reproduces with Kotlin 1.8, JetBrains Compose Compiler 1.4.0, and JetBrains Compose 1.3.0

e: java.lang.Exception: IR lowering failed at: ChangePasswordSection.kt
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.visitFile(ComposableFunctionBodyTransformer.kt:4665)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitFile(IrElementTransformerVoid.kt:48)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitFile(IrElementTransformerVoid.kt:24)
        at org.jetbrains.kotlin.ir.declarations.IrFile.accept(IrFile.kt:30)
        at org.jetbrains.kotlin.ir.declarations.IrFile.transform(IrFile.kt:33)
        at org.jetbrains.kotlin.ir.declarations.IrFile.transform(IrFile.kt:21)
        at org.jetbrains.kotlin.ir.util.TransformKt.transformInPlace(transform.kt:35)
        at org.jetbrains.kotlin.ir.declarations.IrModuleFragment.transformChildren(IrModuleFragment.kt:51)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoidKt.transformChildrenVoid(IrElementTransformerVoid.kt:346)
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.lower(ComposableFunctionBodyTransformer.kt:480)
        at androidx.compose.compiler.plugins.kotlin.ComposeIrGenerationExtension.generate(ComposeIrGenerationExtension.kt:171)
        at org.jetbrains.kotlin.ir.backend.js.KlibKt.generateModuleFragmentWithPlugins$lambda$20(klib.kt:552)
        at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment(Psi2IrTranslator.kt:104)
        at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment$default(Psi2IrTranslator.kt:81)
        at org.jetbrains.kotlin.ir.backend.js.KlibKt.generateModuleFragmentWithPlugins(klib.kt:561)
        at org.jetbrains.kotlin.ir.backend.js.KlibKt.generateIrForKlibSerialization(klib.kt:181)
        at org.jetbrains.kotlin.ir.backend.js.KlibKt.generateKLib(klib.kt:223)
        at org.jetbrains.kotlin.ir.backend.js.KlibKt.generateKLib$default(klib.kt:205)
        at org.jetbrains.kotlin.cli.js.K2JsIrCompiler.doExecute(K2JsIrCompiler.kt:353)
        at org.jetbrains.kotlin.cli.js.K2JSCompiler.doExecute(K2JSCompiler.java:183)
        at org.jetbrains.kotlin.cli.js.K2JSCompiler.doExecute(K2JSCompiler.java:72)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:101)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:47)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
        at org.jetbrains.kotlin.incremental.IncrementalJsCompilerRunner.runCompiler(IncrementalJsCompilerRunner.kt:213)
        at org.jetbrains.kotlin.incremental.IncrementalJsCompilerRunner.runCompiler(IncrementalJsCompilerRunner.kt:84)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.doCompile(IncrementalCompilerRunner.kt:424)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileImpl(IncrementalCompilerRunner.kt:360)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileNonIncrementally(IncrementalCompilerRunner.kt:242)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:98)
        at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile$default(IncrementalCompilerRunner.kt:80)
        at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execJsIncrementalCompiler(CompileServiceImpl.kt:566)
        at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execJsIncrementalCompiler(CompileServiceImpl.kt:101)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1837)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
        at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
        at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
        at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.IllegalStateException: Expected a value parameter
        at androidx.compose.compiler.plugins.kotlin.lower.AbstractComposeLowering.unboxValueIfInline(AbstractComposeLowering.kt:228)
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.irChanged(ComposableFunctionBodyTransformer.kt:2115)
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.buildPreambleStatementsAndReturnIfSkippingPossible(ComposableFunctionBodyTransformer.kt:1475)
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.visitRestartableComposableFunction(ComposableFunctionBodyTransformer.kt:1170)
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.visitFunctionInScope(ComposableFunctionBodyTransformer.kt:770)
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.visitFunction(ComposableFunctionBodyTransformer.kt:736)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitSimpleFunction(IrElementTransformerVoid.kt:72)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitSimpleFunction(IrElementTransformerVoid.kt:73)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitSimpleFunction(IrElementTransformerVoid.kt:24)
        at org.jetbrains.kotlin.ir.declarations.IrSimpleFunction.accept(IrSimpleFunction.kt:36)
        at org.jetbrains.kotlin.ir.IrElementBase.transform(IrElementBase.kt:24)
        at org.jetbrains.kotlin.ir.util.TransformKt.transformInPlace(transform.kt:35)
        at org.jetbrains.kotlin.ir.declarations.IrFile.transformChildren(IrFile.kt:40)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitPackageFragment(IrElementTransformerVoid.kt:41)
        at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitFile(IrElementTransformerVoid.kt:47)
        at androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer.visitFile(ComposableFunctionBodyTransformer.kt:1859)
        ... 50 more
pablichjenkov commented 1 year ago

It seems pretty similar to this one: https://github.com/JetBrains/compose-jb/issues/2615

eymar commented 1 year ago

Related: https://github.com/JetBrains/compose-jb/issues/2613

okushnikov commented 3 months ago

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