rewrite icon indicating copy to clipboard operation
rewrite copied to clipboard

Use K2Compiler via JvmFirPipeline to support Kotlin v2

Open Crustack opened this issue 2 months ago • 0 comments

What's changed?

  • [x] Update kotlin-compiler dependencies to 2.2.21
  • [x] Implement JvmFirPipeline to use current K2 phased compiler API to generate FirFiles
  • [x] Update KotlinIrTypeMapping, IrTreeVisitor, KotlinTypeIrSignatureBuilder to be compilable, but they are not used atm
  • [x] Update KotlinTypeMapping, KotlinTypeSignatureBuilder, PsiElementAssociations for new compiler dependency versions to be compilable
  • [ ] Check all rewrite-kotlin tests still work and adjust KotlinTypeMapping, KotlinTypeSignatureBuilder, PsiElementAssociations if necessary
  • [ ] To provide the K2 Compiler with proper String paths, the kotlin sources are copied into a tmp folder, not sure if this can be done with LightVirtualFiles?

What's your motivation?

  • Closes #6007
  • Groundwork for https://github.com/openrewrite/rewrite/pull/6325

Anything in particular you'd like reviewers to focus on?

rewrite-kotlin test stats atm: ✅ 1.001 pass, ❌118 fail

Some Tests fail because the recipes do not make all correct changes yet, probably due to some missing modifications to PsiElementAssociations and KotlinTypeSignatureBuilder. I will try to investigate that further.

A few tests fail, where the compiler returns compile errors. I am not so sure what the intended behaviour should be for these cases, e.g.:

Tests with K2 Compilation errors

EqualsMethodUsageTest.replace:

/tmp/rewrite574599695127284439/openRewriteFile0.kt:3:1: error: missing return statement.
}
^

ChangePackageTest.changePackageSecondaryConstructor:

