From 8528519d9629df0cf286c7c50fb1ec70d6059505 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Wed, 22 Mar 2023 16:34:22 +0000 Subject: [PATCH] Improve container error reporting with containerId Merge-request: KT-MR-8965 Merged-by: Vladimir Dolzhenko --- .../jetbrains/kotlin/container/Container.kt | 9 ++++-- .../org/jetbrains/kotlin/container/Resolve.kt | 30 +++++++++++-------- .../jetbrains/kotlin/container/Singletons.kt | 2 +- .../org/jetbrains/kotlin/container/Storage.kt | 10 ++++--- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Container.kt b/compiler/container/src/org/jetbrains/kotlin/container/Container.kt index 12ea40228e7..84f18e4752c 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Container.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Container.kt @@ -25,6 +25,8 @@ import java.lang.reflect.WildcardType class ContainerConsistencyException(message: String) : Exception(message) interface ComponentContainer { + val containerId: String + fun createResolveContext(requestingDescriptor: ValueDescriptor): ValueResolveContext } @@ -108,7 +110,7 @@ class StorageComponentContainer( } override fun create(request: Class): T { - val constructorBinding = request.bindToConstructor(unknownContext) + val constructorBinding = request.bindToConstructor(containerId, unknownContext) val args = constructorBinding.argumentDescriptors.map { it.getValue() }.toTypedArray() return runWithUnwrappingInvocationException { @Suppress("UNCHECKED_CAST") @@ -116,7 +118,10 @@ class StorageComponentContainer( } } - override fun toString() = "Container $id" + override val containerId + get() = "Container: $id" + + override fun toString() = containerId } fun StorageComponentContainer.registerSingleton(klass: Class<*>): StorageComponentContainer { diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt b/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt index de7b36ffec6..6707a5934f4 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Resolve.kt @@ -31,11 +31,12 @@ interface ValueResolveContext { } class ComponentResolveContext( - val container: StorageComponentContainer, - val requestingDescriptor: ValueDescriptor, - val parentContext: ValueResolveContext? = null + 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 resolve(registration: Type): ValueDescriptor? = + container.resolve(registration, this) ?: parentContext?.resolve(registration) override fun toString(): String = "for $requestingDescriptor in $container" } @@ -51,17 +52,21 @@ class MethodBinding(val method: Method, private val argumentDescriptors: List): List = argumentDescriptors.map { it.getValue() } -fun Class<*>.bindToConstructor(context: ValueResolveContext): ConstructorBinding { - val constructorInfo = getInfo().constructorInfo ?: error("No constructor for $this: ${getInfo()}") +fun Class<*>.bindToConstructor(containerId: String, context: ValueResolveContext): ConstructorBinding { + val constructorInfo = getInfo().constructorInfo ?: error("No constructor for $this: ${getInfo()} in $containerId") val candidate = constructorInfo.constructor - return ConstructorBinding(candidate, candidate.bindArguments(constructorInfo.parameters, context)) + return ConstructorBinding(candidate, candidate.bindArguments(containerId, constructorInfo.parameters, context)) } -fun Method.bindToMethod(context: ValueResolveContext): MethodBinding { - return MethodBinding(this, bindArguments(genericParameterTypes.toList(), context)) +fun Method.bindToMethod(containerId: String, context: ValueResolveContext): MethodBinding { + return MethodBinding(this, bindArguments(containerId, genericParameterTypes.toList(), context)) } -private fun Member.bindArguments(parameters: List, context: ValueResolveContext): List { +private fun Member.bindArguments( + containerId: String, + parameters: List, + context: ValueResolveContext +): List { val bound = ArrayList(parameters.size) var unsatisfied: MutableList? = null @@ -71,13 +76,12 @@ private fun Member.bindArguments(parameters: List, context: ValueResolveCo if (unsatisfied == null) unsatisfied = ArrayList() unsatisfied.add(parameter) - } - else { + } else { bound.add(descriptor) } } if (unsatisfied != null) { - throw UnresolvedDependenciesException("Dependencies for `$this` cannot be satisfied:\n $unsatisfied") + throw UnresolvedDependenciesException("$containerId: Dependencies for `$this` cannot be satisfied:\n $unsatisfied") } return bound } diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt b/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt index ce7476b64c2..c81c3c9eaff 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Singletons.kt @@ -121,7 +121,7 @@ open class SingletonTypeComponentDescriptor(container: ComponentContainer, val k override fun getRegistrations(): Iterable = klass.getInfo().registrations private fun createInstanceOf(klass: Class<*>, context: ValueResolveContext): Any { - val binding = klass.bindToConstructor(context) + val binding = klass.bindToConstructor(container.containerId, context) state = ComponentState.Initializing for (argumentDescriptor in binding.argumentDescriptors) { if (argumentDescriptor is Closeable && argumentDescriptor !is SingletonDescriptor) { diff --git a/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt b/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt index 0694e680e7d..0bd64fc8590 100644 --- a/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt +++ b/compiler/container/src/org/jetbrains/kotlin/container/Storage.kt @@ -69,7 +69,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va return nonDefault.singleOrNull() ?: throw InvalidCardinalityException( - "Request $request cannot be satisfied because there is more than one type registered\n" + + "$containerId: Request $request cannot be satisfied because there is more than one type registered\n" + "Clashed registrations: ${entry.joinToString()}" ) } @@ -86,7 +86,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va } fun dump(printer: PrintStream): Unit = with(printer) { - val heading = "Container: $myId" + val heading = containerId println(heading) println("=".repeat(heading.length)) println() @@ -107,6 +107,8 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va } } + val containerId + get() = "Container: $myId" fun resolveMultiple(request: Type, context: ValueResolveContext): Iterable { registerDependency(request, context) @@ -132,7 +134,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va fun compose(context: ComponentResolveContext) { if (state != ComponentStorageState.Initial) - throw ContainerConsistencyException("Container $myId was already composed.") + throw ContainerConsistencyException("$containerId $myId was already composed.") state = ComponentStorageState.Initialized composeDescriptors(context, descriptors) @@ -216,7 +218,7 @@ class ComponentStorage(private val myId: String, parent: ComponentStorage?) : Va val classInfo = instance::class.java.getInfo() classInfo.setterInfos.forEach { (method) -> - val methodBinding = method.bindToMethod(context) + val methodBinding = method.bindToMethod(containerId, context) methodBinding.invoke(instance) } }