Skip to content

Commit 561ffbe

Browse files
committed
Fix compile error when accessing parent scoped dependency in cycle run block
Fixes #279
1 parent dcf3d48 commit 561ffbe

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

integration-tests/common/src/test/kotlin/me/tatarka/inject/test/RecursiveTest.kt

+28
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,24 @@ abstract class OptimizedCycleComponent {
9393
abstract val baz: CycleBaz
9494
}
9595

96+
@CustomScope
97+
@Inject
98+
class ScopeBar(val foo: ScopeFoo)
99+
100+
@Inject
101+
class ScopeFoo(val bar: Lazy<ScopeBar>)
102+
103+
@Component
104+
@CustomScope
105+
abstract class ParentCycleComponent
106+
107+
@Component
108+
abstract class ChildCycleComponent(
109+
@Component val parent: ParentCycleComponent,
110+
) {
111+
abstract val foo: ScopeFoo
112+
}
113+
96114
class RecursiveTest {
97115

98116
@Test
@@ -152,4 +170,14 @@ class RecursiveTest {
152170
assertThat(baz.foo).isSameAs(baz.foo.bar.foo())
153171
}
154172
}
173+
174+
@Test
175+
fun generates_a_component_with_a_scoped_parent_dependency_recursively() {
176+
val component = ChildCycleComponent::class.create(ParentCycleComponent::class.create())
177+
val foo = component.foo
178+
val bar = foo.bar.value
179+
180+
assertThat(foo).isSameAs(foo.bar.value.foo)
181+
assertThat(bar).isSameAs(bar.foo.bar.value)
182+
}
155183
}

kotlin-inject-compiler/core/src/main/kotlin/me/tatarka/inject/compiler/TypeResultGenerator.kt

+12-2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ data class TypeResultGenerator(val options: Options, val implicitAccessor: Acces
155155
add("$paramName = ")
156156
add(param.generate())
157157
}
158+
158159
else -> add(param.generate())
159160
}
160161
}
@@ -197,13 +198,15 @@ data class TypeResultGenerator(val options: Options, val implicitAccessor: Acces
197198
} else {
198199
add("%T::class.java.name", typeName)
199200
}
201+
200202
is ParameterizedTypeName -> {
201203
addTypeName(typeName.rawType)
202204
for (arg in typeName.typeArguments) {
203205
add("+")
204206
addTypeName(arg)
205207
}
206208
}
209+
207210
is LambdaTypeName -> {
208211
val functionName = if (typeName.isSuspending) {
209212
ClassName("kotlin.coroutines", "SuspendFunction${typeName.parameters.size}")
@@ -219,6 +222,7 @@ data class TypeResultGenerator(val options: Options, val implicitAccessor: Acces
219222
add("+")
220223
addTypeName(typeName.returnType)
221224
}
225+
222226
else -> add("%S", typeName)
223227
}
224228
} else {
@@ -323,8 +327,14 @@ data class TypeResultGenerator(val options: Options, val implicitAccessor: Acces
323327

324328
private fun TypeResult.LateInit.generate(): CodeBlock {
325329
return CodeBlock.builder().apply {
326-
beginControlFlow("run")
327-
addStatement("lateinit var %N: %T", name, result.key.type.toTypeName())
330+
// Using the run extension method creates a new 'this' scope which causes kotlin's type inference for the
331+
// current 'this' to be dropped. This breaks scoped parent resolution as we use
332+
// require(parent is ScopedComponent) to access the parent scope.
333+
// To work around this we explicitly pass the return type to ensure it calls the top-level run overload
334+
// instead of the extension method.
335+
val returnType = result.key.type.toTypeName()
336+
beginControlFlow("run<%T>", returnType)
337+
addStatement("lateinit var %N: %T", name, returnType)
328338
add(result.generate())
329339
beginControlFlow(".also")
330340
addStatement("%N = it", name)

0 commit comments

Comments
 (0)