Advanced Features

Garbage Collection

A garbage collector is included in distage by default. Given a set of GC root keys, GC will remove all bindings that are neither direct nor transitive dependencies of the supplied roots – these bindings will be thrown out and never instantiated.

GC serves two important purposes:

  • It enables faster tests by omitting unrequired instantiations and initialization of potentially heavy resources,
  • It enables multiple independent applications, aka “Roles” to be hosted within a single .jar file.

To use garbage collector, pass GC roots as an argument to Injector.produce* methods:

import distage._

class A(b: B) {
  println("A!")
}
class B() {
  println("B!")
}
class C() {
  println("C!")
}

val module = new ModuleDef {
  make[A]
  make[B]
  make[C]
}
// module: AnyRef with ModuleDef = 
// make[{type.repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.A}].from(call(Class(repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.B): repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.A)) ((advanced-features.md:30))
// make[{type.repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.B}].from(call(Class(): repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.B)) ((advanced-features.md:31))
// make[{type.repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.C}].from(call(Class(): repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.C)) ((advanced-features.md:32))

// declare `A` as a GC root

val gc = Roots(root = DIKey[A])
// gc: Roots = Of(NonEmptySet({type.repl.MdocSession::repl.MdocSession.App0::repl.MdocSession.App0.A}))

// create an object graph from description in `module`
// with `A` as a GC root

val objects = Injector().produce(module, gc).unsafeGet()
// B!
// A!
// objects: izumi.fundamentals.platform.functional.package.Identity[Locator] = izumi.distage.LocatorDefaultImpl@38bb0441

// A and B are in the object graph

objects.find[A]
// res1: Option[A] = Some(repl.MdocSession$App0$A@6f54155b)

objects.find[B]
// res2: Option[B] = Some(repl.MdocSession$App0$B@497971b4)

// C is missing

objects.find[C]
// res3: Option[C] = None

Class C was removed because neither B nor A depended on it. It’s not present in the Locator and the "C!" message has never been printed. If class B had a C parameter, like class B(c: C); C would have been retained, because A - the GC root, would depend on B, and B would depend on C.

class B(c: C) {
  println("B!")
}

val objects = Injector().produce(module, Roots(DIKey[A])).unsafeGet()
// C!
// B!
// A!
// objects: izumi.fundamentals.platform.functional.package.Identity[Locator] = izumi.distage.LocatorDefaultImpl@100013d5

objects.find[C]
// res5: Option[C] = Some(repl.MdocSession$App4$C@70f99498)

Circular Dependencies Support

distage automatically resolves arbitrary circular dependencies, including self-references:

import distage.{Roots, ModuleDef, Injector}

class A(val b: B)
class B(val a: A)  
class C(val c: C)

val objects = Injector().produce(new ModuleDef {
  make[A]
  make[B]
  make[C]
}, Roots.Everything).unsafeGet()
// objects: izumi.fundamentals.platform.functional.package.Identity[izumi.distage.model.Locator] = izumi.distage.LocatorDefaultImpl@3f48b911

objects.get[A] eq objects.get[B].a
// res7: Boolean = true
objects.get[B] eq objects.get[A].b
// res8: Boolean = true
objects.get[C] eq objects.get[C].c
// res9: Boolean = true

Automatic Resolution with generated proxies

The above strategy depends on distage-core-proxy-cglib module which is a default dependency of distage-core.

If you want to disable it, use NoProxies bootstrap configuration:

Injector.NoProxies()
// res10: Injector = izumi.distage.InjectorDefaultImpl@3d3e8b9d

Proxies are not supported on Scala.js.

Manual Resolution with by-name parameters

Most cycles can be resolved without proxies, using By-Name parameters:

import distage.{Roots, ModuleDef, Injector}

class A(b0: => B) {
  def b: B = b0
}

class B(a0: => A) {
  def a: A = a0
}

class C(self: => C) {
  def c: C = self
}

val module = new ModuleDef {
  make[A]
  make[B]
  make[C]
}
// module: AnyRef with ModuleDef = 
// make[{type.repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.A}].from(call(Class(repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.B): repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.A)) ((advanced-features.md:156))
// make[{type.repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.B}].from(call(Class(repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.A): repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.B)) ((advanced-features.md:157))
// make[{type.repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.C}].from(call(Class(repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.C): repl.MdocSession::repl.MdocSession.App11::repl.MdocSession.App11.C)) ((advanced-features.md:158))

// disable proxies and execute the module

val locator = Injector.NoProxies()
  .produce(module, Roots.Everything)
  .unsafeGet()
// locator: izumi.fundamentals.platform.functional.package.Identity[izumi.distage.model.Locator] = izumi.distage.LocatorDefaultImpl@2d30a954

locator.get[A].b eq locator.get[B]
// res12: Boolean = true
locator.get[B].a eq locator.get[A]
// res13: Boolean = true
locator.get[C].c eq locator.get[C]
// res14: Boolean = true

The proxy generation via cglib is enabled by default, because in scenarios with extreme late-binding cycles can emerge unexpectedly, out of control of the origin module.

Note: Currently a limitation applies to by-names - ALL dependencies of a class engaged in a by-name circular dependency must be by-name, otherwise distage will revert to generating proxies.

Auto-Sets

AutoSet Planner Hooks can traverse the plan and collect all future objects that match a predicate.

Using Auto-Sets you can e.g. collect all AutoCloseable classes and .close() them after the application has finished work. NOTE: please use Resource bindings for real lifecycle, this is just an example.

import distage.{BootstrapModuleDef, ModuleDef, Injector, Roots}
import izumi.distage.model.planning.PlanningHook
import izumi.distage.planning.AutoSetHook

class PrintResource(name: String) {
  def start(): Unit = println(s"$name started")
  def stop(): Unit = println(s"$name stopped")
}

class A extends PrintResource("A")
class B(val a: A) extends PrintResource("B")
class C(val b: B) extends PrintResource("C")

val bootstrapModule = new BootstrapModuleDef {
  many[PlanningHook]
    .add(new AutoSetHook[PrintResource, PrintResource](identity))
}
// bootstrapModule: AnyRef with BootstrapModuleDef = 
// many[{type.scala.collection.immutable.Set[=PlanningHook]}] ((advanced-features.md:207))
// many[{type.scala.collection.immutable.Set[=PlanningHook]}].add[{type.izumi.distage.planning.AutoSetHook[=MdocSession::App15::PrintResource,=MdocSession::App15::PrintResource]}].from(call(izumi.distage.model.definition.dsl.ModuleDefDSL$SetDSLBase$$Lambda$18839/758193869@3ed4ee18(): izumi.distage.planning.AutoSetHook[=MdocSession::App15::PrintResource,=MdocSession::App15::PrintResource])) ((advanced-features.md:208))