this type is final, so it cannot be extended.
class A() : Original() {
            ^^^^^^^^

RemoveLambdaArgumentParenthesesTest.NoChangeWhenNotLambda:

/tmp/rewrite895204994807792292/openRewriteFile0.kt:1:1: error: conflicting overloads:
fun method(): Unit
fun method() {
^^^^^^^^^^^^
/tmp/rewrite895204994807792292/openRewriteFile1.kt:1:1: error: conflicting overloads:
fun method(): Unit
fun method() {
^^^^^^^^^^^^

MinimumViableSpacingTest.infixOperator:

/tmp/rewrite9946978307521212855/openRewriteFile0.kt:1:19: error: literals must be surrounded by whitespace.
val l = listOf('a'to 1)
                  ^^

TabsAndIndentsTest.annotationIndentation:

/tmp/rewrite8740096574429919170/openRewriteFile0.kt:3:1: error: this annotation is not applicable to target 'class'. Applicable targets: constructor, function, getter, setter, expression
@SafeVarargs
^^^^^^^^^^^^

TabsAndIndentsTest.methodArgumentsThatDontStartOnNewLine2:

/tmp/rewrite8740096574429919170/openRewriteFile0.kt:5:24: error: argument type mismatch: actual type is 'Unit', but 'Int' was expected.
        return method5(method5(method5(method5(3,
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
/tmp/rewrite8740096574429919170/openRewriteFile0.kt:5:32: error: argument type mismatch: actual type is 'Unit', but 'Int' was expected.
        return method5(method5(method5(method5(3,
                               ^^^^^^^^^^^^^^^^^^
/tmp/rewrite8740096574429919170/openRewriteFile0.kt:5:40: error: argument type mismatch: actual type is 'Unit', but 'Int' was expected.
        return method5(method5(method5(method5(3,
                                       ^^^^^^^^^^

CompilationUnitTest.packageDecl:

/tmp/rewrite14113186597569014177/openRewriteFile0.kt:1:1: error: only the Kotlin standard library is allowed to use the 'kotlin' package
package kotlin
^^^^^^^^^^^^^^

MemberReferenceTest.firCallableReferenceAccess:

/tmp/rewrite14113186597569014177/openRewriteFile0.kt:9:23: error: unresolved reference 'unresolved'.
  Foo.Bar(1).method(::unresolved)
                      ^^^^^^^^^^
/tmp/rewrite17488290301649377049/openRewriteFile0.kt:1:1: error: 'expect' and 'actual' declarations can be used only in multiplatform projects. Learn more about Kotlin Multiplatform: https://kotl.in/multiplatform-setup
expect suspend fun Any.executeAsync(): Any
^^^^^^

WhileLoopTest.unaryOp:

/tmp/rewrite14113186597569014177/openRewriteFile0.kt:3:15: error: 'val' cannot be reassigned.
    while (-- len > 0) {
              ^^^
/tmp/rewrite14113186597569014177/openRewriteFile0.kt:5:19: error: 'val' cannot be reassigned.
    while (0 < -- len) {
                  ^^^

AnnotationTest.multipleFileScope:

/tmp/rewrite8740096574429919170/openRewriteFile1.kt:2:1: error: this annotation is not repeatable.
@file : Anno
^^^^^^^^^^^^
/tmp/rewrite8740096574429919170/openRewriteFile1.kt:3:1: error: this annotation is not repeatable.
@file : Anno
^^^^^^^^^^^^

AnnotationTest.annotationUseSiteTarget:

/tmp/rewrite8740096574429919170/openRewriteFile0.kt:1:18: error: redeclaration:
annotation class Anno : Annotation
annotation class Anno
                 ^^^^
/tmp/rewrite8740096574429919170/openRewriteFile1.kt:1:18: error: redeclaration:
annotation class Anno : Annotation
annotation class Anno
                 ^^^^

MethodInvocationTest.unresolvedMethodInvocationName:

/tmp/rewrite4137133719902878536/openRewriteFile0.kt:1:9: error: unresolved reference 'some'.
val x = some .  qualified   . fooBar ( )
        ^^^^

ReturnTest.implicitReturn:

/tmp/rewrite1617474480328035921/openRewriteFile0.kt:3:1: error: missing return statement.
}
^

ClassDeclarationTest.modifiers[4]:

/tmp/rewrite9946978307521212855/openRewriteFile0.kt:1:1: error: modifier 'protected' is not applicable inside 'file'.
protected class Foo
^^^^^^^^^

ImportTest.escapedImport:

/tmp/rewrite8740096574429919170/openRewriteFile0.kt:1:12: error: unresolved reference 'should be equal to'.
import org.`should be equal to`
           ^^^^^^^^^^^^^^^^^^^^

ImportTest.inlineImport:

/tmp/rewrite8740096574429919170/openRewriteFile1.kt:1:12: error: unresolved reference 'method'.
import a.b.method
           ^^^^^^

ImportTest.quotedImportWithDollar:

/tmp/rewrite8740096574429919170/openRewriteFile0.kt:1:8: error: unresolved reference 'my'.
import my.org.`$x`
       ^^

IfTest.multipleDeSugaredParens:

/tmp/rewrite9946978307521212855/openRewriteFile0.kt:2:13: error: 'if' must have both main and 'else' branches when used as an expression.
    ( ( ( ( if ( ( ( a ) ) == ( ( null ) ) ) return ) ) ) )
            ^^

VariableDeclarationTest.unresolvedNameFirSource:

/tmp/rewrite9946978307521212855/openRewriteFile0.kt:1:9: error: unresolved reference 'SomeInput'.
val t = SomeInput . Test
        ^^^^^^^^^

Does OpenRewrite support running recipes on code that doesnt compile by default? I am not sure if K2Compiler allows to disable throwing these diagnostics as errors via something like K2JVMCompilerArguments.suppressedDiagnostics, maybe @e5l can help out on this?

Anyone you would like to review specifically?

@shanman190 @jkschneider

Any additional context

Checklist

  • [ ] I've added unit tests to cover both positive and negative cases
  • [ ] I've read and applied the recipe conventions and best practices
  • [x] I've used the IntelliJ IDEA auto-formatter on affected files

Crustack avatar Nov 25 '25 12:11 Crustack