Hi! Trying to adopt my Ir backend compiler plugin ...
# compiler
p
Hi! Trying to adopt my Ir backend compiler plugin for Js target. While Jvm works, for Js I've faced with problem: if assign to IrSimplyFunction.body body of type IrExpressionBody (func.body = IrFactory.createExpressionBody(...)) then compiler issue an error 'e: java.lang.ClassCastException' to console and compilation will fail with internal compiler error without any stack trace. If change to IrBlockBody with one return statement returning expression then it compiles successfully. Compiler version is 2.0.0 Reproducing sample code is in thread. P.S. while making reproducing sample got more info about an exception (wrote in thread)
Copy code
val klass: IrClass = ...
val pluginContext: IrPluginContext = ...
klass.addFunction {
    name = Name.identifier("testGeneratedFun")
    returnType = context.irBuiltIns.anyType
}.let { func ->
    val willFailWithJavaLangClassCastException = true
    if (willFailWithJavaLangClassCastException) {
        func.body = func.factory.createExpressionBody(
            IrConstImpl(
                startOffset = UNDEFINED_OFFSET,
                endOffset = UNDEFINED_OFFSET,
                type = pluginContext.irBuiltIns.booleanType,
                kind = IrConstKind.Boolean,
                value = true
            )
        )
    } else {
        func.body = func.factory.createBlockBody(
            startOffset = UNDEFINED_OFFSET,
            endOffset = UNDEFINED_OFFSET
        ).apply {
            statements.add(
                IrReturnImpl(
                    startOffset = UNDEFINED_OFFSET,
                    endOffset = UNDEFINED_OFFSET,
                    type = pluginContext.irBuiltIns.booleanType,
                    returnTargetSymbol = func.symbol,
                    value = IrConstImpl(
                        startOffset = UNDEFINED_OFFSET,
                        endOffset = UNDEFINED_OFFSET,
                        type = pluginContext.irBuiltIns.booleanType,
                        kind = IrConstKind.Boolean,
                        value = true
                    )
                )
            )
        }
    }
}
This sample code produce error message for willFailJavaLangClassCastException == true:
Copy code
java.lang.ClassCastException: class org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl cannot be cast to class org.jetbrains.kotlin.ir.expressions.IrBody (org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl and org.jetbrains.kotlin.ir.expressions.IrBody are in unnamed module of loader 'app')
And stack trace:
Copy code
java.lang.ClassCastException: class org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl cannot be cast to class org.jetbrains.kotlin.ir.expressions.IrBody (org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl and org.jetbrains.kotlin.ir.expressions.IrBody are in unnamed module of loader 'app')
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer$withDeserializedIrFunctionBase$1$1$1$1.invoke(IrDeclarationDeserializer.kt:580)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer$withDeserializedIrFunctionBase$1$1$1$1.invoke(IrDeclarationDeserializer.kt:569)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.withBodyGuard(IrDeclarationDeserializer.kt:512)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.access$withBodyGuard(IrDeclarationDeserializer.kt:68)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeIrFunction$ir_serialization_common(IrDeclarationDeserializer.kt:1208)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration(IrDeclarationDeserializer.kt:821)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration$default(IrDeclarationDeserializer.kt:815)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeIrClass(IrDeclarationDeserializer.kt:390)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration(IrDeclarationDeserializer.kt:820)
	at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration$default(IrDeclarationDeserializer.kt:815)
	at org.jetbrains.kotlin.backend.common.serialization.IrFileDeserializer.deserializeDeclaration(IrFileDeserializer.kt:40)
	at org.jetbrains.kotlin.backend.common.serialization.FileDeserializationState.deserializeAllFileReachableTopLevel(IrFileDeserializer.kt:127)
	at org.jetbrains.kotlin.backend.common.serialization.BasicIrModuleDeserializer$ModuleDeserializationState.deserializeReachableDeclarations(BasicIrModuleDeserializer.kt:173)
	at org.jetbrains.kotlin.backend.common.serialization.BasicIrModuleDeserializer.deserializeReachableDeclarations(BasicIrModuleDeserializer.kt:141)
	at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.deserializeAllReachableTopLevels(KotlinIrLinker.kt:110)
	at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.findDeserializedDeclarationForSymbol(KotlinIrLinker.kt:121)
	at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.deserializeOrResolveDeclaration(KotlinIrLinker.kt:158)
	at org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.getDeclaration(KotlinIrLinker.kt:147)
	at org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator.generateUnboundSymbolsAsDependencies(ExternalDependenciesGenerator.kt:39)
	at org.jetbrains.kotlin.ir.backend.js.ic.LoadedJsIr.loadUnboundSymbols(JsIrLinkerLoader.kt:80)
	at org.jetbrains.kotlin.ir.backend.js.ic.JsIrLinkerLoader.loadIr(JsIrLinkerLoader.kt:247)
	at org.jetbrains.kotlin.ir.backend.js.ic.JsIrLinkerLoader.loadIr$default(JsIrLinkerLoader.kt:191)
	at org.jetbrains.kotlin.ir.backend.js.ic.CacheUpdater.loadIrForDirtyFilesAndInitCompiler(CacheUpdater.kt:704)
	at org.jetbrains.kotlin.ir.backend.js.ic.CacheUpdater.loadIrAndMakeIrFragmentGenerators(CacheUpdater.kt:768)
	at org.jetbrains.kotlin.ir.backend.js.ic.CacheUpdater.actualizeCaches(CacheUpdater.kt:804)
	at org.jetbrains.kotlin.cli.js.K2JsIrCompiler.prepareIcCaches(K2JsIrCompiler.kt:716)
	at org.jetbrains.kotlin.cli.js.K2JsIrCompiler.doExecute(K2JsIrCompiler.kt:308)
	at org.jetbrains.kotlin.cli.js.K2JSCompiler.doExecute(K2JSCompiler.java:109)
	at org.jetbrains.kotlin.cli.js.K2JSCompiler.doExecute(K2JSCompiler.java:72)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:104)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:48)
	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
	at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1556)
	at jdk.internal.reflect.GeneratedMethodAccessor15.invoke(Unknown Source)
	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:840)
