Repository: evant/kotlin-inject (kotlin)

Issue:
NoSuchElementException when tracing a missing dependency and the root is a type parameter
```kotlin
class Foo
                
@Inject class Bar(val foo: Foo)
                
interface DestinationComponent<C> {
  val c: C
}
                
@Inject class CType(val bar: Bar)
                
@Component
abstract class FooBarComponent : DestinationComponent<CType>
```

```
[ksp] java.util.NoSuchElementException: No TypeParameter found for index C
	at com.squareup.kotlinpoet.ksp.TypeParameterResolver$Companion$EMPTY$1.get(TypeParameterResolver.kt:45)
	at com.squareup.kotlinpoet.ksp.KsTypesKt.toTypeName(KsTypes.kt:71)
	at com.squareup.kotlinpoet.ksp.KsTypesKt.toTypeName(KsTypes.kt:194)
	at com.squareup.kotlinpoet.ksp.KsTypesKt.toTypeName$default(KsTypes.kt:182)
	at me.tatarka.kotlin.ast.KSAstType.toString(KSAst.kt:535)
	at java.base/java.lang.String.valueOf(String.java:4507)
	at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
	at me.tatarka.kotlin.ast.AstProperty.toString(Ast.kt:184)
	at me.tatarka.kotlin.ast.KSAstProvider.toTrace(KSAst.kt:90)
	at me.tatarka.inject.compiler.CycleDetector.trace$lambda$4(CycleDetector.kt:69)
	at kotlin.text.StringsKt__AppendableKt.appendElement(Appendable.kt:84)
	at kotlin.collections.CollectionsKt___CollectionsKt.joinTo(_Collections.kt:3493)
	at kotlin.collections.CollectionsKt___CollectionsKt.joinToString(_Collections.kt:3510)
	at kotlin.collections.CollectionsKt___CollectionsKt.joinToString$default(_Collections.kt:3509)
	at me.tatarka.inject.compiler.CycleDetector.trace(CycleDetector.kt:69)
	at me.tatarka.inject.compiler.TypeResultResolver.trace(TypeResultResolver.kt:586)
	at me.tatarka.inject.compiler.TypeResultResolver.cannotFind(TypeResultResolver.kt:588)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParamsLegacy(TypeResultResolver.kt:177)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParams(TypeResultResolver.kt:71)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor$lambda$23(TypeResultResolver.kt:477)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection$lambda$30(TypeResultResolver.kt:564)
	at me.tatarka.inject.compiler.CycleDetector.check(CycleDetector.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection(TypeResultResolver.kt:562)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor(TypeResultResolver.kt:472)
	at me.tatarka.inject.compiler.TypeResultResolver.constructor(TypeResultResolver.kt:393)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:249)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolve(TypeResultResolver.kt:40)
	at me.tatarka.inject.compiler.TypeResultResolver.Scoped(TypeResultResolver.kt:463)
	at me.tatarka.inject.compiler.TypeResultResolver.constructor(TypeResultResolver.kt:385)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:249)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolve(TypeResultResolver.kt:40)
	at me.tatarka.inject.compiler.TypeResultResolver.Provides$lambda$21(TypeResultResolver.kt:444)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection$lambda$30(TypeResultResolver.kt:564)
	at me.tatarka.inject.compiler.CycleDetector.check(CycleDetector.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection(TypeResultResolver.kt:562)
	at me.tatarka.inject.compiler.TypeResultResolver.Provides(TypeResultResolver.kt:437)
	at me.tatarka.inject.compiler.TypeResultResolver.method(TypeResultResolver.kt:269)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:224)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParamsNew(TypeResultResolver.kt:114)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParams(TypeResultResolver.kt:69)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor$lambda$23(TypeResultResolver.kt:477)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection$lambda$30(TypeResultResolver.kt:564)
	at me.tatarka.inject.compiler.CycleDetector.check(CycleDetector.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection(TypeResultResolver.kt:562)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor(TypeResultResolver.kt:472)
	at me.tatarka.inject.compiler.TypeResultResolver.constructor(TypeResultResolver.kt:393)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:249)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.functionType(TypeResultResolver.kt:358)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:236)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParamsLegacy(TypeResultResolver.kt:173)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParams(TypeResultResolver.kt:71)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor$lambda$23(TypeResultResolver.kt:477)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection$lambda$30(TypeResultResolver.kt:564)
	at me.tatarka.inject.compiler.CycleDetector.check(CycleDetector.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection(TypeResultResolver.kt:562)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor(TypeResultResolver.kt:472)
	at me.tatarka.inject.compiler.TypeResultResolver.constructor(TypeResultResolver.kt:393)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:249)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolve(TypeResultResolver.kt:40)
	at me.tatarka.inject.compiler.TypeResultResolver.Scoped(TypeResultResolver.kt:463)
	at me.tatarka.inject.compiler.TypeResultResolver.constructor(TypeResultResolver.kt:385)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:249)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParamsLegacy(TypeResultResolver.kt:173)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveParams(TypeResultResolver.kt:71)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor$lambda$23(TypeResultResolver.kt:477)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection$lambda$30(TypeResultResolver.kt:564)
	at me.tatarka.inject.compiler.CycleDetector.check(CycleDetector.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection(TypeResultResolver.kt:562)
	at me.tatarka.inject.compiler.TypeResultResolver.Constructor(TypeResultResolver.kt:472)
	at me.tatarka.inject.compiler.TypeResultResolver.constructor(TypeResultResolver.kt:393)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:249)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolve(TypeResultResolver.kt:40)
	at me.tatarka.inject.compiler.TypeResultResolver.Scoped(TypeResultResolver.kt:463)
	at me.tatarka.inject.compiler.TypeResultResolver.constructor(TypeResultResolver.kt:385)
	at me.tatarka.inject.compiler.TypeResultResolver.findType(TypeResultResolver.kt:249)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveOrNull(TypeResultResolver.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.resolve(TypeResultResolver.kt:40)
	at me.tatarka.inject.compiler.TypeResultResolver.Provider$lambda$18(TypeResultResolver.kt:412)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection$lambda$30(TypeResultResolver.kt:564)
	at me.tatarka.inject.compiler.CycleDetector.check(CycleDetector.kt:50)
	at me.tatarka.inject.compiler.TypeResultResolver.withCycleDetection(TypeResultResolver.kt:562)
	at me.tatarka.inject.compiler.TypeResultResolver.Provider(TypeResultResolver.kt:411)
	at me.tatarka.inject.compiler.TypeResultResolver.resolveAll(TypeResultResolver.kt:31)
	at me.tatarka.inject.compiler.InjectGenerator.generateInjectComponent(InjectGenerator.kt:153)
	at me.tatarka.inject.compiler.InjectGenerator.generate(InjectGenerator.kt:68)
	at me.tatarka.inject.compiler.ksp.ProcessInjectKt.process(ProcessInject.kt:78)
	at me.tatarka.inject.compiler.ksp.ProcessInjectKt.processInject(ProcessInject.kt:28)
	at me.tatarka.inject.compiler.ksp.ProcessInjectKt.processInject$default(ProcessInject.kt:19)
	at me.tatarka.inject.compiler.ksp.InjectProcessor.process$lambda$1(InjectProcessor.kt:55)
	at kotlin.sequences.FilteringSequence$iterator$1.calcNext(Sequences.kt:171)
	at kotlin.sequences.FilteringSequence$iterator$1.hasNext(Sequences.kt:194)
	at kotlin.sequences.SequencesKt___SequencesKt.toList(_Sequences.kt:813)
	at me.tatarka.inject.compiler.ksp.InjectProcessor.process(InjectProcessor.kt:57)
```