val appModule = new ModuleDef {
  make[A]
  make[B]
  make[C]
}
// appModule: AnyRef with ModuleDef = 
// make[{type.repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.A}].from(call(Class(): repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.A)) ((advanced-features.md:213))
// make[{type.repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.B}].from(call(Class(repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.A): repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.B)) ((advanced-features.md:214))
// make[{type.repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.C}].from(call(Class(repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.B): repl.MdocSession::repl.MdocSession.App15::repl.MdocSession.App15.C)) ((advanced-features.md:215))

val resources = Injector(bootstrapModule)
  .produce(appModule, Roots.Everything)
  .use(_.get[Set[PrintResource]])
// resources: izumi.fundamentals.platform.functional.package.Identity[Set[PrintResource]] = ListSet(repl.MdocSession$App15$A@646fdfd2, repl.MdocSession$App15$B@2523dae2, repl.MdocSession$App15$C@4ff3229b)

resources.foreach(_.start())
// A started
// B started
// C started
resources.toSeq.reverse.foreach(_.stop())
// C stopped
// B stopped
// A stopped

Calling .foreach on an auto-set is safe; the actions will be executed in order of dependencies. Auto-Sets preserve ordering, they use ListSet under the hood, unlike user-defined Sets. e.g. If C depends on B depends on A, autoset order is: A, B, C, to start call: A, B, C, to close call: C, B, A. When you use auto-sets for finalization, you must .reverse the autoset.

Note: Auto-Sets are NOT subject to Garbage Collection, they are assembled after garbage collection is done, as such they can’t contain garbage by construction. Because of that they also cannot be used as GC Roots.

See also: same concept in MacWire

Weak Sets

Set bindings can contain weak references. References designated as weak will be retained only if there are other dependencies on the referred bindings, NOT if there’s a dependency only on the entire Set.

Example:

import distage._

sealed trait Elem

final case class Strong() extends Elem {
  println("Strong constructed")
}

final case class Weak() extends Elem {
  println("Weak constructed")
}

val module = new ModuleDef {
  make[Strong]
  make[Weak]
  
  many[Elem]
    .ref[Strong]
    .weak[Weak]
}
// module: AnyRef with ModuleDef = 
// make[{type.repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Strong}].from(call(Class(): repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Strong)) ((advanced-features.md:253))
// make[{type.repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Weak}].from(call(Class(): repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Weak)) ((advanced-features.md:254))
// many[{type.scala.collection.immutable.Set[=MdocSession::App18::Elem]}] ((advanced-features.md:256))
// many[{type.scala.collection.immutable.Set[=MdocSession::App18::Elem]}].add[{type.repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Strong}].from(using[{type.repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Strong}: repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Strong]) ((advanced-features.md:257))
// many[{type.scala.collection.immutable.Set[=MdocSession::App18::Elem]}].add[{type.repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Weak}].from(weak[{type.repl.MdocSession::repl.MdocSession.App18::repl.MdocSession.App18.Weak}]) ((advanced-features.md:258))

// Designate Set[Elem] as the garbage collection root,
// everything that Set[Elem] does not strongly depend on will be garbage collected
// and will not be constructed. 

val roots = Set[DIKey](DIKey[Set[Elem]])
// roots: Set[DIKey] = Set({type.scala.collection.immutable.Set[=MdocSession::App18::Elem]})

val objects = Injector().produce(PlannerInput(module, roots)).unsafeGet()
// Strong constructed
// objects: izumi.fundamentals.platform.functional.package.Identity[Locator] = izumi.distage.LocatorDefaultImpl@56cea153

// Strong is around

objects.find[Strong]
// res19: Option[Strong] = Some(Strong())

// Weak is not

objects.find[Strong]
// res20: Option[Strong] = Some(Strong())

// There's only Strong in the Set

objects.get[Set[Elem]]
// res21: Set[Elem] = Set(Strong())

The Weak class was not required by any dependency of Set[Elem], so it was pruned. The Strong class remained, because the reference to it was strong, so it was counted as a dependency of Set[Elem].

If we change Strong to depend on the Weak, then Weak will be retained:

final class Strong(weak: Weak) extends Elem {
  println("Strong constructed")
}

val objects = Injector().produce(PlannerInput(module, roots)).unsafeGet()
// Weak constructed
// Strong constructed
// objects: izumi.fundamentals.platform.functional.package.Identity[Locator] = izumi.distage.LocatorDefaultImpl@4c456517

// Weak is around

objects.find[Weak]
// res23: Option[Weak] = Some(repl.MdocSession$App22$Weak@778a42b7)

// both Strong and Weak are in the Set

objects.get[Set[Elem]]
// res24: Set[Elem] = Set(repl.MdocSession$App22$Strong@21bb4127, repl.MdocSession$App22$Weak@778a42b7)

Inner Classes and Path-Dependent Types

Path-dependent types with a value prefix will be instantiated normally:

import distage.{Roots, ModuleDef, Injector}

class Path {
  class A
}
val path = new Path
// path: Path = repl.MdocSession$App25$Path@2dcb87a

def module = new ModuleDef {
  make[path.A]
}

Injector()
  .produce(module, Roots.Everything)
  .use(_.get[path.A])
// res26: izumi.fundamentals.platform.functional.package.Identity[path.A] = repl.MdocSession$App25$Path$A@655618eb

Since version 0.10, support for path-dependent types with a non-value (type) prefix hasn’t reimplemented after a rewrite of the internals, see issue: https://github.com/7mind/izumi/issues/764

However, there’s a gotcha with value prefixes, when seen by distage they’re based on the literal variable name of the prefix, not the full type information available to the compiler, therefore the following usage will fail:

def pathModule(p: Path) = new ModuleDef {
  make[p.A]
}

val path1 = new Path
// path1: Path = repl.MdocSession$App25$Path@406c710c
val path2 = new Path
// path2: Path = repl.MdocSession$App25$Path@3b25a25f
Injector()
  .produceRun(pathModule(path1) ++ pathModule(path2)) {
    (p1a: path1.A, p2a: path2.A) =>
      println((p1a, p2a))
  }