e
Did you open an issue on YT for this?
p
Not yet. First asking here if it is known issue.
👍 1
As there is some timeout passed without any comments I've posted an issuse then: https://youtrack.jetbrains.com/issue/KT-69439/Js-Ir-backend-compiler-error-for-IrExpressionBody-as-IrFunction-body
e
There were other issues in the past for the JS backend, so it's possible this is a new one
n
Hi, Is
pluginContext.irFactory.createExpressionBody
still binary compatible between
2.0.0
and
2.0.20
? it looks like
IrFactory
moved from being an interface into a class in https://github.com/JetBrains/kotlin/commit/7f6562285b6b228e435550e1a0a5a12fbab9a6cb AFAIK methods on JVM uses
invokevirtual
whereas on interface they use
invokeinterface
which makes it binary incompatible hence the error message reported in https://github.com/kotest/kotest/issues/4177 https://youtrack.jetbrains.com/issue/KT-69439/ and https://github.com/realm/realm-kotlin/issues/1825
Polite ping @Wojciech Litewka
w
Yes, as you say, it will likely be incompatible because of the interface -> class change. KT-69439 doesn't seem related though.
n
Thanks is there a recommended work around? this forces the libraries to bump to minimum 2.0.20 to remain compatible with clients using 2.0.20+?
w
Unfortunately no, this is how compiler plugins work right now, they have to be compiled against a specific version of a compiler, and may now work if run on another version. This may be resolved once we develop a stable API for plugins.
Somewhat a walkaround may be for library authors to adopt the release scheme of KSP - example - where the same version of a library may be published for multiple versions of kotlin.
👍 1
n
Thanks for the explanation Wojciech 👍