Repository: 7mind/izumi
Pull request #749 (2019-11-26 19:10:47)

Update classgraph to 4.8.55
Updates [io.github.classgraph:classgraph](https://github.com/classgraph/classgraph) from 4.8.54 to 4.8.55.


I'll automatically update this PR to resolve conflicts as long as you don't change it yourself.

If you'd like to skip this version, you can just close this PR. If you have any feedback, just mention me in the comments below.

Have a fantastic day writing Scala!

<details>
<summary>Ignore future updates</summary>

Add this to your `.scala-steward.conf` file to ignore future updates of this dependency:
```
updates.ignore = [ { groupId = "io.github.classgraph", artifactId = "classgraph" } ]
```
</details>

labels: semver-patch


Patch:
diff --git a/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala
index 121a5e943..0c0277a80 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/InjectorDefaultImpl.scala
@@ -5,7 +5,7 @@ import izumi.distage.model.definition.DIResource.DIResourceBase
 import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.monadic.DIEffect
 import izumi.distage.model.plan.initial.PrePlan
-import izumi.distage.model.plan.{AbstractPlan, ExecutableOp, OrderedPlan, SemiPlan}
+import izumi.distage.model.plan.{OrderedPlan, SemiPlan}
 import izumi.distage.model.provisioning.PlanInterpreter
 import izumi.distage.model.provisioning.PlanInterpreter.{FailedProvision, FinalizersFilter}
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse
@@ -45,10 +45,6 @@ class InjectorDefaultImpl(parentContext: Locator) extends Injector {
     planner.truncate(plan, roots)
   }
 
-  override def merge[OpType <: ExecutableOp](a: AbstractPlan[OpType], b: AbstractPlan[OpType]): OrderedPlan = {
-    planner.merge(a, b)
-  }
-
   override protected[distage] def produceFX[F[_] : TagK : DIEffect](plan: OrderedPlan, filter: FinalizersFilter[F]): DIResourceBase[F, Locator] = {
     produceDetailedFX[F](plan, filter).evalMap(_.throwOnFailure())
   }
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala
index b70fbb3ae..ecd458ea7 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/ForwardingRefResolverDefaultImpl.scala
@@ -53,7 +53,7 @@ class ForwardingRefResolverDefaultImpl
     }
 
     val imports = plan.steps.collect({ case i: ImportDependency => i })
-    OrderedPlan(imports ++ proxyOps, plan.gcMode, plan.topology)
+    OrderedPlan(imports ++ proxyOps, plan.declaredRoots, plan.topology)
   }
 
   protected def initProxiesAtTheEnd(proxies: List[ProxyOp.MakeProxy], resolvedSteps: Seq[ExecutableOp]): Seq[ExecutableOp] = {
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
index 14472be97..8ada72deb 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/PlannerDefaultImpl.scala
@@ -35,11 +35,9 @@ final class PlannerDefaultImpl
     if (roots.isEmpty) {
       OrderedPlan.empty
     } else {
-      println(roots)
-      println(plan.index.keySet)
       assert(roots.diff(plan.index.keySet).isEmpty)
       val collected = new TracingDIGC(roots, plan.index, ignoreMissingDeps = false).gc(plan.steps)
-      OrderedPlan(collected.nodes, GCMode.GCRoots(roots), analyzer.topology(collected.nodes))
+      OrderedPlan(collected.nodes, roots, analyzer.topology(collected.nodes))
     }
   }
 
@@ -58,7 +56,7 @@ final class PlannerDefaultImpl
       .get
   }
 
-  override def rewrite(module: ModuleBase): ModuleBase= {
+  override def rewrite(module: ModuleBase): ModuleBase = {
     hook.hookDefinition(module)
   }
 
@@ -70,13 +68,8 @@ final class PlannerDefaultImpl
       .get
   }
 