Pull request:
Fixes #426 

I'm not sure if this is the best solution, or why the type parameter is included in the CycleDetector. An alternate option is to catch this in the `CycleDetector` and just filter it out. Another option is to catch any exceptions from `toTypeName()` and use `typeRef.toString()` instead.

Patch:
diff --git a/ast/ksp/src/main/kotlin/me/tatarka/kotlin/ast/KSAst.kt b/ast/ksp/src/main/kotlin/me/tatarka/kotlin/ast/KSAst.kt
index 6ae4086f..d3885ad0 100644
--- a/ast/ksp/src/main/kotlin/me/tatarka/kotlin/ast/KSAst.kt
+++ b/ast/ksp/src/main/kotlin/me/tatarka/kotlin/ast/KSAst.kt
@@ -531,7 +531,11 @@ private class KSAstType private constructor(
         return if (type.isError) {
             typeRef.toString()
         } else {
-            typeRef.toTypeName().toString()
+            try {
+                typeRef.toTypeName().toString()
+            } catch (_: Throwable) {
+                typeRef.toString()
+            }
         }.shortenPackage()
     }
 


Test patch:
diff --git a/kotlin-inject-compiler/test/src/test/kotlin/me/tatarka/inject/test/FailureTest.kt b/kotlin-inject-compiler/test/src/test/kotlin/me/tatarka/inject/test/FailureTest.kt
index 87cd2336..faab527d 100644
--- a/kotlin-inject-compiler/test/src/test/kotlin/me/tatarka/inject/test/FailureTest.kt
+++ b/kotlin-inject-compiler/test/src/test/kotlin/me/tatarka/inject/test/FailureTest.kt
@@ -1273,4 +1273,37 @@ class FailureTest {
             contains("Qualifier: @MyQualifier can only be applied to the outer type")
         }
     }
+
+    @ParameterizedTest
+    @EnumSource(Target::class)
+    fun fails_if_cannot_find_inject_or_provider_and_root_is_a_type_parameter(target: Target) {
+        val projectCompiler = ProjectCompiler(target, workingDir)
+
+        assertFailure {
+            projectCompiler.source(
+                "MyComponent.kt",
+                """
+                import me.tatarka.inject.annotations.Component
+                import me.tatarka.inject.annotations.Inject
+                import me.tatarka.inject.annotations.Provides
+
+                class Foo
+
+                @Inject class Bar(val foo: Foo)
+
+                interface DestinationComponent<C> {
+                  val c: C
+                  val cProvider: () -> C
+                }
+
+                @Inject class CType(val bar: Bar)
+
+                @Component
+                abstract class FooBarComponent : DestinationComponent<CType>
+                """.trimIndent()
+            ).compile()
+        }.output().all {
+            contains("e: [ksp] Cannot find an @Inject constructor or provider for: Foo")
+        }
+    }
 }