I'm trying to do a relatively simple transform whe...
# compiler
r
I'm trying to do a relatively simple transform where I turn annotated function params into another type, and delegate the original param out of them as a var, like
fun test(x: @Watched Int)
-->
fun test(x$watch: Watcher<Int>){ var x by x$watch ...
This is easy enough on the IR side, but I get "Can't assign to a var" errors, and when I suppress them,
Not a variable: value-parameter x: @com.rnett.klairvoyant.Watched <http://kotlin.Int|kotlin.Int>
errors from
org.jetbrains.kotlin.psi2ir
classes. Is there a way to intercept this phase or another way around this? I'm trying to avoid editing the PSI because it looks like a pain after looking at arrow-meta.
Copy code
e: java.lang.AssertionError: Not a variable: value-parameter x: @com.rnett.klairvoyant.Watched <http://kotlin.Int|kotlin.Int> defined in com.rnett.klairvoyant.test[ValueParameterDescriptorImpl@213496a8]
	at org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue.store(VariableLValue.kt:52)
	at org.jetbrains.kotlin.psi2ir.intermediate.AssignmentReceiver$assign$1.invoke(Values.kt:35)
	at org.jetbrains.kotlin.psi2ir.intermediate.AssignmentReceiver$assign$1.invoke(Values.kt:33)
	at org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue.assign(VariableLValue.kt:57)
	at org.jetbrains.kotlin.psi2ir.intermediate.AssignmentReceiver$DefaultImpls.assign(Values.kt:35)
	at org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue.assign(VariableLValue.kt:31)
	at org.jetbrains.kotlin.psi2ir.generators.AssignmentGenerator.generateAssignment(AssignmentGenerator.kt:49)
	at org.jetbrains.kotlin.psi2ir.generators.OperatorExpressionGenerator.generateBinaryExpression(OperatorExpressionGenerator.kt:137)
	at org.jetbrains.kotlin.psi2ir.generators.StatementGenerator.visitBinaryExpression(StatementGenerator.kt:423)
	at org.jetbrains.kotlin.psi2ir.generators.StatementGenerator.visitBinaryExpression(StatementGenerator.kt:50)
	at org.jetbrains.kotlin.psi.KtBinaryExpression.accept(KtBinaryExpression.java:35)
	at org.jetbrains.kotlin.psi2ir.generators.StatementGenerator.genStmt(StatementGenerator.kt:75)
	at org.jetbrains.kotlin.psi2ir.generators.StatementGenerator.generateStatement(StatementGenerator.kt:65)
	at org.jetbrains.kotlin.psi2ir.generators.StatementGenerator.generateStatements(StatementGenerator.kt:68)
	at org.jetbrains.kotlin.psi2ir.generators.BodyGenerator.generateFunctionBody(BodyGenerator.kt:59)
	at org.jetbrains.kotlin.psi2ir.generators.FunctionGenerator.generateFunctionDeclaration(FunctionGenerator.kt:41)
	at org.jetbrains.kotlin.psi2ir.generators.DeclarationGenerator.generateMemberDeclaration(DeclarationGenerator.kt:44)
	at org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator.generateSingleFile(ModuleGenerator.kt:80)
	at org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator.generateFiles(ModuleGenerator.kt:65)
	at org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator.generateModuleFragmentWithoutDependencies(ModuleGenerator.kt:42)
	at org.jetbrains.kotlin.psi2ir.Psi2IrTranslator.generateModuleFragment(Psi2IrTranslator.kt:74)
	at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFiles(JvmBackendFacade.kt:65)
	at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.generateModule(JvmIrCodegenFactory.kt:37)
	at org.jetbrains.kotlin.codegen.KotlinCodegenFacade.compileCorrectFiles(KotlinCodegenFacade.java:35)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.generate(KotlinToJVMBytecodeCompiler.kt:640)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:196)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:164)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:51)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:86)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44)
	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:105)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:346)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:102)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:240)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.access$compileIncrementally(IncrementalCompilerRunner.kt:39)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner$compile$2.invoke(IncrementalCompilerRunner.kt:81)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:93)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:606)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:99)
	at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1645)
	at jdk.internal.reflect.GeneratedMethodAccessor104.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:359)
	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(Native Method)
	at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1135)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:844)
Full stack trace:
s
I doubt you can avoid editing PSI in that case, basically you have to make frontend happy with the code you have written. I assume you are trying to assign something to x which is not something that is allowed by default 🙂
r
Yeah, ugh. Do you know of any way to make `replace`/`astReplace` work? I'm trying to avoid re-writing the entire file's text like meta does.
s
Regarding interception of psi2ir, there used to be a way pre-1.3.70, afaik compose used something like that before.
I know that PSI is unmodifiable in compiler, but I am not sure how it is freezed. So far, replacing the whole file is the best solution I have seen 🙂
Maybe you can adjust your api so that it pass compiler checks?
Also, also, even it wouldn't throw exceptions, that
var x
will be something different rather than
x
from parameters for the backend, so you will have to patch all accessors there 🙂
r
Yeah, I was planning on that. I'm essentially trying to wrap stuff in observers transparently, and wanted a way to pass the observer to a function and change its value without having to un-delegate, it, but that doesn't seem possible without rewriting the files. Which I'll probably get to eventually, but not for now.
this is not possible in the CLI as Andrei pointed out. Meta uses it’s own representation that wraps psi to produce new trees for this reason. That api only works in IDEA.
Meta has automatic synth resolution in the IDE also you will have to build that piece if your plugin adds any declarations or expands code in a way you are altering line nubers etc in the doc
also just transforming IR implies your users will never see anything useful in regular highlighting until they build the whole project when they are in IDEA