evant / kotlin-inject

Dependency injection lib for kotlin
Apache License 2.0
1.14k stars 51 forks source link

Generated code tries to use property or variable that isn't there #403

Closed sergeshustoff closed 1 week ago

sergeshustoff commented 1 week ago

I can't seem to find a small reproducible case for that, but it reproduces in a big modular project with bloated component. For some reason generated code tries to use either property or variable that wasn't created. Looks like it happens somewhere deep inside Lazy dependency construction block with at least one local var already present. Probably it happens when cycle is broken by Lazy

Also in this case produced component implementation (the one that doesn't compile) is huge - more than 40000loc. With cycle broken in a different way (manually calling component when upstream dependency is needed for downstream class) generated code is much shorter 2500loc

kotlin-inject version 0.7.1

sergeshustoff commented 1 week ago

Finnaly found the case to reproduce it. It's complucated but the end result is incorrect generated code that expects variable or property that isn't there

interface Lvl1
interface Lvl2
interface Lvl3
interface Lvl4

@Inject
class Lvl1Impl(val dep: Lvl2): Lvl1
@Inject
class Lvl2Impl(val dep: Lvl3): Lvl2
@Inject
class Lvl3Impl(val dep: Lazy<Lvl4>): Lvl3
@Inject
class Lvl4Impl(val dep1: Dep1, val dep2: Dep2): Lvl4

@Inject
class Dep1(val dep: Dep3)
@Inject
class Dep2(val dep: Dep3, val lvl0: Lvl1)
@Inject
class Dep3(val lvl1: Lvl1, val lvl2: Lvl2Impl, val lvl3: Lvl3)

@Component
abstract class ComplexCycleComponent {
    abstract val lvl1: Lvl1

    @Provides
    fun lvl1(impl: Lvl1Impl): Lvl1 = impl
    @Provides
    fun lvl2(impl: Lvl2Impl): Lvl2 = impl
    @Provides
    fun lvl3(impl: Lvl3Impl): Lvl3 = impl
    @Provides
    fun lvl4(impl: Lvl4Impl): Lvl4 = impl
}

generated code:

public class InjectComplexCycleComponent() : ComplexCycleComponent() {
  override val lvl1: Lvl1
    get() = run<Lvl1> {
      lateinit var lvl1: Lvl1
      lvl1(
        impl = Lvl1Impl(
          dep = lvl2(
            impl = Lvl2Impl(
              dep = lvl3(
                impl = Lvl3Impl(
                  dep = lazy {
                    lvl4(
                      impl = Lvl4Impl(
                        dep1 = Dep1(
                          dep = Dep3(
                            lvl1 = lvl1,
                            lvl2 = lvl2Impl,
                            lvl3 = lvl3
                          )
                        ),
                        dep2 = Dep2(
                          dep = Dep3(
                            lvl1 = lvl1,
                            lvl2 = lvl2Impl,
                            lvl3 = lvl3
                          ),
                          lvl0 = lvl1
                        )
                      )
                    )
                  }
                )
              )
            )
          )
        )
      ).also {
        lvl1 = it
      }
    }
}

error is in Dep3 construction, both lvl2Impl and lvl3 don't exist