// izumi.distage.model.exceptions.ProvisioningException: Provisioner stopped after 1 instances, 2/2 operations failed: 
//  - {type.repl.MdocSession::repl.MdocSession.App25::repl.MdocSession.App25.path1::repl.MdocSession.App25.Path.A} (<unknown>), MissingInstanceException: izumi.distage.model.exceptions.MissingInstanceException: Instance is not available in the object graph: {type.repl.MdocSession::repl.MdocSession.App25::repl.MdocSession.App25.path1::repl.MdocSession.App25.Path.A}.
// Required by refs:ø
// 	at izumi.distage.provisioning.strategies.ImportStrategyDefaultImpl.importDependency(ImportStrategyDefaultImpl.scala:15)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.execute(PlanInterpreterDefaultRuntimeImpl.scala:147)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$3(PlanInterpreterDefaultRuntimeImpl.scala:79)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.definitelyRecover(DIEffect.scala:75)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2(PlanInterpreterDefaultRuntimeImpl.scala:81)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2$adapted(PlanInterpreterDefaultRuntimeImpl.scala:71)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.processStep$1(PlanInterpreterDefaultRuntimeImpl.scala:70)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$14(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 	at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$2(DIEffect.scala:44)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 	at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$1(DIEffect.scala:44)
// 	at scala.collection.IterableOnceOps.foldLeft(IterableOnce.scala:638)
// 	at scala.collection.IterableOnceOps.foldLeft$(IterableOnce.scala:634)
// 	at scala.collection.AbstractIterable.foldLeft(Iterable.scala:920)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.instantiateImpl(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiate$1(PlanInterpreterDefaultRuntimeImpl.scala:44)
// 	at izumi.distage.model.definition.DIResource$$anon$1.acquire(DIResource.scala:162)
// 	at izumi.distage.model.definition.DIResource$$anon$11.$anonfun$acquire$6(DIResource.scala:687)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.bracketCase(DIEffect.scala:87)
// 	at izumi.distage.model.definition.DIResource$$anon$11.acquire(DIResource.scala:676)
// 	at izumi.distage.model.definition.DIResource$DIResourceUse$.$anonfun$use$extension$1(DIResource.scala:144)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.bracket(DIEffect.scala:83)
// 	at izumi.distage.model.Injector.produceRunF(Injector.scala:52)
// 	at izumi.distage.model.Injector.produceRunF$(Injector.scala:51)
// 	at izumi.distage.InjectorDefaultImpl.produceRunF(InjectorDefaultImpl.scala:15)
// 	at izumi.distage.model.Injector.produceRun(Injector.scala:156)
// 	at izumi.distage.model.Injector.produceRun$(Injector.scala:156)
// 	at izumi.distage.InjectorDefaultImpl.produceRun(InjectorDefaultImpl.scala:15)
// 	at repl.MdocSession$App25$$anonfun$65.apply$mcV$sp(advanced-features.md:370)
// 	at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 	at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.crash(DocumentBuilder.scala:69)
// 	at repl.MdocSession$App25.<init>(advanced-features.md:370)
// 	at repl.MdocSession$App22$.<clinit>(advanced-features.md:324)
// 	at repl.MdocSession$App18$.<clinit>(advanced-features.md:277)
// 	at repl.MdocSession$App15.<init>(advanced-features.md:230)
// 	at repl.MdocSession$App11.<init>(advanced-features.md:176)
// 	at repl.MdocSession$App6$.<clinit>(advanced-features.md:131)
// 	at repl.MdocSession$App4$.<clinit>(advanced-features.md:91)
// 	at repl.MdocSession$App0.<init>(advanced-features.md:51)
// 	at repl.MdocSession$App.<init>(advanced-features.md:5)
// 	at repl.MdocSession$.app(advanced-features.md:3)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:82)
// 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 	at scala.Console$.withErr(Console.scala:193)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:82)
// 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 	at scala.Console$.withOut(Console.scala:164)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:81)
// 	at mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44)
// 	at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:186)
// 	at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:153)
// 	at mdoc.internal.markdown.Processor.processDocument(Processor.scala:52)
// 	at mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:132)
// 	at mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82)
// 	at mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110)
// 	at mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:157)
// 	at scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:168)
// 	at scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:164)
// 	at scala.collection.immutable.List.foldLeft(List.scala:79)
// 	at mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155)
// 	at mdoc.internal.cli.MainOps.run(MainOps.scala:178)
// 	at mdoc.internal.cli.MainOps$.process(MainOps.scala:270)
// 	at mdoc.Main$.process(Main.scala:26)
// 	at mdoc.Main$.process(Main.scala:21)
// 	at mdoc.Main$.main(Main.scala:16)
// 	at mdoc.Main.main(Main.scala)
// 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
// 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
// 	at java.lang.reflect.Method.invoke(Method.java:498)
// 	at sbt.Run.invokeMain(Run.scala:115)
// 	at sbt.Run.execute$1(Run.scala:79)
// 	at sbt.Run.$anonfun$runWithLoader$4(Run.scala:92)
// 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
// 	at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:10)
// 	at sbt.TrapExit$App.run(TrapExit.scala:257)
// 	at java.lang.Thread.run(Thread.java:748)
// 
//  - {type.repl.MdocSession::repl.MdocSession.App25::repl.MdocSession.App25.path2::repl.MdocSession.App25.Path.A} (<unknown>), MissingInstanceException: izumi.distage.model.exceptions.MissingInstanceException: Instance is not available in the object graph: {type.repl.MdocSession::repl.MdocSession.App25::repl.MdocSession.App25.path2::repl.MdocSession.App25.Path.A}.
// Required by refs:ø
// 	at izumi.distage.provisioning.strategies.ImportStrategyDefaultImpl.importDependency(ImportStrategyDefaultImpl.scala:15)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.execute(PlanInterpreterDefaultRuntimeImpl.scala:147)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$3(PlanInterpreterDefaultRuntimeImpl.scala:79)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.definitelyRecover(DIEffect.scala:75)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2(PlanInterpreterDefaultRuntimeImpl.scala:81)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2$adapted(PlanInterpreterDefaultRuntimeImpl.scala:71)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.processStep$1(PlanInterpreterDefaultRuntimeImpl.scala:70)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$14(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 	at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$2(DIEffect.scala:44)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 	at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$1(DIEffect.scala:44)
// 	at scala.collection.IterableOnceOps.foldLeft(IterableOnce.scala:638)
// 	at scala.collection.IterableOnceOps.foldLeft$(IterableOnce.scala:634)
// 	at scala.collection.AbstractIterable.foldLeft(Iterable.scala:920)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.instantiateImpl(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 	at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiate$1(PlanInterpreterDefaultRuntimeImpl.scala:44)
// 	at izumi.distage.model.definition.DIResource$$anon$1.acquire(DIResource.scala:162)
// 	at izumi.distage.model.definition.DIResource$$anon$11.$anonfun$acquire$6(DIResource.scala:687)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.bracketCase(DIEffect.scala:87)
// 	at izumi.distage.model.definition.DIResource$$anon$11.acquire(DIResource.scala:676)
// 	at izumi.distage.model.definition.DIResource$DIResourceUse$.$anonfun$use$extension$1(DIResource.scala:144)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.bracket(DIEffect.scala:83)
// 	at izumi.distage.model.Injector.produceRunF(Injector.scala:52)
// 	at izumi.distage.model.Injector.produceRunF$(Injector.scala:51)
// 	at izumi.distage.InjectorDefaultImpl.produceRunF(InjectorDefaultImpl.scala:15)
// 	at izumi.distage.model.Injector.produceRun(Injector.scala:156)
// 	at izumi.distage.model.Injector.produceRun$(Injector.scala:156)
// 	at izumi.distage.InjectorDefaultImpl.produceRun(InjectorDefaultImpl.scala:15)
// 	at repl.MdocSession$App25$$anonfun$65.apply$mcV$sp(advanced-features.md:370)
// 	at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 	at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.crash(DocumentBuilder.scala:69)
// 	at repl.MdocSession$App25.<init>(advanced-features.md:370)
// 	at repl.MdocSession$App22$.<clinit>(advanced-features.md:324)
// 	at repl.MdocSession$App18$.<clinit>(advanced-features.md:277)
// 	at repl.MdocSession$App15.<init>(advanced-features.md:230)
// 	at repl.MdocSession$App11.<init>(advanced-features.md:176)
// 	at repl.MdocSession$App6$.<clinit>(advanced-features.md:131)
// 	at repl.MdocSession$App4$.<clinit>(advanced-features.md:91)
// 	at repl.MdocSession$App0.<init>(advanced-features.md:51)
// 	at repl.MdocSession$App.<init>(advanced-features.md:5)
// 	at repl.MdocSession$.app(advanced-features.md:3)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:82)
// 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 	at scala.Console$.withErr(Console.scala:193)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:82)
// 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 	at scala.Console$.withOut(Console.scala:164)
// 	at mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:81)
// 	at mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44)
// 	at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:186)
// 	at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:153)
// 	at mdoc.internal.markdown.Processor.processDocument(Processor.scala:52)
// 	at mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:132)
// 	at mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82)
// 	at mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110)
// 	at mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:157)
// 	at scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:168)
// 	at scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:164)
// 	at scala.collection.immutable.List.foldLeft(List.scala:79)
// 	at mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155)
// 	at mdoc.internal.cli.MainOps.run(MainOps.scala:178)
// 	at mdoc.internal.cli.MainOps$.process(MainOps.scala:270)
// 	at mdoc.Main$.process(Main.scala:26)
// 	at mdoc.Main$.process(Main.scala:21)
// 	at mdoc.Main$.main(Main.scala:16)
// 	at mdoc.Main.main(Main.scala)
// 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
// 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
// 	at java.lang.reflect.Method.invoke(Method.java:498)
// 	at sbt.Run.invokeMain(Run.scala:115)
// 	at sbt.Run.execute$1(Run.scala:79)
// 	at sbt.Run.$anonfun$runWithLoader$4(Run.scala:92)
// 	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
// 	at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:10)
// 	at sbt.TrapExit$App.run(TrapExit.scala:257)
// 	at java.lang.Thread.run(Thread.java:748)
// 
// 	at izumi.distage.model.provisioning.PlanInterpreter$FailedProvision.$anonfun$throwException$2(PlanInterpreter.scala:65)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.fail(DIEffect.scala:97)
// 	at izumi.distage.model.provisioning.PlanInterpreter$FailedProvision.throwException(PlanInterpreter.scala:66)
// 	at izumi.distage.model.provisioning.PlanInterpreter$FailedProvision$FailedProvisionExt$.$anonfun$throwOnFailure$1(PlanInterpreter.scala:73)
// 	at scala.util.Either.fold(Either.scala:190)
// 	at izumi.distage.model.provisioning.PlanInterpreter$FailedProvision$FailedProvisionExt$.throwOnFailure$extension(PlanInterpreter.scala:73)
// 	at izumi.distage.InjectorDefaultImpl.$anonfun$produceFX$1(InjectorDefaultImpl.scala:55)
// 	at izumi.distage.model.definition.DIResource$.$anonfun$evalMapImpl$2(DIResource.scala:710)
// 	at izumi.distage.model.definition.DIResource$$anon$1.acquire(DIResource.scala:162)
// 	at izumi.distage.model.definition.DIResource$$anon$11.$anonfun$acquire$9(DIResource.scala:690)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.bracketCase(DIEffect.scala:87)
// 	at izumi.distage.model.definition.DIResource$$anon$11.$anonfun$acquire$8(DIResource.scala:676)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.$anonfun$bracketCase$1(DIEffect.scala:88)
// 	at scala.util.Try$.apply(Try.scala:210)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.bracketCase(DIEffect.scala:88)
// 	at izumi.distage.model.definition.DIResource$$anon$11.acquire(DIResource.scala:676)
// 	at izumi.distage.model.definition.DIResource$DIResourceUse$.$anonfun$use$extension$1(DIResource.scala:144)
// 	at izumi.distage.model.effect.DIEffect$$anon$1.bracket(DIEffect.scala:83)
// 	at izumi.distage.model.Injector.produceRunF(Injector.scala:52)
// 	at izumi.distage.model.Injector.produceRunF$(Injector.scala:51)
// 	at izumi.distage.InjectorDefaultImpl.produceRunF(InjectorDefaultImpl.scala:15)
// 	at izumi.distage.model.Injector.produceRun(Injector.scala:156)
// 	at izumi.distage.model.Injector.produceRun$(Injector.scala:156)
// 	at izumi.distage.InjectorDefaultImpl.produceRun(InjectorDefaultImpl.scala:15)
// 	at repl.MdocSession$App25$$anonfun$65.apply$mcV$sp(advanced-features.md:370)
// 	at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 	at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 	Suppressed: izumi.distage.model.exceptions.MissingInstanceException: Instance is not available in the object graph: {type.repl.MdocSession::repl.MdocSession.App25::repl.MdocSession.App25.path1::repl.MdocSession.App25.Path.A}.
// Required by refs:ø
// 		at izumi.distage.provisioning.strategies.ImportStrategyDefaultImpl.importDependency(ImportStrategyDefaultImpl.scala:15)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.execute(PlanInterpreterDefaultRuntimeImpl.scala:147)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$3(PlanInterpreterDefaultRuntimeImpl.scala:79)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.definitelyRecover(DIEffect.scala:75)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2(PlanInterpreterDefaultRuntimeImpl.scala:81)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2$adapted(PlanInterpreterDefaultRuntimeImpl.scala:71)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.processStep$1(PlanInterpreterDefaultRuntimeImpl.scala:70)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$14(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 		at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$2(DIEffect.scala:44)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 		at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$1(DIEffect.scala:44)
// 		at scala.collection.IterableOnceOps.foldLeft(IterableOnce.scala:638)
// 		at scala.collection.IterableOnceOps.foldLeft$(IterableOnce.scala:634)
// 		at scala.collection.AbstractIterable.foldLeft(Iterable.scala:920)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.instantiateImpl(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiate$1(PlanInterpreterDefaultRuntimeImpl.scala:44)
// 		at izumi.distage.model.definition.DIResource$$anon$1.acquire(DIResource.scala:162)
// 		at izumi.distage.model.definition.DIResource$$anon$11.$anonfun$acquire$6(DIResource.scala:687)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.bracketCase(DIEffect.scala:87)
// 		at izumi.distage.model.definition.DIResource$$anon$11.acquire(DIResource.scala:676)
// 		at izumi.distage.model.definition.DIResource$DIResourceUse$.$anonfun$use$extension$1(DIResource.scala:144)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.bracket(DIEffect.scala:83)
// 		at izumi.distage.model.Injector.produceRunF(Injector.scala:52)
// 		at izumi.distage.model.Injector.produceRunF$(Injector.scala:51)
// 		at izumi.distage.InjectorDefaultImpl.produceRunF(InjectorDefaultImpl.scala:15)
// 		at izumi.distage.model.Injector.produceRun(Injector.scala:156)
// 		at izumi.distage.model.Injector.produceRun$(Injector.scala:156)
// 		at izumi.distage.InjectorDefaultImpl.produceRun(InjectorDefaultImpl.scala:15)
// 		at repl.MdocSession$App25$$anonfun$65.apply$mcV$sp(advanced-features.md:370)
// 		at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 		at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.crash(DocumentBuilder.scala:69)
// 		at repl.MdocSession$App25.<init>(advanced-features.md:370)
// 		at repl.MdocSession$App22$.<clinit>(advanced-features.md:324)
// 		at repl.MdocSession$App18$.<clinit>(advanced-features.md:277)
// 		at repl.MdocSession$App15.<init>(advanced-features.md:230)
// 		at repl.MdocSession$App11.<init>(advanced-features.md:176)
// 		at repl.MdocSession$App6$.<clinit>(advanced-features.md:131)
// 		at repl.MdocSession$App4$.<clinit>(advanced-features.md:91)
// 		at repl.MdocSession$App0.<init>(advanced-features.md:51)
// 		at repl.MdocSession$App.<init>(advanced-features.md:5)
// 		at repl.MdocSession$.app(advanced-features.md:3)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:82)
// 		at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 		at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 		at scala.Console$.withErr(Console.scala:193)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:82)
// 		at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 		at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 		at scala.Console$.withOut(Console.scala:164)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:81)
// 		at mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44)
// 		at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:186)
// 		at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:153)
// 		at mdoc.internal.markdown.Processor.processDocument(Processor.scala:52)
// 		at mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:132)
// 		at mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82)
// 		at mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110)
// 		at mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:157)
// 		at scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:168)
// 		at scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:164)
// 		at scala.collection.immutable.List.foldLeft(List.scala:79)
// 		at mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155)
// 		at mdoc.internal.cli.MainOps.run(MainOps.scala:178)
// 		at mdoc.internal.cli.MainOps$.process(MainOps.scala:270)
// 		at mdoc.Main$.process(Main.scala:26)
// 		at mdoc.Main$.process(Main.scala:21)
// 		at mdoc.Main$.main(Main.scala:16)
// 		at mdoc.Main.main(Main.scala)
// 		at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// 		at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
// 		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
// 		at java.lang.reflect.Method.invoke(Method.java:498)
// 		at sbt.Run.invokeMain(Run.scala:115)
// 		at sbt.Run.execute$1(Run.scala:79)
// 		at sbt.Run.$anonfun$runWithLoader$4(Run.scala:92)
// 		at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
// 		at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:10)
// 		at sbt.TrapExit$App.run(TrapExit.scala:257)
// 		at java.lang.Thread.run(Thread.java:748)
// 	Suppressed: izumi.distage.model.exceptions.MissingInstanceException: Instance is not available in the object graph: {type.repl.MdocSession::repl.MdocSession.App25::repl.MdocSession.App25.path2::repl.MdocSession.App25.Path.A}.
// Required by refs:ø
// 		at izumi.distage.provisioning.strategies.ImportStrategyDefaultImpl.importDependency(ImportStrategyDefaultImpl.scala:15)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.execute(PlanInterpreterDefaultRuntimeImpl.scala:147)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$3(PlanInterpreterDefaultRuntimeImpl.scala:79)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.definitelyRecover(DIEffect.scala:75)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2(PlanInterpreterDefaultRuntimeImpl.scala:81)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$2$adapted(PlanInterpreterDefaultRuntimeImpl.scala:71)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.processStep$1(PlanInterpreterDefaultRuntimeImpl.scala:70)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiateImpl$14(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 		at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$2(DIEffect.scala:44)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.flatMap(DIEffect.scala:71)
// 		at izumi.distage.model.effect.DIEffect.$anonfun$traverse_$1(DIEffect.scala:44)
// 		at scala.collection.IterableOnceOps.foldLeft(IterableOnce.scala:638)
// 		at scala.collection.IterableOnceOps.foldLeft$(IterableOnce.scala:634)
// 		at scala.collection.AbstractIterable.foldLeft(Iterable.scala:920)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.instantiateImpl(PlanInterpreterDefaultRuntimeImpl.scala:119)
// 		at izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl.$anonfun$instantiate$1(PlanInterpreterDefaultRuntimeImpl.scala:44)
// 		at izumi.distage.model.definition.DIResource$$anon$1.acquire(DIResource.scala:162)
// 		at izumi.distage.model.definition.DIResource$$anon$11.$anonfun$acquire$6(DIResource.scala:687)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.bracketCase(DIEffect.scala:87)
// 		at izumi.distage.model.definition.DIResource$$anon$11.acquire(DIResource.scala:676)
// 		at izumi.distage.model.definition.DIResource$DIResourceUse$.$anonfun$use$extension$1(DIResource.scala:144)
// 		at izumi.distage.model.effect.DIEffect$$anon$1.bracket(DIEffect.scala:83)
// 		at izumi.distage.model.Injector.produceRunF(Injector.scala:52)
// 		at izumi.distage.model.Injector.produceRunF$(Injector.scala:51)
// 		at izumi.distage.InjectorDefaultImpl.produceRunF(InjectorDefaultImpl.scala:15)
// 		at izumi.distage.model.Injector.produceRun(Injector.scala:156)
// 		at izumi.distage.model.Injector.produceRun$(Injector.scala:156)
// 		at izumi.distage.InjectorDefaultImpl.produceRun(InjectorDefaultImpl.scala:15)
// 		at repl.MdocSession$App25$$anonfun$65.apply$mcV$sp(advanced-features.md:370)
// 		at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 		at repl.MdocSession$App25$$anonfun$65.apply(advanced-features.md:370)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.crash(DocumentBuilder.scala:69)
// 		at repl.MdocSession$App25.<init>(advanced-features.md:370)
// 		at repl.MdocSession$App22$.<clinit>(advanced-features.md:324)
// 		at repl.MdocSession$App18$.<clinit>(advanced-features.md:277)
// 		at repl.MdocSession$App15.<init>(advanced-features.md:230)
// 		at repl.MdocSession$App11.<init>(advanced-features.md:176)
// 		at repl.MdocSession$App6$.<clinit>(advanced-features.md:131)
// 		at repl.MdocSession$App4$.<clinit>(advanced-features.md:91)
// 		at repl.MdocSession$App0.<init>(advanced-features.md:51)
// 		at repl.MdocSession$App.<init>(advanced-features.md:5)
// 		at repl.MdocSession$.app(advanced-features.md:3)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:82)
// 		at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 		at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 		at scala.Console$.withErr(Console.scala:193)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:82)
// 		at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
// 		at scala.util.DynamicVariable.withValue(DynamicVariable.scala:59)
// 		at scala.Console$.withOut(Console.scala:164)
// 		at mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:81)
// 		at mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44)
// 		at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:186)
// 		at mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:153)
// 		at mdoc.internal.markdown.Processor.processDocument(Processor.scala:52)
// 		at mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:132)
// 		at mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82)
// 		at mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110)
// 		at mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:157)
// 		at scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:168)
// 		at scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:164)
// 		at scala.collection.immutable.List.foldLeft(List.scala:79)
// 		at mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155)
// 		at mdoc.internal.cli.MainOps.run(MainOps.scala:178)
// 		at mdoc.internal.cli.MainOps$.process(MainOps.scala:270)
// 		at mdoc.Main$.process(Main.scala:26)
// 		at mdoc.Main$.process(Main.scala:21)
// 		at mdoc.Main$.main(Main.scala:16)
// 		at mdoc.Main.main(Main.scala)
// 		at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// 		at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
// 		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
// 		at java.lang.reflect.Method.invoke(Method.java:498)
// 		at sbt.Run.invokeMain(Run.scala:115)
// 		at sbt.Run.execute$1(Run.scala:79)
// 		at sbt.Run.$anonfun$runWithLoader$4(Run.scala:92)
// 		at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
// 		at sbt.util.InterfaceUtil$$anon$1.get(InterfaceUtil.scala:10)
// 		at sbt.TrapExit$App.run(TrapExit.scala:257)
// 		at java.lang.Thread.run(Thread.java:748)

