evant / kotlin-inject

Dependency injection lib for kotlin
Apache License 2.0
1.29k stars 60 forks source link

Annotation targets for qualifier annotations break kotlin-inject #447

Open vRallev opened 1 month ago

vRallev commented 1 month ago

The following code compiles fine:

@Qualifier
annotation class QualifiedString

@Component
abstract class MainComponent {

    @Provides
    @QualifiedString
    fun provideString(): String = ""

    @QualifiedString
    abstract val otherString: String
}

But if I add a target to the qualifier annotation, even with an exhaustive list, the code fails to compile with a confusing error.

@Qualifier
@Target(
    CLASS,
    ANNOTATION_CLASS,
    TYPE_PARAMETER,
    PROPERTY,
    FIELD,
    LOCAL_VARIABLE,
    VALUE_PARAMETER,
    CONSTRUCTOR,
    FUNCTION,
    PROPERTY_GETTER,
    PROPERTY_SETTER,
    TYPE,
    FILE,
    TYPEALIAS,
)
annotation class QualifiedString

Error:

e: [ksp] Cannot find an @Inject constructor or provider for: String
/kotlin-inject-anvil/sample/lib/src/androidMain/kotlin/software/amazon/lastmile/kotlin/inject/anvil/sample/AndroidApplicationIdProvider.kt:84: otherString: String
vRallev commented 1 month ago

Oh, screw this, it's related to KSP2. With KSP1 ksp.useKSP2=false it works fine.

evant commented 1 month ago

I wonder if that makes them no longer compare equal, may be related to https://github.com/google/ksp/issues/2091

vRallev commented 1 month ago

Happy to forward this as new issue to them, but could you please point me to where qualifier annotations are resolved and how you compare them?

evant commented 1 month ago

sure, comparisons are done for looking for an equal TypeKey which in turn uses the equals implementation for annotations here

evant commented 1 month ago

Also note I put 'blocked by 3rd-party' on this but if there's a reasonable adjustment to our implementation that works I'm happy to accept it

vRallev commented 2 weeks ago

This almost slipped through the cracks: https://github.com/google/ksp/issues/2196

eygraber commented 4 days ago

I can get that test case to succeed with KSP2 by doing abstract val otherString: @QualifiedString String.

@Qualifier
@Target(
    CLASS,
    ANNOTATION_CLASS,
    TYPE_PARAMETER,
    PROPERTY,
    FIELD,
    LOCAL_VARIABLE,
    VALUE_PARAMETER,
    CONSTRUCTOR,
    FUNCTION,
    PROPERTY_GETTER,
    PROPERTY_SETTER,
    TYPE,
    FILE,
    TYPEALIAS,
)
annotation class QualifiedString

@Component
abstract class MainComponent {

    @Provides
    @QualifiedString
    fun provideString(): String = ""

    abstract val otherString: @QualifiedString String
}
eygraber commented 4 days ago

This looks related to something I saw in one of my projects using KSP1:

@Qualifier
@Target(
  PROPERTY,
  PROPERTY_GETTER,
  FUNCTION,
  VALUE_PARAMETER,
  TYPE,
)
annotation class ActivityContext

class Context

@Component
abstract class MainComponent(
  @get:Provides val context: @ActivityContext Context
) {
    @ActivityContext
    abstract val c: Context
}

If I do @get:Provides @ActivityContext val context: Context it doesn't work.

Ppeepost4489 commented 23 hours ago

The following code compiles fine:

@Qualifier
annotation class QualifiedString

@Component
abstract class MainComponent {

    @Provides
    @QualifiedString
    fun provideString(): String = ""

    @QualifiedString
    abstract val otherString: String
}

But if I add a target to the qualifier annotation, even with an exhaustive list, the code fails to compile with a confusing error.

@Qualifier
@Target(
    CLASS,
    ANNOTATION_CLASS,
    TYPE_PARAMETER,
    PROPERTY,
    FIELD,
    LOCAL_VARIABLE,
    VALUE_PARAMETER,
    CONSTRUCTOR,
    FUNCTION,
    PROPERTY_GETTER,
    PROPERTY_SETTER,
    TYPE,
    FILE,
    TYPEALIAS,
)
annotation class QualifiedString

Error:

e: [ksp] Cannot find an @Inject constructor or provider for: String
/kotlin-inject-anvil/sample/lib/src/androidMain/kotlin/software/amazon/lastmile/kotlin/inject/anvil/sample/AndroidApplicationIdProvider.kt:84: otherString: String