diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Container.kt b/compiler/container/src/org/jetbrains/kotlin/container/Container.kt index 867deef1b68..7a64e3fccc9 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Container.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Container.kt @@ -38,9 +38,12 @@ object DynamicComponentDescriptor : ValueDescriptor { override fun toString(): String = "Dynamic" } -class StorageComponentContainer(id: String) : ComponentContainer, ComponentProvider, Closeable { - val unknownContext: ComponentResolveContext by lazy { ComponentResolveContext(this, DynamicComponentDescriptor) } - val componentStorage = ComponentStorage(id) +class StorageComponentContainer(id: String, parent: StorageComponentContainer? = null) : ComponentContainer, ComponentProvider, Closeable { + val unknownContext: ComponentResolveContext by lazy { + val parentContext = parent?.let { ComponentResolveContext(it, DynamicComponentDescriptor) } + ComponentResolveContext(this, DynamicComponentDescriptor, parentContext) + } + val componentStorage: ComponentStorage = ComponentStorage(id, parent?.componentStorage) override fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext { if (requestingDescriptor == DynamicComponentDescriptor) // cache unknown component descriptor diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Dsl.kt b/compiler/container/src/org/jetbrains/kotlin/container/Dsl.kt index 0820532ced0..7d8898eab09 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Dsl.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Dsl.kt @@ -18,8 +18,8 @@ package org.jetbrains.kotlin.container import kotlin.reflect.KProperty -fun createContainer(id: String, init: StorageComponentContainer.() -> Unit): StorageComponentContainer { - val c = StorageComponentContainer(id) +fun createContainer(id: String, parent: StorageComponentContainer? = null, init: StorageComponentContainer.() -> Unit): StorageComponentContainer { + val c = StorageComponentContainer(id, parent) c.init() c.compose() return c diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Registry.kt b/compiler/container/src/org/jetbrains/kotlin/container/Registry.kt index 8251d8850e9..e060cd3bff4 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Registry.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Registry.kt @@ -17,8 +17,7 @@ package org.jetbrains.kotlin.container import com.intellij.util.containers.MultiMap -import java.util.ArrayList -import java.lang.reflect.* +import java.lang.reflect.Type internal class ComponentRegistry { fun buildRegistrationMap(descriptors: Collection): MultiMap { @@ -40,4 +39,8 @@ internal class ComponentRegistry { fun tryGetEntry(request: Type): Collection { return registrationMap.get(request) } + + fun addAll(other: ComponentRegistry) { + registrationMap.putAllValues(other.registrationMap) + } } \ No newline at end of file diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt b/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt index d475f9ab0a5..50e4bfe8c7c 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt @@ -30,8 +30,12 @@ interface ValueResolveContext { fun resolve(registration: Type): ValueDescriptor? } -class ComponentResolveContext(val container: StorageComponentContainer, val requestingDescriptor: ValueDescriptor) : ValueResolveContext { - override fun resolve(registration: Type): ValueDescriptor? = container.resolve(registration, this) +class ComponentResolveContext( + val container: StorageComponentContainer, + val requestingDescriptor: ValueDescriptor, + val parentContext: ValueResolveContext? = null +) : ValueResolveContext { + override fun resolve(registration: Type): ValueDescriptor? = container.resolve(registration, this) ?: parentContext?.resolve(registration) override fun toString(): String = "for $requestingDescriptor in $container" } diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt b/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt index c8c2fbfe916..05afb125986 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt @@ -35,9 +35,13 @@ enum class ComponentStorageState { internal class InvalidCardinalityException(message: String, val descriptors: Collection) : Exception(message) -class ComponentStorage(val myId: String) : ValueResolver { +class ComponentStorage(val myId: String, parent: ComponentStorage?) : ValueResolver { var state = ComponentStorageState.Initial private val registry = ComponentRegistry() + init { + parent?.let { registry.addAll(it.registry) } + } + private val descriptors = LinkedHashSet() private val dependencies = MultiMap.createLinkedSet() diff --git a/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt b/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt index a9a6358af96..c41a3ebc169 100644 --- a/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt +++ b/compiler/container/tests/org/jetbrains/kotlin/container/tests/ComponentContainerTest.kt @@ -270,4 +270,46 @@ class ComponentContainerTest { assertTrue(c is C) } + @Test + fun use_parent_context_to_discover_dependencies() { + class A + class B(val a: A) + + val ac = createContainer("a") { + useImpl() + } + + val bc = createContainer("b", ac) { + useImpl() + } + val b = bc.get() + + val a = ac.get() + assertTrue(b is B) + assertTrue(b.a is A) + assertTrue(a is A) + assertTrue(b.a === a) + } + + @Test + fun several_child_dependencies() { + class A + class B(val a: A) + + val ac = createContainer("a") { + useImpl() + } + + val bc1 = createContainer("b1", ac) { + useImpl() + } + val bc2 = createContainer("b2", ac) { + useImpl() + } + val a = ac.get() + assertTrue(a is A) + assertTrue(a === bc2.get().a) + assertTrue(a === bc1.get().a) + assertTrue(a === bc1.get()) + } } \ No newline at end of file