This will fail because while path1.A and p.A inside new ModuleDef are the same type, the varialbes path1 & p are spelled differently and this causes a mismatch.

There’s one way to workaround this - turn the type member A into a type parameter using the Aux Pattern, and then for that type parameter in turn, summon the type information using Tag implicit (as described in Tagless Final Style chapter) and summon the constructor using the ClassConstructor implicit, example:

import distage.{ClassConstructor, Roots, ModuleDef, Injector, Tag}

object Path {
  type Aux[A0] = Path { type A = A0 }
}

def pathModule[A: Tag: ClassConstructor](p: Path.Aux[A]) = new ModuleDef {
  make[A]
}

val path1 = new Path
// path1: Path = repl.MdocSession$App27$Path@40d1942d
val path2 = new Path
// path2: Path = repl.MdocSession$App27$Path@7bb6d52c

Injector()
  .produceRun(pathModule(path1) ++ pathModule(path2)) {
    (p1a: path1.A, p2a: path2.A) =>
      println((p1a, p2a))
  }
// (repl.MdocSession$App27$Path$A@5ba41df5,repl.MdocSession$App27$Path$A@793a3c35)

Now the example works, because the A inside pathModule is path1.A & path2.A respectively, the same as it is later in produceRun

Depending on Locator

Objects can depend on the outer object graph that contains them (Locator), by including a LocatorRef parameter:

