Repository: evant/kotlin-inject (kotlin)

Issue:
Conflicting declarations for scoped `@Provides` functions with parameterized return type
If I have:

```
import me.tatarka.inject.annotations.Inject
import me.tatarka.inject.annotations.Provides
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Scope

@Scope annotation class MyScope

@MyScope @Component abstract class MyComponent {
  abstract val foo: Foo
 
  @MyScope @Provides protected fun t1() = T<Int>()
 
  @MyScope @Provides protected fun t2() = T<String>()
}

class T<T>

@MyScope @Inject class Foo(
  private val t1: T<Int>,
  private val t2: T<String>,
  private val bar: Bar
)

@MyScope @Inject class Bar(
  private val t1: T<Int>,
  private val t2: T<String>
)
```

then the generated properties for both are named `_t`.

Pull request:
- If multiple scoped @Provides functions have the same return type with different type args, the generated properties will have the same name
  - This causes conflicting declaration errors while compiling
  - To fix that, the type args are included in property name generation

Fixes #174

Patch:
diff --git a/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt b/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
index 63d78d05..e97058b1 100644
--- a/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
+++ b/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/InjectGenerator.kt
@@ -221,7 +221,19 @@ fun AstClass.toInjectName(): String =
 
 fun AstType.toVariableName(): String =
     simpleName.split(".")
-        .joinToString("_") { it.decapitalize(Locale.US) }
+        .joinToString("_") { it.decapitalize(Locale.US) } +
+        joinArgumentTypeNames()
+
+private fun AstType.joinArgumentTypeNames(): String = when {
+  arguments.isEmpty() -> ""
+  else -> arguments.joinToString(separator = "") {
+    it
+      .simpleName
+      .split(".")
+      .joinToString("_") +
+      it.joinArgumentTypeNames()
+  }
+}
 
 private fun dumpGraph(astClass: AstClass, entries: List<TypeResult.Provider>): String {
     val out = StringBuilder(astClass.name).append("\n")


Test patch:
diff --git a/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/ScopeTest.kt b/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/ScopeTest.kt
index 73b45beb..db2fb0e6 100644
--- a/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/ScopeTest.kt
+++ b/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/ScopeTest.kt
@@ -149,6 +149,37 @@ abstract class NestedExternalScopedComponent(@Component val parent: ExternalChil
     abstract val foo: IExternalFoo
 }
 
+class Parameterized<E, S>
+
+@CustomScope
+@Inject
+class ParameterizedFoo(
+  private val p1: Parameterized<List<Int>, List<String>>,
+  private val p2: Parameterized<List<String>, List<String>>,
+  private val bar: ParameterizedBar
+)
+
+@CustomScope
+@Inject
+class ParameterizedBar(
+  private val p1: Parameterized<List<Int>, List<String>>,
+  private val p2: Parameterized<List<String>, List<String>>
+)
+
+@CustomScope
+@Component
+abstract class MultipleSameTypedScopedProvidesComponent {
+  abstract val foo: ParameterizedFoo
+
+  @CustomScope
+  @Provides
+  protected fun parameterized1() = Parameterized<List<Int>, List<String>>()
+
+  @CustomScope
+  @Provides
+  protected fun parameterized2() = Parameterized<List<String>, List<String>>()
+}
+
 class ScopeTest {
     @BeforeTest
     fun setup() {
@@ -251,4 +282,11 @@ class ScopeTest {
 
         assertThat(component.foo).isSameAs(component.foo)
     }
-}
\ No newline at end of file
+
+  @Test
+  fun generates_a_component_when_multiple_scoped_provides_funs_have_the_same_return_type_with_different_type_args() {
+    val component = MultipleSameTypedScopedProvidesComponent::class.create()
+
+    assertThat(component.foo).isSameAs(component.foo)
+ }
+}