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

Use KSP2 #350

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open

Use KSP2 #350

wants to merge 18 commits into from

Conversation

eygraber
Copy link
Contributor

@eygraber eygraber commented Feb 8, 2024

No description provided.

@eygraber eygraber force-pushed the ksp2 branch 3 times, most recently from bb53268 to 009a7e7 Compare June 17, 2024 17:05
@eygraber eygraber force-pushed the ksp2 branch 2 times, most recently from 761cad1 to f52527a Compare July 11, 2024 21:34
@eygraber eygraber force-pushed the ksp2 branch 2 times, most recently from 8fb90a7 to 82ddb23 Compare November 15, 2024 00:41
@eygraber
Copy link
Contributor Author

@evant I updated all dependencies to latest versions, but looks like google/ksp#1854 is still an issue, as well as some issues with typealiases which might be related to https://kotlinlang.slack.com/archives/C013BA8EQSE/p1716431911867909. I tested with 2.1.0-RC and both issues are present there as well.

I probably won't have much time to dedicate to this for the next few months, in case there's anyone who'd like to pick it up.

@ting-yuan
Copy link

The exception KtInvalidLifetimeOwnerAccessException: Access to invalid KtAlwaysAccessibleLifetimeToken: PSI has changed since creation, was thrown in the second round in the SymbolProcessor.finish()

invoke:79, AbstractKSDeclarationImpl$containingFile$2 (com.google.devtools.ksp.impl.symbol.kotlin)
invoke:78, AbstractKSDeclarationImpl$containingFile$2 (com.google.devtools.ksp.impl.symbol.kotlin)
lambda 'synchronized' in 'value':74, SynchronizedLazyImpl (kotlin)
getValue:69, SynchronizedLazyImpl (kotlin)
getContainingFile:78, AbstractKSDeclarationImpl (com.google.devtools.ksp.impl.symbol.kotlin)
lambda 'apply' in 'addOriginatingElement':95, KSAstProvider (me.tatarka.kotlin.ast)
addOriginatingElement:94, KSAstProvider (me.tatarka.kotlin.ast)
lambda 'forEach' in 'generate':27, KmpComponentCreateGenerator (me.tatarka.inject.compiler)
forEach:1863, KmpComponentCreateGenerator (me.tatarka.inject.compiler)
lambda 'apply' in 'generate':23, KmpComponentCreateGenerator (me.tatarka.inject.compiler)
lambda 'with' in 'generate':22, KmpComponentCreateGenerator (me.tatarka.inject.compiler)
generate:18, KmpComponentCreateGenerator (me.tatarka.inject.compiler)
lambda 'forEach' in 'generateKmpComponentCreateFiles':40, ProcessKmpComponentCreateKt (me.tatarka.inject.compiler.ksp)
forEach:216, ProcessKmpComponentCreateKt (me.tatarka.inject.compiler.ksp)
generateKmpComponentCreateFiles:39, ProcessKmpComponentCreateKt (me.tatarka.inject.compiler.ksp)
finish:113, InjectProcessor (me.tatarka.inject.compiler.ksp)
lambda 'forEach' in 'execute':586, KotlinSymbolProcessing (com.google.devtools.ksp.impl)
execute$stub_for_inlining$32:1863, KotlinSymbolProcessing (com.google.devtools.ksp.impl)
forEach:1863, KotlinSymbolProcessing (com.google.devtools.ksp.impl)
execute:586, KotlinSymbolProcessing (com.google.devtools.ksp.impl)
...

whereas the corresponding element of createNative was from the first round:

lambda 'with' in 'processKmpComponentCreate':29, ProcessKmpComponentCreateKt (me.tatarka.inject.compiler.ksp)
processKmpComponentCreate:16, ProcessKmpComponentCreateKt (me.tatarka.inject.compiler.ksp)
process$lambda$3:69, InjectProcessor (me.tatarka.inject.compiler.ksp)
invoke:-1, InjectProcessor$$Lambda/0x00007f43f947f670 (me.tatarka.inject.compiler.ksp)
calcNext:171, FilteringSequence$iterator$1 (kotlin.sequences)
hasNext:194, FilteringSequence$iterator$1 (kotlin.sequences)
toList:813, SequencesKt___SequencesKt (kotlin.sequences)
process:70, InjectProcessor (me.tatarka.inject.compiler.ksp)
invoke:552, KotlinSymbolProcessing$execute$1$1 (com.google.devtools.ksp.impl)
invoke:550, KotlinSymbolProcessing$execute$1$1 (com.google.devtools.ksp.impl)
closeFilesOnException:409, IncrementalContextBase (ksp.com.google.devtools.ksp.common)
lambda 'forEach' in 'execute':550, KotlinSymbolProcessing (com.google.devtools.ksp.impl)
forEach:1863, KotlinSymbolProcessing (com.google.devtools.ksp.impl)
execute:549, KotlinSymbolProcessing (com.google.devtools.ksp.impl)
...

Please avoid caching and using the elements across rounds.

@evant
Copy link
Owner

evant commented Nov 19, 2024

@eygraber ^ probably due to

private val kmpComponentCreateFunctionsByComponentType = mutableMapOf<AstClass, MutableList<AstFunction>>()
we should change it to only store the KSName like we do for other deferred symbols.

@eygraber
Copy link
Contributor Author

