Repository: evant/kotlin-inject (kotlin)

Issue:
Parameters with default values
```kotlin
class Foo(
  val generator: () -> String = { "bar" }
)
```

For constructors (or functions) with parameters that have default values, can `kotlin-inject` ignore injecting them? I have a lambda parameter with a default value that I'm only overriding in tests so I don't wanna add a provider for it to my component.

Pull request:
Fixes #161

Patch:
diff --git a/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeResultResolver.kt b/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeResultResolver.kt
index 83c763fe..a9e8e650 100644
--- a/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeResultResolver.kt
+++ b/kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeResultResolver.kt
@@ -55,8 +55,8 @@ class TypeResultResolver(private val provider: AstProvider, private val options:
             if (arg != null) {
                 val (type, name) = arg
                 if (type.isAssignableFrom(key.type)) {
-                  paramsWithName[param.name] = TypeResultRef(key, TypeResult.Arg(name))
-                  return@forEachIndexed
+                    paramsWithName[param.name] = TypeResultRef(key, TypeResult.Arg(name))
+                    return@forEachIndexed
                 }
             }
             val result = resolveOrNull(context, key)
@@ -206,13 +206,11 @@ class TypeResultResolver(private val provider: AstProvider, private val options:
         context: Context,
         key: TypeKey,
         args: List<AstType>
-    ): TypeResult {
+    ): TypeResult? {
         cycleDetector.delayedConstruction()
         val namedArgs = args.mapIndexed { i, arg -> arg to "arg$i" }
-        return TypeResult.Function(
-            args = namedArgs.map { it.second },
-            result = resolve(context.withArgs(namedArgs), key)
-        )
+        val result = resolveOrNull(context.withArgs(namedArgs), key) ?: return null
+        return TypeResult.Function(args = namedArgs.map { it.second }, result = result)
     }
 
     private fun NamedFunction(
@@ -234,9 +232,10 @@ class TypeResultResolver(private val provider: AstProvider, private val options:
         )
     }
 
-    private fun Lazy(context: Context, key: TypeKey): TypeResult {
+    private fun Lazy(context: Context, key: TypeKey): TypeResult? {
         cycleDetector.delayedConstruction()
-        return maybeLateInit(key, TypeResult.Lazy(resolve(context, key)))
+        val result = resolveOrNull(context, key) ?: return null
+        return maybeLateInit(key, TypeResult.Lazy(result))
     }
 
     private fun LateInit(


Test patch:
diff --git a/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/DefaultParamTest.kt b/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/DefaultParamTest.kt
index 97d9f10d..674390b5 100644
--- a/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/DefaultParamTest.kt
+++ b/integration-tests/common/src/test/kotlin/me/tatarka/inject/test/DefaultParamTest.kt
@@ -8,17 +8,27 @@ import me.tatarka.inject.annotations.Provides
 import kotlin.test.Test
 
 @Inject
-class FooWithDefault(override val name: String = "default") : IFooWithDefault
+class FooWithDefault(
+    override val name: String = "default",
+    override val fn: () -> String = { "default" },
+    override val lazy: Lazy<String> = lazy { "default" },
+) : IFooWithDefault
 
 interface IFooWithDefault {
     val name: String
+    val fn: () -> String
+    val lazy: Lazy<String>
 }
 
 typealias fooWithDefaultFun = () -> IFooWithDefault
 
 @Inject
-fun fooWithDefaultFun(name: String = "default"): IFooWithDefault {
-    return FooWithDefault(name)
+fun fooWithDefaultFun(
+    name: String = "default",
+    fn: () -> String = { "default" },
+    lazy: Lazy<String> = lazy { "default" },
+): IFooWithDefault {
+    return FooWithDefault(name, fn, lazy)
 }
 
 @Component
@@ -28,7 +38,11 @@ abstract class UseDefaultComponent {
     abstract val fooFun: fooWithDefaultFun
 
     @Provides
-    fun iFoo(name: String = "default"): IFooWithDefault = FooWithDefault(name)
+    fun iFoo(
+        name: String = "default",
+        fn: () -> String = { "default" },
+        lazy: Lazy<String> = lazy { "default" },
+    ): IFooWithDefault = FooWithDefault(name, fn, lazy)
 }
 
 @Component
@@ -41,7 +55,11 @@ abstract class OverrideDefaultComponent {
         @Provides get() = "override"
 
     @Provides
-    fun iFoo(name: String = "default"): IFooWithDefault = FooWithDefault(name)
+    fun iFoo(
+        name: String = "default",
+        fn: () -> String = { "default" },
+        lazy: Lazy<String> = lazy { "default" },
+    ): IFooWithDefault = FooWithDefault(name, fn, lazy)
 }
 
 class DefaultParamTest {
@@ -50,8 +68,14 @@ class DefaultParamTest {
         val component = UseDefaultComponent::class.create()
 
         assertThat(component.foo.name).isEqualTo("default")
+        assertThat(component.foo.fn()).isEqualTo("default")
+        assertThat(component.foo.lazy.value).isEqualTo("default")
         assertThat(component.iFoo.name).isEqualTo("default")
+        assertThat(component.iFoo.fn()).isEqualTo("default")
+        assertThat(component.iFoo.lazy.value).isEqualTo("default")
         assertThat(component.fooFun().name).isEqualTo("default")
+        assertThat(component.fooFun().fn()).isEqualTo("default")
+        assertThat(component.fooFun().lazy.value).isEqualTo("default")
     }
 
     @Test
@@ -59,7 +83,13 @@ class DefaultParamTest {
         val component = OverrideDefaultComponent::class.create()
 
         assertThat(component.foo.name).isEqualTo("override")
+        assertThat(component.foo.fn()).isEqualTo("override")
+        assertThat(component.foo.lazy.value).isEqualTo("override")
         assertThat(component.iFoo.name).isEqualTo("override")
+        assertThat(component.iFoo.fn()).isEqualTo("override")
+        assertThat(component.iFoo.lazy.value).isEqualTo("override")
         assertThat(component.fooFun().name).isEqualTo("override")
+        assertThat(component.fooFun().fn()).isEqualTo("override")
+        assertThat(component.fooFun().lazy.value).isEqualTo("override")
     }
 }
\ No newline at end of file