-  // TODO: add tests
-  override def merge[OpType <: ExecutableOp](a: AbstractPlan[OpType], b: AbstractPlan[OpType]): OrderedPlan = {
-    order(SemiPlan((a.toSemi.steps ++ b.toSemi.steps).toVector, a.gcMode ++ b.gcMode))
-  }
-
   override def prepare(input: PlannerInput): PrePlan = {
-      input.bindings.bindings.foldLeft(PrePlan.empty(input.bindings, input.mode)) {
+    input.bindings.bindings.foldLeft(PrePlan.empty(input.bindings, input.mode)) {
       case (currentPlan, binding) =>
         Value(bindingTranslator.computeProvisioning(currentPlan, binding))
           .eff(sanityChecker.assertProvisionsSane)
@@ -199,7 +192,13 @@ final class PlannerDefaultImpl
 
     val sortedOps = sortedKeys.flatMap(k => index.get(k).toSeq)
 
-    OrderedPlan(sortedOps.toVector, completedPlan.gcMode, topology)
+    val roots = completedPlan.gcMode match {
+      case GCMode.GCRoots(roots) =>
+        roots
+      case GCMode.NoGC =>
+        topology.effectiveRoots
+    }
+    OrderedPlan(sortedOps.toVector, roots, topology)
   }
 
   private[this] def hasByNameParameter(fsto: ExecutableOp): Boolean = {
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala
index 5027eb068..74fc5ae40 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/SanityCheckerDefaultImpl.scala
@@ -31,8 +31,7 @@ class SanityCheckerDefaultImpl
       throw new MissingRefException(s"Cannot finish the plan, there are missing references: $missingRefs in ${fullRefTable.dependencies}!", missingRefs, Some(fullRefTable))
     }
 
-    val roots = plan.gcMode.toSet
-    val missingRoots = roots.diff(plan.keys)
+    val missingRoots = plan.declaredRoots.diff(plan.keys)
     if (missingRoots.nonEmpty) {
       throw new MissingRootsException(s"Missing GC roots in final plan, check if there were any conflicts: $missingRoots", missingRoots)
     }
diff --git a/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala b/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala
index a597e7c37..a759996a0 100644
--- a/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala
+++ b/distage/distage-core/src/main/scala/izumi/distage/planning/extensions/GraphDumpObserver.scala
@@ -4,16 +4,16 @@ import java.nio.charset.StandardCharsets
 import java.nio.file.{Files, Paths}
 import java.util.concurrent.atomic.AtomicReference
 
+import distage._
 import izumi.distage.model.plan.ExecutableOp.{MonadicOp, ProxyOp}
-import izumi.distage.model.plan.{GCMode, OrderedPlan => _, SemiPlan => _, _}
+import izumi.distage.model.plan.initial.PrePlan
+import izumi.distage.model.plan.repr.KeyMinimizer
+import izumi.distage.model.plan.{OrderedPlan => _, SemiPlan => _, _}
 import izumi.distage.model.planning.{PlanAnalyzer, PlanningObserver}
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse
 import izumi.distage.planning.extensions.GraphDumpObserver.RenderedDot
 import izumi.fundamentals.graphs.dotml.Digraph
 import izumi.fundamentals.platform.language.Quirks._
-import distage._
-import izumi.distage.model.plan.initial.PrePlan
-import izumi.distage.model.plan.repr.KeyMinimizer
 
 import scala.collection.mutable
 
@@ -85,12 +85,7 @@ final class GraphDumpObserver
     val missingKeysSeq = missingKeys.toSeq
 
     val km = new KeyMinimizer(goodKeys ++ originalKeys)
-    val roots = finalPlan.gcMode match {
-      case GCMode.GCRoots(roots) =>
-        roots
-      case GCMode.NoGC =>
-        Set.empty[DIKey]
-    }
+    val roots = finalPlan.declaredRoots
 
     goodKeys.foreach {
       k =>
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/PlannerExtendedAPI.scala b/distage/distage-model/src/main/scala/izumi/distage/model/PlannerExtendedAPI.scala
index 141d9ad70..9a72ee91c 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/PlannerExtendedAPI.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/PlannerExtendedAPI.scala
@@ -1,10 +1,7 @@
 package izumi.distage.model
 
-import izumi.distage.model.plan.{AbstractPlan, ExecutableOp, OrderedPlan}
 import izumi.distage.model.planning.PlanSplitter
 
 trait PlannerExtendedAPI extends PlanSplitter {
   this: Planner =>
-
-  def merge[OpType <: ExecutableOp](a: AbstractPlan[OpType], b: AbstractPlan[OpType]): OrderedPlan
 }
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/definition/LocatorDef.scala b/distage/distage-model/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
index 47c05b16e..76cf9d9a5 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/definition/LocatorDef.scala
@@ -59,7 +59,7 @@ trait LocatorDef
         ReferenceInstance(key, Instance(key.tpe, value), origin)
     }.toVector
 
-    OrderedPlan(ops, GCMode.NoGC, topology)
+    OrderedPlan(ops, ops.map(_.target).toSet, topology)
   }
 
   override def parent: Option[Locator] = None
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala b/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala
index 6209a9fb8..44d3c2ebe 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlan.scala
@@ -4,17 +4,15 @@ import izumi.distage.model.definition.ModuleBase
 import izumi.distage.model.plan.ExecutableOp.SemiplanOp
 import izumi.distage.model.plan.impl.{AbstractPlanOps, OrderedPlanExtensions, OrderedPlanOps, PlanLazyOps, SemiPlanExtensions, SemiPlanOps}
 import izumi.distage.model.plan.topology.PlanTopology
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse
+import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 
 
 sealed trait AbstractPlan[OpType <: ExecutableOp] extends AbstractPlanExtendedAPI[OpType] {
   def definition: ModuleBase
 
-  def gcMode: GCMode
-
   def steps: Seq[OpType]
 
-  def index: Map[RuntimeDIUniverse.DIKey, OpType]
+  def index: Map[DIKey, OpType]
 
   override def toString: String = {
     steps.map(_.toString).mkString("\n")
@@ -45,7 +43,7 @@ object SemiPlan extends SemiPlanExtensions
   */
 final case class OrderedPlan(
                               steps: Vector[ExecutableOp],
-                              gcMode: GCMode,
+                              declaredRoots: Set[DIKey],
                               topology: PlanTopology
                             ) extends ExtendedPlan[ExecutableOp] with OrderedPlanOps
 
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala b/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala
index 47402b9f6..9b5e5420a 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/plan/AbstractPlanExtendedAPI.scala
@@ -1,8 +1,7 @@
 package izumi.distage.model.plan
 
 import izumi.distage.model.Locator
-import izumi.distage.model.plan.ExecutableOp.ProxyOp.{InitProxy, MakeProxy}
-import izumi.distage.model.plan.ExecutableOp.{ImportDependency, ProxyOp, SemiplanOp}
+import izumi.distage.model.plan.ExecutableOp.{ImportDependency, SemiplanOp}
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 
 trait AbstractPlanExtendedAPI[OpType <: ExecutableOp] {
@@ -66,18 +65,6 @@ trait AbstractPlanExtendedAPI[OpType <: ExecutableOp] {
     steps.foldLeft(z)(f)
   }
 
-  def toSemi: SemiPlan = {
-    val safeSteps: Seq[SemiplanOp] = steps.flatMap{
-      case s: SemiplanOp =>
-        Seq(s)
-      case s: ProxyOp =>
-        s match {
-          case m: MakeProxy =>
-            Seq(m.op)
-          case _: InitProxy =>
-            Seq.empty
-        }
-    }
-    SemiPlan(safeSteps.toVector, gcMode)
-  }
+  def toSemi: SemiPlan
+
 }
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/plan/GCMode.scala b/distage/distage-model/src/main/scala/izumi/distage/model/plan/GCMode.scala
index c4d7d45d3..339a483d9 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/plan/GCMode.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/plan/GCMode.scala
@@ -4,18 +4,19 @@ import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 
 sealed trait GCMode {
   def toSet: Set[DIKey]
-
-  final def ++(that: GCMode): GCMode = (this, that) match {
-    case (GCMode.NoGC, _) => GCMode.NoGC
-    case (_, GCMode.NoGC) => GCMode.NoGC
-    case (GCMode.GCRoots(aRoots), GCMode.GCRoots(bRoots)) =>
-      GCMode.GCRoots(aRoots ++ bRoots)
-  }
 }
 
 object GCMode {
   def apply(key: DIKey, more: DIKey*): GCMode = GCRoots(more.toSet + key)
 
+  def fromSet(roots: Set[DIKey]): GCMode = {
+    if (roots.isEmpty) {
+      NoGC
+    } else {
+      GCRoots(roots)
+    }
+  }
+
   final case class GCRoots(roots: Set[DIKey]) extends GCMode {
     assert(roots.nonEmpty, "GC roots set cannot be empty")
 
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/plan/TriSplittedPlan.scala b/distage/distage-model/src/main/scala/izumi/distage/model/plan/TriSplittedPlan.scala
index 587b02f78..f51b29985 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/plan/TriSplittedPlan.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/plan/TriSplittedPlan.scala
@@ -1,24 +1,20 @@
 package izumi.distage.model.plan
 
-import izumi.distage.model.plan.TriSplittedPlan.Subplan
-import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 import izumi.fundamentals.platform.strings.IzString._
 
 case class TriSplittedPlan(
-                            side: Subplan,
-                            primary: Subplan,
-                            shared: Subplan,
+                            side: OrderedPlan,
+                            primary: OrderedPlan,
+                            shared: OrderedPlan,
                           )
 
 object TriSplittedPlan {
-  case class Subplan(plan: OrderedPlan, roots: Set[DIKey])
-
   implicit class TriPlanEx(split: TriSplittedPlan) {
     def render(): String = {
       Seq(
-        split.shared.plan.render().listing("Shared Plan"),
-        split.side.plan.render().listing("Side Plan"),
-        split.primary.plan.render().listing("Primary Plan"),
+        split.shared.render().listing("Shared Plan"),
+        split.side.render().listing("Side Plan"),
+        split.primary.render().listing("Primary Plan"),
       ).mkString("\n")
     }
   }
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanExtensions.scala b/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanExtensions.scala
index 4ccd41503..2bb8e73c3 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanExtensions.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanExtensions.scala
@@ -2,14 +2,12 @@ package izumi.distage.model.plan.impl
 
 import cats.Applicative
 import izumi.distage.model.plan.ExecutableOp.{ImportDependency, SemiplanOp}
-import izumi.distage.model.plan.{ExecutableOp, GCMode, OrderedPlan, SemiPlan}
 import izumi.distage.model.plan.impl.OrderedPlanExtensions.{OrderedPlanExts, OrderedPlanSyntax}
-import SemiPlanOrderedPlanInstances.resolveImportsImpl
+import izumi.distage.model.plan.impl.SemiPlanOrderedPlanInstances.resolveImportsImpl
 import izumi.distage.model.plan.repr.{CompactPlanFormatter, DepTreeRenderer}
 import izumi.distage.model.plan.topology.DepTreeNode.DepNode
-import izumi.distage.model.plan.topology.DependencyGraph
-import izumi.distage.model.plan.topology.DependencyGraph.DependencyKind
-import izumi.distage.model.plan.topology.PlanTopology.PlanTopologyImmutable
+import izumi.distage.model.plan.topology.PlanTopology
+import izumi.distage.model.plan.{ExecutableOp, GCMode, OrderedPlan, SemiPlan}
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 import izumi.functional.Renderable
 
@@ -18,7 +16,7 @@ import scala.language.implicitConversions
 trait OrderedPlanExtensions {
   implicit val defaultFormatter: Renderable[OrderedPlan] = CompactPlanFormatter.OrderedPlanFormatter
 
-  def empty: OrderedPlan = OrderedPlan(Vector.empty, GCMode.NoGC, PlanTopologyImmutable(DependencyGraph(Map.empty, DependencyKind.Depends), DependencyGraph(Map.empty, DependencyKind.Required)))
+  def empty: OrderedPlan = OrderedPlan(Vector.empty, Set.empty, PlanTopology.empty)
 
   @inline implicit final def toPlanSyntax(plan: OrderedPlan): OrderedPlanSyntax = new OrderedPlanSyntax(plan)
   @inline implicit final def toOrderedPlanExts(plan: OrderedPlan): OrderedPlanExts = new OrderedPlanExts(plan)
@@ -43,10 +41,10 @@ private[plan] object OrderedPlanExtensions {
     import cats.syntax.traverse._
 
     def traverse[F[_] : Applicative](f: ExecutableOp => F[SemiplanOp]): F[SemiPlan] =
-      plan.steps.traverse(f).map(SemiPlan(_, plan.gcMode))
+      plan.steps.traverse(f).map(SemiPlan(_, GCMode.fromSet(plan.declaredRoots)))
 
     def flatMapF[F[_] : Applicative](f: ExecutableOp => F[Seq[SemiplanOp]]): F[SemiPlan] =
-      plan.steps.traverse(f).map(s => SemiPlan(s.flatten, plan.gcMode))
+      plan.steps.traverse(f).map(s => SemiPlan(s.flatten, GCMode.fromSet(plan.declaredRoots)))
 
     def resolveImportF[T]: ResolveImportFOrderedPlanPartiallyApplied[T] = new ResolveImportFOrderedPlanPartiallyApplied(plan)
 
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala b/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala
index 1f580df77..108c92561 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/plan/impl/OrderedPlanOps.scala
@@ -1,8 +1,9 @@
 package izumi.distage.model.plan.impl
 
 import izumi.distage.model.Locator
-import izumi.distage.model.plan.ExecutableOp.ImportDependency
-import izumi.distage.model.plan.{AbstractPlan, OrderedPlan}
+import izumi.distage.model.plan.ExecutableOp.ProxyOp.{InitProxy, MakeProxy}
+import izumi.distage.model.plan.ExecutableOp.{ImportDependency, ProxyOp, SemiplanOp}
+import izumi.distage.model.plan.{AbstractPlan, GCMode, OrderedPlan, SemiPlan}
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 
 trait OrderedPlanOps {
@@ -13,11 +14,10 @@ trait OrderedPlanOps {
     * Proper usage assume that `keys` contains complete subgraph reachable from graph roots.
     */
   def replaceWithImports(keys: Set[DIKey]): OrderedPlan = {
-    val roots = gcMode.toSet
     val newSteps = steps.flatMap {
       case s if keys.contains(s.target) =>
         val dependees = topology.dependees.direct(s.target)
-        if (dependees.diff(keys).nonEmpty || roots.contains(s.target)) {
+        if (dependees.diff(keys).nonEmpty || declaredRoots.contains(s.target)) {
           val dependees = topology.dependees.transitive(s.target).diff(keys)
           Seq(ImportDependency(s.target, dependees, s.origin.toSynthetic))
         } else {
@@ -29,7 +29,7 @@ trait OrderedPlanOps {
 
     OrderedPlan(
       newSteps,
-      gcMode,
+      declaredRoots,
       topology.removeKeys(keys),
     )
   }
@@ -54,4 +54,19 @@ trait OrderedPlanOps {
   override def locateImports(locator: Locator): OrderedPlan = {
     resolveImports(Function.unlift(i => locator.lookupLocal[Any](i.target)))
   }
+
+  override def toSemi: SemiPlan = {
+    val safeSteps: Seq[SemiplanOp] = steps.flatMap{
+      case s: SemiplanOp =>
+        Seq(s)
+      case s: ProxyOp =>
+        s match {
+          case m: MakeProxy =>
+            Seq(m.op)
+          case _: InitProxy =>
+            Seq.empty
+        }
+    }
+    SemiPlan(safeSteps.toVector, GCMode.fromSet(declaredRoots))
+  }
 }
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala b/distage/distage-model/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala
index ec1ac4724..61d0672b4 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/plan/topology/PlanTopology.scala
@@ -1,5 +1,6 @@
 package izumi.distage.model.plan.topology
 
+import izumi.distage.model.plan.topology.DependencyGraph.DependencyKind
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 
 
@@ -26,10 +27,16 @@ sealed trait PlanTopology {
     * @return full set of all the keys transitively depending on key
     */
   def transitiveDependencies(key: DIKey): Set[DIKey] = dependencies.transitive(key)
+
+  def effectiveRoots: Set[DIKey] = {
+    dependees.graph.toSeq.filter(_._2.isEmpty).map(_._1).toSet
+  }
 }
 
 object PlanTopology {
 
+  def empty: PlanTopologyImmutable = PlanTopologyImmutable(DependencyGraph(Map.empty, DependencyKind.Depends), DependencyGraph(Map.empty, DependencyKind.Required))
+
   final case class PlanTopologyImmutable(
                                           dependees: DependencyGraph
                                           , dependencies: DependencyGraph
@@ -40,6 +47,8 @@ object PlanTopology {
         dependencies.dropDepsOf(keys),
       )
     }
+
+
   }
 
 }
\ No newline at end of file
diff --git a/distage/distage-model/src/main/scala/izumi/distage/model/planning/PlanSplitter.scala b/distage/distage-model/src/main/scala/izumi/distage/model/planning/PlanSplitter.scala
index 6803bc621..f278848c1 100644
--- a/distage/distage-model/src/main/scala/izumi/distage/model/planning/PlanSplitter.scala
+++ b/distage/distage-model/src/main/scala/izumi/distage/model/planning/PlanSplitter.scala
@@ -1,14 +1,13 @@
 package izumi.distage.model.planning
 
 import izumi.distage.model.definition.ModuleBase
-import izumi.distage.model.plan.TriSplittedPlan.Subplan
 import izumi.distage.model.plan.{OrderedPlan, TriSplittedPlan}
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse._
 import izumi.distage.model.{Planner, PlannerInput}
 
 trait PlanSplitter {
   this: Planner =>
-  final def trisectByPredicate(appModule: ModuleBase, primaryRoots: Set[DIKey])(extractSubRoots: OrderedPlan => Set[DIKey]): TriSplittedPlan = {
+  final def trisectByKeys(appModule: ModuleBase, primaryRoots: Set[DIKey])(extractSubRoots: OrderedPlan => Set[DIKey]): TriSplittedPlan = {
     val rewritten = rewrite(appModule)
     val basePlan = toSubplanNoRewrite(rewritten, primaryRoots)
 
@@ -18,11 +17,9 @@ trait PlanSplitter {
   }
 
   final def trisectByRoots(appModule: ModuleBase, primaryRoots: Set[DIKey], subplanRoots: Set[DIKey]): TriSplittedPlan = {
-    val basePlan = toSubplanNoRewrite(appModule, primaryRoots)
-    trisect(appModule, basePlan, primaryRoots, subplanRoots)
+    trisectByKeys(appModule, primaryRoots)(_ => subplanRoots)
   }
 
-
   private final def trisect(appModule: ModuleBase, baseplan: OrderedPlan, primaryRoots: Set[DIKey], subplanRoots: Set[DIKey]): TriSplittedPlan = {
     assert(primaryRoots.diff(baseplan.keys).isEmpty)
     val extractedSubplan = truncateOrReplan(appModule, baseplan, subplanRoots)
@@ -33,10 +30,14 @@ trait PlanSplitter {
     val primplan = baseplan.replaceWithImports(sharedKeys)
     val subplan = extractedSubplan.replaceWithImports(sharedKeys)
 
+    assert(subplan.declaredRoots == subplanRoots)
+    assert(primplan.declaredRoots == primaryRoots)
+    assert(sharedPlan.declaredRoots == sharedKeys)
+
     TriSplittedPlan(
-      Subplan(subplan, subplanRoots),
-      Subplan(primplan, primaryRoots),
-      Subplan(sharedPlan, sharedKeys),
+      subplan,
+      primplan,
+      sharedPlan,
     )
   }
 
diff --git a/distage/distage-roles/src/main/scala/izumi/distage/roles/RoleAppLauncher.scala b/distage/distage-roles/src/main/scala/izumi/distage/roles/RoleAppLauncher.scala
index 3659da2f6..22055d986 100644
--- a/distage/distage-roles/src/main/scala/izumi/distage/roles/RoleAppLauncher.scala
+++ b/distage/distage-roles/src/main/scala/izumi/distage/roles/RoleAppLauncher.scala
@@ -91,7 +91,7 @@ abstract class RoleAppLauncherImpl[F[_]: TagK: DIEffect] extends RoleAppLauncher
     val appModule = moduleProvider.appModules().merge overridenBy defApp overridenBy appOverride
     val planner = makePlanner(options, bsModule, activation, lateLogger)
     val appPlan = planner.makePlan(roots, appModule)
-    lateLogger.info(s"Planning finished. ${appPlan.app.primary.plan.keys.size -> "main ops"}, ${appPlan.app.side.plan.keys.size -> "integration ops"}, ${appPlan.app.shared.plan.keys.size -> "shared ops"}, ${appPlan.runtime.keys.size -> "runtime ops"}")
+    lateLogger.info(s"Planning finished. ${appPlan.app.primary.keys.size -> "main ops"}, ${appPlan.app.side.keys.size -> "integration ops"}, ${appPlan.app.shared.keys.size -> "shared ops"}, ${appPlan.runtime.keys.size -> "runtime ops"}")
 
     val injector = appPlan.injector
     val r = makeExecutor(parameters, roles, lateLogger, makeStartupExecutor(lateLogger, injector))
diff --git a/distage/distage-roles/src/main/scala/izumi/distage/roles/internal/ConfigWriter.scala b/distage/distage-roles/src/main/scala/izumi/distage/roles/internal/ConfigWriter.scala
index 0799e2cfb..99ceb117c 100644
--- a/distage/distage-roles/src/main/scala/izumi/distage/roles/internal/ConfigWriter.scala
+++ b/distage/distage-roles/src/main/scala/izumi/distage/roles/internal/ConfigWriter.scala
@@ -136,14 +136,14 @@ class ConfigWriter[F[_] : DIEffect]
       getConfig(plan) getOrElse ConfigFactory.empty()
     }
 
-    if (plans.app.primary.plan.steps.exists(_.target == roleDIKey)) {
-      val cfg = getConfig(plans.app.primary.plan)
-        .orElse(getConfig(plans.app.shared.plan))
-        .orElse(getConfig(plans.app.side.plan))
+    if (plans.app.primary.steps.exists(_.target == roleDIKey)) {
+      val cfg = getConfig(plans.app.primary)
+        .orElse(getConfig(plans.app.shared))
+        .orElse(getConfig(plans.app.side))
 
       cfg
-        .map(_.withFallback(getConfigOrEmpty(plans.app.side.plan)))
-        .map(_.withFallback(getConfigOrEmpty(plans.app.shared.plan)))
+        .map(_.withFallback(getConfigOrEmpty(plans.app.side)))
+        .map(_.withFallback(getConfigOrEmpty(plans.app.shared)))
         .map(_.withFallback(getConfigOrEmpty(plans.runtime)))
     } else {
       logger.warn(s"$roleDIKey is not in the refined plan")
diff --git a/distage/distage-roles/src/main/scala/izumi/distage/roles/services/RoleAppPlanner.scala b/distage/distage-roles/src/main/scala/izumi/distage/roles/services/RoleAppPlanner.scala
index aa512b3ea..c3d8a34bd 100644
--- a/distage/distage-roles/src/main/scala/izumi/distage/roles/services/RoleAppPlanner.scala
+++ b/distage/distage-roles/src/main/scala/izumi/distage/roles/services/RoleAppPlanner.scala
@@ -50,22 +50,15 @@ object RoleAppPlanner {
 
       val runtimePlan = injector.plan(PlannerInput(fullAppModule, runtimeGcRoots))
 
-      val appPlan = injector.trisectByPredicate(fullAppModule.drop(runtimeGcRoots), appMainRoots) {
+      val appPlan = injector.trisectByKeys(fullAppModule.drop(runtimeGcRoots), appMainRoots) {
         _.collectChildren[IntegrationCheck].map(_.target).toSet
       }
 
       val check = new PlanCircularDependencyCheck(options, logger)
       check.verify(runtimePlan)
-      check.verify(appPlan.shared.plan)
-      check.verify(appPlan.side.plan)
-      check.verify(appPlan.primary.plan)
-
-//      import izumi.fundamentals.platform.strings.IzString._
-//      logger.error(s"${fullAppModule.bindings.niceList() -> "app module"}")
-//      logger.error(s"${runtimePlan.render() -> "runtime plan"}")
-//      logger.error(s"${appPlan.shared.plan.render() -> "shared plan"}")
-//      logger.error(s"${appPlan.side.plan.render() -> "integration plan"}")
-//      logger.error(s"${appPlan.primary.plan.render() -> "primary plan"}")
+      check.verify(appPlan.shared)
+      check.verify(appPlan.side)
+      check.verify(appPlan.primary)
 
       AppStartupPlans(
         runtimePlan,
diff --git a/distage/distage-roles/src/main/scala/izumi/distage/roles/services/StartupPlanExecutor.scala b/distage/distage-roles/src/main/scala/izumi/distage/roles/services/StartupPlanExecutor.scala
index 38fd5f771..bcfb2dfaa 100644
--- a/distage/distage-roles/src/main/scala/izumi/distage/roles/services/StartupPlanExecutor.scala
+++ b/distage/distage-roles/src/main/scala/izumi/distage/roles/services/StartupPlanExecutor.scala
@@ -41,21 +41,21 @@ object StartupPlanExecutor {
 
             runner.run {
               Injector.inherit(runtimeLocator)
-                .produceFX[F](appPlan.app.shared.plan, filters.filterF)
+                .produceFX[F](appPlan.app.shared, filters.filterF)
                 .use {
                   sharedLocator =>
 
 
                     Injector.inherit(sharedLocator)
-                      .produceFX[F](appPlan.app.side.plan, filters.filterF)
+                      .produceFX[F](appPlan.app.side, filters.filterF)
                       .use {
                         integrationLocator =>
-                          integrationChecker.checkOrFail(appPlan.app.side.roots, integrationLocator)
+                          integrationChecker.checkOrFail(appPlan.app.side.declaredRoots, integrationLocator)
                       }
                       .flatMap {
                         _ =>
                           Injector.inherit(sharedLocator)
-                            .produceFX[F](appPlan.app.primary.plan, filters.filterF)
+                            .produceFX[F](appPlan.app.primary, filters.filterF)
                             .use(doRun(_, effect))
                       }
                 }
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
index bd1896c44..b2e5345ac 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/impl/BIOZio.scala
@@ -20,6 +20,7 @@ class BIOZio[R] extends BIO[ZIO[R, +?, +?]] {
   @inline override final def pure[A](a: A): IO[Nothing, A] = ZIO.succeed(a)
   @inline override final def sync[A](effect: => A): IO[Nothing, A] = ZIO.effectTotal(effect)
   @inline override final def syncThrowable[A](effect: => A): IO[Throwable, A] = ZIO.effect(effect)
+  @inline override final def suspend[A](effect: => IO[Throwable, A]): IO[Throwable, A] = ZIO.effectSuspend(effect)
 
   @inline override final def fail[E](v: => E): IO[E, Nothing] = ZIO.effectTotal(v).flatMap[R, E, Nothing](ZIO.fail)
   @inline override final def terminate(v: => Throwable): IO[Nothing, Nothing] = ZIO.effectTotal(v).flatMap[R, Nothing, Nothing](ZIO.die)
diff --git a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
index 6c37f3472..bab4ca8bb 100644
--- a/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
+++ b/fundamentals/fundamentals-bio/src/main/scala/izumi/functional/bio/package.scala
@@ -172,6 +172,8 @@ package object bio extends BIOSyntax {
     @inline final def apply[A](effect: => A): F[Throwable, A] = syncThrowable(effect)
 
     // defaults
+    @inline def suspend[A](effect: => F[Throwable, A]): F[Throwable, A] = flatten(syncThrowable(effect))
+
     @inline override def fromEither[E, A](effect: => Either[E, A]): F[E, A] = flatMap(sync(effect)) {
       case Left(e) => fail(e): F[E, A]
       case Right(v) => pure(v): F[E, A]
diff --git a/fundamentals/fundamentals-thirdparty-boopickle-shaded/src/main/scala_2.12/izumi/thirdparty/internal/boopickle/XCompat.scala b/fundamentals/fundamentals-thirdparty-boopickle-shaded/src/main/scala_2.12/izumi/thirdparty/internal/boopickle/XCompat.scala
index 823d5969c..8e07e570f 100644
--- a/fundamentals/fundamentals-thirdparty-boopickle-shaded/src/main/scala_2.12/izumi/thirdparty/internal/boopickle/XCompat.scala
+++ b/fundamentals/fundamentals-thirdparty-boopickle-shaded/src/main/scala_2.12/izumi/thirdparty/internal/boopickle/XCompat.scala
@@ -1,8 +1,7 @@
 package izumi.thirdparty.internal.boopickle
 
-import Constants.NullRef
+import izumi.thirdparty.internal.boopickle.Constants.NullRef
 
-import collection.generic.CanBuildFrom
 import scala.collection.generic.CanBuildFrom
 import scala.language.higherKinds
 
diff --git a/project/Versions.scala b/project/Versions.scala
index bb8f032d7..87682dca7 100644
--- a/project/Versions.scala
+++ b/project/Versions.scala
@@ -12,7 +12,7 @@ object V {
   val cats = "2.0.0"
   val cats_effect = "2.0.0"
   val zio = "1.0.0-RC17"
-  val zio_interop_cats = "2.0.0.0-RC8"
+  val zio_interop_cats = "2.0.0.0-RC9"
 
   val circe = "0.12.3"
   val circe_generic_extras = "0.12.2"
@@ -30,7 +30,7 @@ object V {
   // java, we need it bcs http4s ws client isn't ready yet
   val asynchttpclient = "2.10.4"
 
-  val classgraph = "4.8.54"
+  val classgraph = "4.8.55"
   val slf4j = "1.7.29"
   val typesafe_config = "1.4.0"
 


Test patch:
diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/PlanOperationsTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/PlanOperationsTest.scala
index 991220ea4..d861a95e4 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/injector/PlanOperationsTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/injector/PlanOperationsTest.scala
@@ -32,21 +32,21 @@ class PlanOperationsTest extends WordSpec with MkInjector {
       make[SharedComponent2]
     }, primary ++ sub)
 
-    val split = injector.trisectByPredicate(definition.bindings, primary) {
+    val split = injector.trisectByKeys(definition.bindings, primary) {
       baseplan =>
         assert(sub.intersect(baseplan.index.keySet).isEmpty)
         sub
     }
 
-    assert(Set(sc0, sc1, sc2).diff(split.shared.plan.index.keySet).isEmpty)
+    assert(Set(sc0, sc1, sc2).diff(split.shared.index.keySet).isEmpty)
 
-    assert((primary ++ sub).intersect(split.shared.plan.index.keySet).isEmpty)
-    assert(primary.intersect(split.side.plan.index.keySet).isEmpty)
-    assert(sub.intersect(split.primary.plan.index.keySet).isEmpty)
+    assert((primary ++ sub).intersect(split.shared.index.keySet).isEmpty)
+    assert(primary.intersect(split.side.index.keySet).isEmpty)
+    assert(sub.intersect(split.primary.index.keySet).isEmpty)
 
-    assert(split.primary.plan.index.keySet.intersect(split.side.plan.index.keySet) == Set(sc2))
-    assert(split.primary.plan.index.keySet.intersect(split.shared.plan.index.keySet) == Set(sc2))
-    assert(split.side.plan.index.keySet.intersect(split.shared.plan.index.keySet) == Set(sc2))
+    assert(split.primary.index.keySet.intersect(split.side.index.keySet) == Set(sc2))
+    assert(split.primary.index.keySet.intersect(split.shared.index.keySet) == Set(sc2))
+    assert(split.side.index.keySet.intersect(split.shared.index.keySet) == Set(sc2))
   }
 
 
@@ -62,11 +62,11 @@ class PlanOperationsTest extends WordSpec with MkInjector {
       make[SharedComponent2]
     }, primary ++ sub)
 
-    val split = injector.trisectByPredicate(definition.bindings, primary)(_ => sub)
+    val split = injector.trisectByKeys(definition.bindings, primary)(_ => sub)
 
-    val sideIndex = split.side.plan.index
-    val primaryIndex = split.primary.plan.index
-    val sharedIndex = split.shared.plan.index
+    val sideIndex = split.side.index
+    val primaryIndex = split.primary.index
+    val sharedIndex = split.shared.index
 
     assert(primaryIndex.keySet.intersect(sideIndex.keySet).intersect(sharedIndex.keySet) == Set(icKey))
 
diff --git a/distage/distage-roles/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala b/distage/distage-roles/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
index dacbdfd28..f4b51ca72 100644
--- a/distage/distage-roles/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
+++ b/distage/distage-roles/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
@@ -115,10 +115,10 @@ class RoleAppTest extends WordSpec
 
       val plans = roleAppPlanner.makePlan(Set(DIKey.get[Set[Resource0]]), definition)
       Injector().produce(plans.runtime).use {
-        Injector.inherit(_).produce(plans.app.shared.plan).use {
-          Injector.inherit(_).produce(plans.app.side.plan).use {
+        Injector.inherit(_).produce(plans.app.shared).use {
+          Injector.inherit(_).produce(plans.app.side).use {
             locator =>
-              integrationChecker.checkOrFail(plans.app.side.roots, locator)
+              integrationChecker.checkOrFail(plans.app.side.declaredRoots, locator)
 
               assert(initCounter.startedCloseables.size == 3)
               assert(initCounter.checkedResources.size == 2)
@@ -150,10 +150,10 @@ class RoleAppTest extends WordSpec
 
       val plans = roleAppPlanner.makePlan(Set(DIKey.get[Set[Resource0]]), definition)
       Injector().produce(plans.runtime).use {
-        Injector.inherit(_).produce(plans.app.shared.plan).use {
-          Injector.inherit(_).produce(plans.app.side.plan).use {
+        Injector.inherit(_).produce(plans.app.shared).use {
+          Injector.inherit(_).produce(plans.app.side).use {
             locator =>
-              integrationChecker.checkOrFail(plans.app.side.roots, locator)
+              integrationChecker.checkOrFail(plans.app.side.declaredRoots, locator)
 
               assert(initCounter.startedCloseables.size == 3)
               assert(initCounter.checkedResources.size == 2)
diff --git a/distage/distage-testkit/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala b/distage/distage-testkit/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
index a9d36a2ca..8e7c6f38e 100644
--- a/distage/distage-testkit/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
+++ b/distage/distage-testkit/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
@@ -79,7 +79,7 @@ class DistageTestRunner[F[_] : TagK]
 
         logger.info(s"Memoized components in env $sharedKeys")
 
-        val shared = injector.trisectByPredicate(appModule.drop(runtimeGcRoots), sharedKeys) {
+        val shared = injector.trisectByKeys(appModule.drop(runtimeGcRoots), sharedKeys) {
           _.collectChildren[IntegrationCheck].map(_.target).toSet
         }
 
@@ -94,12 +94,12 @@ class DistageTestRunner[F[_] : TagK]
 
             runner.run {
               // now we produce integration components for our shared plan
-              checker.verify(shared.side.plan)
+              checker.verify(shared.side)
 
-              Injector.inherit(runtimeLocator).produceF[F](shared.shared.plan).use {
+              Injector.inherit(runtimeLocator).produceF[F](shared.shared).use {
                 sharedLocator =>
 
-                  Injector.inherit(sharedLocator).produceF[F](shared.side.plan).use {
+                  Injector.inherit(sharedLocator).produceF[F](shared.side).use {
                     sharedIntegrationLocator =>
                       ifIntegChecksOk(F, sharedIntegrationLocator)(testplans.map(_._1), shared) {
                         proceed(appModule, checker, testplans, shared, sharedLocator)
@@ -114,7 +114,7 @@ class DistageTestRunner[F[_] : TagK]
 
   private def ifIntegChecksOk(F: DIEffect[F], integLocator: Locator)(testplans: Seq[DistageTest[F]], plans: TriSplittedPlan)(onSuccess: => F[Unit]): F[Unit] = {
     implicit val FF: DIEffect[F] = F
-    integrationChecker.collectFailures(plans.side.roots, integLocator).flatMap {
+    integrationChecker.collectFailures(plans.side.declaredRoots, integLocator).flatMap {
       case Left(value) =>
         F.traverse_(testplans) {
           test =>
@@ -130,8 +130,8 @@ class DistageTestRunner[F[_] : TagK]
   private def proceed(appmodule: ModuleBase, checker: PlanCircularDependencyCheck, testplans: Seq[(DistageTest[F], OrderedPlan)], shared: TriSplittedPlan, parent: Locator)
                      (implicit F: DIEffect[F], P: DIEffectAsync[F]): F[Unit] = {
     // here we produce our shared plan
-    checker.verify(shared.primary.plan)
-    Injector.inherit(parent).produceF[F](shared.primary.plan).use {
+    checker.verify(shared.primary)
+    Injector.inherit(parent).produceF[F](shared.primary).use {
       mainSharedLocator =>
         val testInjector = Injector.inherit(mainSharedLocator)
 
@@ -152,14 +152,14 @@ class DistageTestRunner[F[_] : TagK]
                   val integrations = testplan.collectChildren[IntegrationCheck].map(_.target).toSet -- allSharedKeys
                   val newtestplan = testInjector.trisectByRoots(appmodule.drop(allSharedKeys), testplan.keys -- allSharedKeys, integrations)
 
-                  checker.verify(newtestplan.primary.plan)
-                  checker.verify(newtestplan.side.plan)
-                  checker.verify(newtestplan.shared.plan)
+                  checker.verify(newtestplan.primary)
+                  checker.verify(newtestplan.side)
+                  checker.verify(newtestplan.shared)
 
                   // we are ready to run the test, finally
-                  testInjector.produceF[F](newtestplan.shared.plan).use {
+                  testInjector.produceF[F](newtestplan.shared).use {
                     sharedLocator =>
-                      Injector.inherit(sharedLocator).produceF[F](newtestplan.side.plan).use {
+                      Injector.inherit(sharedLocator).produceF[F](newtestplan.side).use {
                         integLocator =>
                           ifIntegChecksOk(F, integLocator)(Seq(test), newtestplan) {
                             proceedIndividual(test, newtestplan, sharedLocator)
@@ -182,7 +182,7 @@ class DistageTestRunner[F[_] : TagK]
 
   private def proceedIndividual(test: DistageTest[F], newtestplan: TriSplittedPlan, parent: Locator)(implicit F: DIEffect[F]): F[Unit] = {
     Injector.inherit(parent)
-      .produceF[F](newtestplan.primary.plan).use {
+      .produceF[F](newtestplan.primary).use {
       testLocator =>
         def doRun(before: Long): F[Unit] = {
           for {
diff --git a/idealingua-v1/idealingua-v1-transpilers/src/main/scala/izumi/idealingua/translator/toscala/types/CompositeStructure.scala b/idealingua-v1/idealingua-v1-transpilers/src/main/scala/izumi/idealingua/translator/toscala/types/CompositeStructure.scala
index 20430f068..4d78c7402 100644
--- a/idealingua-v1/idealingua-v1-transpilers/src/main/scala/izumi/idealingua/translator/toscala/types/CompositeStructure.scala
+++ b/idealingua-v1/idealingua-v1-transpilers/src/main/scala/izumi/idealingua/translator/toscala/types/CompositeStructure.scala
@@ -2,6 +2,7 @@ package izumi.idealingua.translator.toscala.types
 
 import izumi.idealingua.model.il.ast.typed.Interfaces
 import izumi.idealingua.translator.toscala.STContext
+import izumi.fundamentals.collections.IzCollections._
 
 import scala.meta._
 
@@ -16,7 +17,6 @@ class CompositeStructure(ctx: STContext, val fields: ScalaStruct) {
   val constructors: List[Defn.Def] = {
     val struct = fields.fields
 
-    import izumi.fundamentals.collections.IzCollections._
     ctx.typespace.structure
       .constructors(struct)
       .map {