import distage.{ModuleDef, LocatorRef, Injector, Roots}

class A(
  objects: LocatorRef
) {
  def c = objects.get.get[C]
}
class B
class C

def module = new ModuleDef {
  make[A]
  make[B]
  make[C]
}

val objects = Injector().produce(module, Roots.Everything).unsafeGet()
// objects: izumi.fundamentals.platform.functional.package.Identity[izumi.distage.model.Locator] = izumi.distage.LocatorDefaultImpl@27d6cbcc

// A took C from the object graph

objects.get[A].c
// res30: C = repl.MdocSession$App29$C@73a7f2c4

// this C is the same C as in this `objects` value

val thisC = objects.get[C]
// thisC: C = repl.MdocSession$App29$C@73a7f2c4
val thatC = objects.get[A].c
// thatC: C = repl.MdocSession$App29$C@73a7f2c4

assert(thisC == thatC)

Locator contains metadata about the plan and the bindings from which it was ultimately created:

import distage.{OrderedPlan, ModuleBase}

// Plan that created this locator (after GC)

val plan: OrderedPlan = objects.plan
// plan: OrderedPlan = 
// {type.LocatorRef} (advanced-features.md:440) := import {type.izumi.distage.model.recursive.LocatorRef} // required for {type.MdocSession::App29::A}
// {type.Activation} (InjectorDefaultImpl.scala:67) := value izumi.distage.model.definition.Activation#-1609326920
// {type.MdocSession::App29::B} (advanced-features.md:441) := call(Class(): MdocSession::App29::B) {}
// {type.MdocSession::App29::C} (advanced-features.md:442) := call(Class(): MdocSession::App29::C) {}
// {type.InjectorFactory} (InjectorDefaultImpl.scala:65) := value distage.Injector$#1869607024
// {type.BootstrapModule} (InjectorDefaultImpl.scala:66) := value izumi.distage.model.definition.BootstrapModule$$anon$1#383284250
// {type.PlannerInput} (InjectorDefaultImpl.scala:64) := value izumi.distage.model.PlannerInput#-43881630
// {type.MdocSession::App29::A} (advanced-features.md:440) := call(Class(LocatorRef): MdocSession::App29::A) {
//   arg objects: LocatorRef = lookup({type.LocatorRef})
// }
// {type.Bootloader} (InjectorDefaultImpl.scala:68) := call(Class(BootstrapModule, Activation, PlannerInput, InjectorFactory): Bootloader) {
//   arg bootstrapModule: BootstrapModule = lookup({type.BootstrapModule})
//   arg activation: Activation = lookup({type.Activation})
//   arg input: PlannerInput = lookup({type.PlannerInput})
//   arg injectorFactory: InjectorFactory = lookup({type.InjectorFactory})
// }