Yup, I started working on that. Not sure if I'm doing something wrong because I'm getting other errors but at least the KtInvalidLifetimeOwnerAccessException seems to have stopped 😄

@eygraber
Copy link
Contributor Author

@evant I believe the latest commit fixes the KtInvalidLifetimeOwnerAccessException issue.

There is still an issue with typealiases (probably related to google/ksp#1921).

Most of the RoundsTests are failing because of a change in dev.zacsweers.kctfork:ksp:0.6.0 where the messages are split between a messages: String property, and a diagnosticMessages: List<DiagnosticMessage>. diagnosticMessages is used in messagesWithSeverity (which is what we call to get the error output), however the errors that we are looking for only appear in messages.

@@ -1495,7 +1495,7 @@ class FailureTest {
""".trimIndent()
).compile()
}.output().all {
contains("e: [ksp] Cannot find an @Inject constructor or provider for: Foo")
contains("Cannot find an @Inject constructor or provider for: Foo")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@evant The e: [ksp] prefix wasn't present anymore; it was a toString representation of DiagnosticMessage

@eygraber eygraber marked this pull request as ready for review November 21, 2024 05:34
@eygraber eygraber requested a review from evant November 21, 2024 05:34
@vRallev
Copy link
Contributor

vRallev commented Nov 21, 2024

The workaround for #447 isn't user friendly.

@eygraber
Copy link
Contributor Author

Agreed, I'm updating the issue you filed on KSP.

@evant
Copy link
Owner

evant commented Nov 22, 2024

Maybe circleci caches need to be cleaned?

you can invalidate the cache by changing the cache_key at

cache_key: linux
&
cache_key: macos

btw thanks @eygraber for keeping up with this

@eygraber
Copy link
Contributor Author

It looks like this happens when running tests after assemble. I'll dig in further.

Comment on lines 20 to 28
data class KmpComponentCreateFunctionInfo(
val name: String,
val annotations: List<AnnotationSpec>,
val visibility: KModifier,
val receiverParameterType: TypeName?,
val parameters: List<Pair<String, TypeName>>,
val parametersTemplate: String,
val parameterNames: List<String>,
)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying everything out of the ast to preserve it between rounds seems really not ideal to me, and I worry about how it'd interact with symbols that are only resolvable in future rounds. Not going to block the pr on this since I haven't looked into enough to come up with a better way, but I'll try to investigate that when I get a chance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. The fastest way I could think of to do this was to defer all functions found with resolver.getSymbolsWithAnnotation and then call resolver.getSymbolsWithAnnotation in finish and generate everything there.

Not sure if that's frowned upon in KSP, so I'm also working on a solution that generates a file per function so that nothing needs to be cached. The difficulty there is naming the generated file because it's easy to end up with multiple files named the same.

@@ -24,36 +43,37 @@ class KmpComponentCreateGenerator(
addFunction(
FunSpec
.builder(kmpComponentCreateFunction.name)
.addOriginatingElement(kmpComponentCreateFunction)
// .addOriginatingElement(kmpComponentCreateFunction)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mean to leave commented out?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mistake 😅

fun AstType.isPair(): Boolean = packageName == "kotlin" && simpleName == "Pair"
fun AstType.isFunctionOrTypeAliasOfFunction() = isFunction() || isTypeAlias() && resolvedType().isFunction()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does resolvedType().isFunction() need to be recursive to handle a type alias to a type alias?

@eygraber
Copy link
Contributor Author

CI is blocked by google/ksp#2230. Alternatively we can update the script to run clean in between assemble and check, and revert that once the KSP issue is resolved.

Outstanding questions are:

  1. Is it OK if kotlin-inject doesn't work with KSP1 anymore?
  2. Is it OK to defer all KmpComponentCreate functions to the last round, or is a different solution needed?

@evant
Copy link
Owner

evant commented Nov 22, 2024

Is it OK if kotlin-inject doesn't work with KSP1 anymore?

I've seen enough issues that I think it would be good to have overlap supporting both for a bit. What breaks here with ksp1? I don't know if it'll easy to detect which one you are using but we could add an additional option to enable it for now

@eygraber
Copy link
Contributor Author

eygraber commented Nov 22, 2024

Actually it looks like it does might work with KSP1. The integration tests are all passing, but about half of the unit tests fail. Maybe I'm not configuring kotlin-compile-testing correctly, or maybe the tests are actually failing, it's hard to say for sure.

@eygraber
Copy link
Contributor Author

Got some inspiration from https://github.com/amzn/kotlin-inject-anvil/blob/main/compiler-utils/src/testFixtures/kotlin/software/amazon/lastmile/kotlin/inject/anvil/Compilation.kt and figured it out 😄

The only unit tests failing now are the ones that check for a specific error format that changed from KSP1 to KSP2, so I'm thinking that it is fine.

@eygraber
Copy link
Contributor Author

Updated the unit and integration tests to run with both KSP1 and KSP2.

@evant
Copy link
Owner

evant commented Nov 23, 2024

CI is blocked by google/ksp#2230

looks like it's already fixed! I'm ok with throwing a clean on ci for now until that's released though

@eygraber
Copy link
Contributor Author

Updated, hopefully that's all that's needed.

@sahilbajaj
Copy link

@eygraber @evant Eagerly awaiting action.

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

Successfully merging this pull request may close these issues.

5 participants