Repository: evant/kotlin-inject (kotlin)

Issue:
Unclear error message for scoped provider
I have a component similar to this:
```
@Scope
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER)
annotation class AppScope

@Component
@AppScope
abstract class AndroidAppComponent
```

I meant to add a new provider from a feature module like this:
```
typealias AppScopeCoroutineScope = CoroutineScope

interface AppScopeCoroutineScopeComponent {
    @AppScope
    @Provides
    fun provideCoroutineScope(dispatcher: IoCoroutineDispatcher): AppScopeCoroutineScope {
        return CoroutineScopeScoped(...)
    }
}

@Component
@AppScope
abstract class AndroidAppComponent : AppScopeCoroutineScopeComponent
```

This fails with following error:
```
e: [ksp] @Provides with scope: com.my.package.di.AppScope cannot be provided in an unscoped component
```
This message is confusing, because it's not clear which the unscoped component is. I only found out by trial and error that this provider method is triggering the error. Removing `@AppScope` from the provider method resolves the error, but it would result in bugs and is required to be a singleton. Changing it to the following will work:
```
@AppScope
interface AppScopeCoroutineScopeComponent {
    @AppScope
    @Provides
    fun provideCoroutineScope(dispatcher: IoCoroutineDispatcher): AppScopeCoroutineScope {
        return CoroutineScopeScoped(...)
    }
}
```

However, this creates a new error:
```
e: [ksp] Cannot apply scope: com.my.package.di.AppScope
e: [ksp] /path/AndroidAppComponent.kt:11: as scope: com.my.package.di.AppScope is already applied
```

This error is surprising, because the scope is not applied twice. I needed to change my final component to this to resolve the problem:
```
@Component
abstract class AndroidAppComponent : AppScopeCoroutineScopeComponent
```
This code finally runs, but I'm afraid that it will start failing again with another interface being added. 

Is this an error on my end? How do I avoid this?

Pull request:
Fixes #320

Patch:
diff --git a/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt b/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
index b6da3254..43bc3349 100644
--- a/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
+++ b/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeCollector.kt
@@ -262,10 +262,10 @@ class TypeCollector(private val provider: AstProvider, private val options: Opti
             for (parentClass in astClass.inheritanceChain()) {
                 val parentScope = parentClass.scopeType(options)
                 if (parentScope != null) {
-                    if (scopeClass == null) {
+                    if (elementScope == null) {
                         scopeClass = parentClass
                         elementScope = parentScope
-                    } else {
+                    } else if (elementScope != parentScope) {
                         provider.error("Cannot apply scope: $parentScope", parentClass)
                         provider.error(
                             "as scope: $elementScope is already applied",


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 bd31207a..f994aa71 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
@@ -199,6 +199,18 @@ abstract class ParentChildScopesChildComponent(@Component val parent: ParentChil
     fun barImpl(foo: IFoo): BarImpl = BarImpl(foo)
 }
 
+@CustomScope
+interface DuplicateScopeInterface {
+    val iFoo: IFoo
+        @Provides @CustomScope get() = Foo()
+}
+
+@CustomScope
+@Component
+abstract class DuplicateScopeComponent : DuplicateScopeInterface {
+    abstract val foo: IFoo
+}
+
 class ScopeTest {
     @BeforeTest
     fun setup() {
@@ -315,4 +327,11 @@ class ScopeTest {
 
         assertThat(component.bar).isNotNull()
     }
+
+    @Test
+    fun generates_a_component_that_applies_the_same_scope_to_itself_and_its_parent_interface() {
+        val component = DuplicateScopeComponent::class.create()
+
+        assertThat(component.foo).isNotNull()
+    }
 }