// Bindings from which the Plan was built (after GC)

val bindings: ModuleBase = plan.definition
// bindings: ModuleBase = 
// make[{type.repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.B}].from(call(Class(): repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.B)) ((advanced-features.md:441))
// make[{type.repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.A}].from(call(Class(izumi.distage.model.recursive.LocatorRef): repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.A)) ((advanced-features.md:440))
// make[{type.izumi.distage.model.PlannerInput}].from(value(PlannerInput(
// make[{type.repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.A}].from(call(Class(izumi.distage.model.recursive.LocatorRef): repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.A)) ((advanced-features.md:440))
// make[{type.repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.B}].from(call(Class(): repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.B)) ((advanced-features.md:441))
// make[{type.repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.C}].from(call(Class(): repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.C)) ((advanced-features.md:442)),Everything): izumi.distage.model.PlannerInput)) ((InjectorDefaultImpl.scala:64))
// make[{type.repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.C}].from(call(Class(): repl.MdocSession::repl.MdocSession.App29::repl.MdocSession.App29.C)) ((advanced-features.md:442))
// make[{type.izumi.distage.InjectorFactory}].from(value(distage.Injector$@6f6ff070: izumi.distage.InjectorFactory)) ((InjectorDefaultImpl.scala:65))
// make[{type.izumi.distage.model.recursive.Bootloader}].from(call(Class(izumi.distage.model.definition.BootstrapModule, izumi.distage.model.definition.Activation, izumi.distage.model.PlannerInput, izumi.distage.InjectorFactory): izumi.distage.model.recursive.Bootloader)) ((InjectorDefaultImpl.scala:68))
// make[{type.izumi.distage.model.definition.Activation}].from(value(Activation(Map()): izumi.distage.model.definition.Activation)) ((InjectorDefaultImpl.scala:67))
// make[{type.izumi.distage.model.definition.BootstrapModule}].from(value(
// make[{type.izumi.distage.model.planning.PlanningHook}].from(call(Class(scala.collection.immutable.Set[=PlanningHook]): izumi.distage.planning.PlanningHookAggregate)) ((BootstrapLocator.scala:153))
// make[{type.izumi.distage.model.provisioning.strategies.SetStrategy}].from(call(Class(): izumi.distage.provisioning.strategies.SetStrategyDefaultImpl)) ((BootstrapLocator.scala:140))
// make[{type.izumi.distage.planning.BindingTranslator}].from(call(Class(izumi.distage.model.planning.PlanningHook): izumi.distage.planning.BindingTranslator::izumi.distage.planning.BindingTranslator.Impl)) ((BootstrapLocator.scala:155))
// make[{type.izumi.distage.model.provisioning.strategies.ProviderStrategy}].from(call(Class(): izumi.distage.provisioning.strategies.ProviderStrategyDefaultImpl)) ((BootstrapLocator.scala:141))
// make[{type.izumi.distage.model.planning.PlanAnalyzer}].from(call(Class(): izumi.distage.planning.PlanAnalyzerDefaultImpl)) ((BootstrapLocator.scala:135))
// make[{type.izumi.distage.model.provisioning.strategies.ProxyStrategy}].from(call(Class(izumi.distage.model.provisioning.proxies.ProxyProvider, izumi.distage.model.reflection.MirrorProvider): izumi.distage.provisioning.strategies.ProxyStrategyDefaultImpl)) ((BootstrapLocator.scala:157))
// make[{type.izumi.distage.model.provisioning.ProvisioningFailureInterceptor}].from(call(Class(): izumi.distage.model.provisioning.ProvisioningFailureInterceptor::izumi.distage.model.provisioning.ProvisioningFailureInterceptor.DefaultImpl)) ((BootstrapLocator.scala:147))
// make[{type.izumi.distage.model.reflection.MirrorProvider}].from(value(izumi.distage.model.reflection.MirrorProvider$Impl$@62fa5eb7: izumi.distage.model.reflection.MirrorProvider::izumi.distage.model.reflection.MirrorProvider.Impl)) ((BootstrapLocator.scala:132))
// make[{type.izumi.distage.model.definition.Activation}].from(value(Activation(Map()): izumi.distage.model.definition.Activation)) ((BootstrapLocator.scala:34))
// make[{type.izumi.distage.model.provisioning.strategies.EffectStrategy}].from(call(Class(): izumi.distage.provisioning.strategies.EffectStrategyDefaultImpl)) ((BootstrapLocator.scala:144))
// make[{type.izumi.distage.model.provisioning.PlanInterpreter}].from(call(Class(izumi.distage.model.provisioning.strategies.SetStrategy, izumi.distage.model.provisioning.strategies.ProxyStrategy, izumi.distage.model.provisioning.strategies.ProviderStrategy, izumi.distage.model.provisioning.strategies.ImportStrategy, izumi.distage.model.provisioning.strategies.InstanceStrategy, izumi.distage.model.provisioning.strategies.EffectStrategy, izumi.distage.model.provisioning.strategies.ResourceStrategy, izumi.distage.model.provisioning.ProvisioningFailureInterceptor, izumi.distage.provisioning.ProvisionOperationVerifier, scala.Boolean): izumi.distage.provisioning.PlanInterpreterDefaultRuntimeImpl)) ((BootstrapLocator.scala:146))
// make[{type.izumi.distage.provisioning.ProvisionOperationVerifier}].from(call(Class(izumi.distage.model.reflection.MirrorProvider): izumi.distage.provisioning.ProvisionOperationVerifier::izumi.distage.provisioning.ProvisionOperationVerifier.Default)) ((BootstrapLocator.scala:130))
// make[{type.izumi.distage.model.planning.SanityChecker}].from(call(Class(izumi.distage.model.planning.PlanAnalyzer): izumi.distage.planning.SanityCheckerDefaultImpl)) ((BootstrapLocator.scala:138))
// make[{type.izumi.distage.model.provisioning.strategies.ResourceStrategy}].from(call(Class(): izumi.distage.provisioning.strategies.ResourceStrategyDefaultImpl)) ((BootstrapLocator.scala:145))
// make[{type.izumi.distage.model.provisioning.strategies.InstanceStrategy}].from(call(Class(): izumi.distage.provisioning.strategies.InstanceStrategyDefaultImpl)) ((BootstrapLocator.scala:143))
// many[{type.scala.collection.immutable.Set[=PlanningHook]}] ((BootstrapLocator.scala:150))
// make[{type.izumi.distage.model.provisioning.proxies.ProxyProvider}].from(call(Class(): izumi.distage.provisioning.strategies.cglib.CglibProxyProvider)) ((CglibBootstrap.scala:11))
// many[{type.scala.collection.immutable.Set[=PlanningObserver]}] ((BootstrapLocator.scala:149))
// make[{type.izumi.distage.model.planning.DIGarbageCollector}].from(call(Singleton(): izumi.distage.planning.gc.TracingDIGC)) ((BootstrapLocator.scala:133))
// make[{type.izumi.distage.model.Planner}].from(call(Class(izumi.distage.model.planning.ForwardingRefResolver, izumi.distage.model.planning.SanityChecker, izumi.distage.model.planning.DIGarbageCollector, izumi.distage.model.planning.PlanningObserver, izumi.distage.model.planning.PlanMergingPolicy, izumi.distage.model.planning.PlanningHook, izumi.distage.planning.BindingTranslator, izumi.distage.model.planning.PlanAnalyzer, izumi.distage.model.reflection.MirrorProvider): izumi.distage.planning.PlannerDefaultImpl)) ((BootstrapLocator.scala:139))
// make[{type.izumi.distage.model.planning.ForwardingRefResolver}].from(call(Class(izumi.distage.model.planning.PlanAnalyzer, scala.Boolean): izumi.distage.planning.ForwardingRefResolverDefaultImpl)) ((BootstrapLocator.scala:137))
// make[{type.scala.Boolean@izumi.distage.interpreter.full-stacktraces}].from(value(true: scala.Boolean)) ((BootstrapLocator.scala:128))
// make[{type.izumi.distage.model.provisioning.strategies.ImportStrategy}].from(call(Class(): izumi.distage.provisioning.strategies.ImportStrategyDefaultImpl)) ((BootstrapLocator.scala:142))
// make[{type.izumi.distage.model.planning.PlanMergingPolicy}].from(call(Class(izumi.distage.model.definition.Activation): izumi.distage.planning.PruningPlanMergingPolicyDefaultImpl)) ((BootstrapLocator.scala:136))
// make[{type.izumi.distage.model.planning.PlanningObserver}].from(call(Class(scala.collection.immutable.Set[=PlanningObserver]): izumi.distage.planning.PlanningObserverAggregate)) ((BootstrapLocator.scala:152))
// make[{type.scala.Boolean@distage.init-proxies-asap}].from(value(true: scala.Boolean)) ((BootstrapLocator.scala:127)): izumi.distage.model.definition.BootstrapModule)) ((InjectorDefaultImpl.scala:66))

