Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting TypeMirror breaks multiplatform KSP usage #1273

Closed
micHar opened this issue Jun 27, 2022 · 12 comments
Closed

Supporting TypeMirror breaks multiplatform KSP usage #1273

micHar opened this issue Jun 27, 2022 · 12 comments

Comments

@micHar
Copy link

micHar commented Jun 27, 2022

buildCodeBlock {
        add("return %T(", Whatever::class)
}

Even though this uses KClass, I get this error when running e.g. kspKotlinIosArm64

        java.lang.NoClassDefFoundError: javax/lang/model/type/TypeMirror
        at com.squareup.kotlinpoet.CodeBlock$Builder.argToType(CodeBlock.kt:377)
        at com.squareup.kotlinpoet.CodeBlock$Builder.addArgument(CodeBlock.kt:346)
        at com.squareup.kotlinpoet.CodeBlock$Builder.add(CodeBlock.kt:318)

This PR deprecated support for TypeMirror in 2020, maybe it's time to drop it? If not, maybe this piece of code can be refactored so that TypeName isn't evaluated if not necessary?

    private fun argToType(o: Any?) = when (o) {
      is TypeName -> o
      is TypeMirror -> {
        logDeprecationWarning(o)
        o.asTypeName()
      }
      is Element -> {
        logDeprecationWarning(o)
        o.asType().asTypeName()
      }
      is Type -> o.asTypeName()
      is KClass<*> -> o.asTypeName()
      else -> throw IllegalArgumentException("expected type but was $o")
    }

If you think it's a good idea, I could contribute.

@Egorand
Copy link
Collaborator

Egorand commented Jun 27, 2022

Are you trying to run KotlinPoet on a non-JVM platform? It is possible to generate platform-agnostic code with KotlinPoet, however you need a JDK to be able to use the library.

This PR deprecated support for TypeMirror in 2020, maybe it's time to drop it?

We can only make ABI-breaking changes in major releases, we can consider dropping this API for KotlinPoet 2.0, but we're not there yet.

@ZacSweers
Copy link
Collaborator

Yeah my understanding was KSP allows for generating code in MPP projects, but not that processing itself was supposed to run in non-JVM environments. A repro project would be great

@micHar
Copy link
Author

micHar commented Jun 27, 2022

In my own project I will be generating ios source sets from common code so I won't need that, but I noticed that when playing with different source set configurations.
I know that KSP team works on some proper multiplatform support for KSP 2 and even today there are tasks like kspIosArm64 etc which, when I got rid of this TypeMirror error, worked pretty fine in a non trivial annotation processor (nothing else broke in kotlinpoet and I use it extensively). I think that if one doesn't use jvm types, he should be fine running ksp on non jvm env.

Repro shouldn't be hard, I will try to prepare something.

Also, from my other experiments, it seemed that merely moving some code to another file so that jvm type isn't resolved or imported, made it possible to run ksp tasks on non-jvm platform, so I think this refactoring could be done in a grateful way - such that if you provide KClass or another "proper" type then you don't need to worry about TypeMirror breaking non-jvm build but at the same time with TypeMirror legacy support. Will be more obvious with a repro...

@ZacSweers
Copy link
Collaborator

Right, what you're describing makes sense, my confusion is that my understanding is that the compiler step KSP runs within is still running in a JVM environment, even if its outputs are for different platforms. It would be surprising to me if this is not the case.

@Egorand
Copy link
Collaborator

Egorand commented Jun 27, 2022

KSP is a Gradle plugin, and Gradle requires JVM, right? Or is it possible to run KSP without Gradle, or Gradle without JVM?

@micHar
Copy link
Author

micHar commented Jun 27, 2022

I believe so, I even have my processor defined as a jvm module, but I'm not sure if it's a problem. My case was:

  1. Have annotation on commonMain source sets.
  2. Add processor as a dependency to kspIosArm64 like so: Improve Multiplatform Support With Source Set-Based Configuration google/ksp#1021.
  3. See iosArm64 source sets generated properly (having got rid of the TypeMirror error).

And that's what I'll try to reproduce.

@micHar
Copy link
Author

micHar commented Jun 27, 2022

Here's the repro :) https://github.com/micHar/kotlinpoet-ksp-repro

micHar added a commit to micHar/kotlinpoet that referenced this issue Jul 12, 2022
@micHar
Copy link
Author

micHar commented Jul 12, 2022

It turns out that simply changing the order of checks is enough to fix the issue. PR awaiting review (you can check that it works with the reproduction repository attached above).

@Egorand
Copy link
Collaborator

Egorand commented Jul 12, 2022

I checked out the repro project and could reproduce the issue - thanks! I'm not overly familiar with KSP, can you please explain if there's anything to gain from doing add("kspIosArm64", project(":processor")) instead of add("kspCommonMainMetadata", project(":processor")) in your project?

I'm also not in favour of the fix you provided (thanks for that though!), the right solution would be to completely remove any reference to JDK-specific types from KotlinPoet core. I think it'd be great to do that in 2.0, but currently I don't believe it's doable without breaking the API.

@micHar
Copy link
Author

micHar commented Jul 13, 2022

It's explained a bit here google/ksp#965, though I'm not sure what will be the final form of multiplatform KSP. In general, imagine a processor, that takes common code as input but generates source sets just for ios. This is what koru is doing in kapt right now and I'm in the process of rewriting it for ksp. Now, there is no established pattern for this in ksp yet, so what I'm doing right now is generating via kspCommonMainMetadata and manually adding generated dir to ios source sets, but afaiu, when ksp is ready, the right thing to do will be to run the processor in the right source set with e.g. kspIosArm64. I don't really understand why javax is not available for them though, since the processor itself is a jvm thing as you observed. I think I might create an issue in ksp itself to make sure it's by design.

@Egorand
Copy link
Collaborator

Egorand commented Jul 13, 2022

Thanks for the context! Yeah, sounds like it might indeed be a KSP issue. I don't imagine KSP itself can be executed without a JDK (since it's a Gradle plugin), so don't see why it wouldn't expose JDK types to annotation processors. If you could link the KSP issue you create to this one that'd be great!

@micHar
Copy link
Author

micHar commented Jul 13, 2022

Sure, it's here.

@Egorand Egorand closed this as not planned Won't fix, can't repro, duplicate, stale Jul 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants