kotlin-inject icon indicating copy to clipboard operation
kotlin-inject copied to clipboard

Kotlin Delegation Support?

Open jamesalee213 opened this issue 1 year ago • 4 comments
trafficstars

Hi. does kotlin-inject not support kotlin delegation? If it doesn't, will the support for kotlin delegation for creating component ever be added?

I'm trying to use component inheritance (link) with kotlin delegation. Here's my setup:

@CustomScope
interface FooComponent {
  @CustomScope
  @Provides
  fun foo(): Foo
}

// the delegate gets created somewhere else in the code and is an instance of `FooComponent`, but it not kotlin-inject component.
@Component
abstract RealFooComponent(delegate: FooComponent) : FooComponent by delegate

but when I try to build, I get this error:

e: [ksp] @Provides method must have a concrete implementation
e: Error occurred in KSP, check log for detail

jamesalee213 avatar Mar 12 '24 22:03 jamesalee213

interesting, seems like ksp doesn't emit the synthentic methods generated for delegation, I wonder if there's another way to detect it.

evant avatar Mar 12 '24 23:03 evant

Unfortunately it looks like KSP won't report on delegation (because it's technically an expression), but working with James we came up with this heuristic which generally works:

// Defined in AstMember:
override fun isDelegated(enclosingClass: AstClass): Boolean {
    return declaration.parentDeclaration != (enclosingClass as KSAstClass).declaration
}

// TypeCollector:
if (isComponent && abstract && !method.isDelegated(astClass)) {
    provider.error("@Provides method must have a concrete implementation", method)
    continue
}

If you manually override the interface method in your component, the parent declaration will be the component (enclosing) class. (i.e. the declarations match and it is definitely not delegated).

If the method is delegated, the parent declaration will be the interface instead of the component class. (i.e. the declarations are not the same, and it is probably not delegated).

If you don't delegate the method and don't implement the method in your component class, then this will pass kotlin-inject because it will think that it is "delegated" however you get a compiler error after the fact because there the method was never implemented.

I don't know if it's worth the trade-off of introducing a more cryptic error for something that kotlin-inject tries to explicitly check for... but that's our only idea so far 🤷

dellisd avatar Mar 13 '24 16:03 dellisd

I think I'm mistaken about interface delegation being an "expression". That would apply to checking if a simple property is delegated, but checking if an abstract property or function is implemented via delegation is definitely compile-time information.

Either way, KSP doesn't support this at the moment, but maybe it's something that could be requested.

dellisd avatar Mar 13 '24 17:03 dellisd

Thanks for looking into it! Yeah I think opening an issue on the ksp side to get this information would be the way to go.

evant avatar Mar 13 '24 20:03 evant