The plan and bindings in Locator are saved in the state they were AFTER Garbage Collection has been performed. Objects can request the original input via a PlannerInput parameter:

import distage.{DIKey, Roots, ModuleDef, PlannerInput, Injector}

class InjectionInfo(val plannerInput: PlannerInput)

val module = new ModuleDef {
  make[InjectionInfo]
}
// module: AnyRef with ModuleDef = 
// make[{type.repl.MdocSession::repl.MdocSession.App32::repl.MdocSession.App32.InjectionInfo}].from(call(Class(izumi.distage.model.PlannerInput): repl.MdocSession::repl.MdocSession.App32::repl.MdocSession.App32.InjectionInfo)) ((advanced-features.md:486))

val input = PlannerInput(module, Roots(root = DIKey[InjectionInfo]))
// input: PlannerInput = PlannerInput(
// make[{type.repl.MdocSession::repl.MdocSession.App32::repl.MdocSession.App32.InjectionInfo}].from(call(Class(izumi.distage.model.PlannerInput): repl.MdocSession::repl.MdocSession.App32::repl.MdocSession.App32.InjectionInfo)) ((advanced-features.md:486)),Of(NonEmptySet({type.repl.MdocSession::repl.MdocSession.App32::repl.MdocSession.App32.InjectionInfo})))

val injectionInfo = Injector().produce(input).unsafeGet().get[InjectionInfo]
// injectionInfo: InjectionInfo = repl.MdocSession$App32$InjectionInfo@20938c9f

// the PlannerInput in `InjectionInfo` is the same as `input`

assert(injectionInfo.plannerInput == input)

Bootloader is another summonable parameter that contains the above information in aggregate and lets you create another object graph from the same inputs as the current or with alterations.