Repository: 7mind/izumi
Pull request #1789 (2022-09-05 20:46:23)

Add `LifecycleAggregator` by @Caparow

codecov-commenter: # [Codecov](https://codecov.io/gh/7mind/izumi/pull/1789?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=7mind) Report
> Merging [#1789](https://codecov.io/gh/7mind/izumi/pull/1789?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=7mind) (10a7721) into [develop](https://codecov.io/gh/7mind/izumi/commit/5c01cfe238ad5f4d01426a2684bd10e82630a5f7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=7mind) (5c01cfe) will **increase** coverage by `0.03%`.
> The diff coverage is `0.00%`.

```diff
@@             Coverage Diff             @@
##           develop    #1789      +/-   ##
===========================================
+ Coverage    63.47%   63.51%   +0.03%     
===========================================
  Files          494      486       -8     
  Lines         9911     9628     -283     
  Branches       480      499      +19     
===========================================
- Hits          6291     6115     -176     
+ Misses        3620     3513     -107     
```


Patch:
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapContextModule.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapContextModule.scala
index 5e7b70512..2a9141770 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapContextModule.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapContextModule.scala
@@ -12,7 +12,5 @@ object BootstrapContextModule {
     }
   }
 
-  implicit val BootstrapBaseModuleApi: ModuleMake[BootstrapContextModule] = new ModuleMake[BootstrapContextModule] {
-    override def make(bindings: Set[Binding]): BootstrapContextModule = BootstrapContextModule.make(bindings)
-  }
+  implicit val BootstrapBaseModuleApi: ModuleMake[BootstrapContextModule] = BootstrapContextModule.make
 }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapModule.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapModule.scala
index 7c94d9eb3..8e4aa6bd8 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapModule.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/BootstrapModule.scala
@@ -12,7 +12,5 @@ object BootstrapModule {
     }
   }
 
-  implicit val BootstrapModuleApi: ModuleMake[BootstrapModule] = new ModuleMake[BootstrapModule] {
-    override def make(bindings: Set[Binding]): BootstrapModule = BootstrapModule.make(bindings)
-  }
+  implicit val BootstrapModuleApi: ModuleMake[BootstrapModule] = BootstrapModule.make
 }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LifecycleAggregator.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LifecycleAggregator.scala
new file mode 100644
index 000000000..4ce9f7fbb
--- /dev/null
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/LifecycleAggregator.scala
@@ -0,0 +1,75 @@
+package izumi.distage.model.definition
+
+import izumi.functional.bio.{Applicative2, F, IO2, Panic2, Primitives2, RefM2, TypedError}
+
+final class LifecycleAggregator[F[+_, +_], E](
+  finalizers: RefM2[F, List[(LifecycleAggregator[F, E]#Key, F[E, Unit])]]
+) {
+
+  def acquire[R](resource: Lifecycle[F[E, _], R])(implicit F: IO2[F]): F[E, R] = {
+    acquireKey(resource).map(_._1)
+  }
+
+  def acquireKey[R](resource: Lifecycle[F[E, _], R])(implicit F: IO2[F]): F[E, (R, Key)] = {
+    F.uninterruptibleExcept {
+      restore =>
+        for {
+          inner <- resource.acquire
+          key <- F.sync(new Key)
+          _ <- finalizers.update_ {
+            fins =>
+              val finalizer = {
+                // suspend
+                F.sync(resource.release(inner)).flatten
+              }
+              F.pure((key -> finalizer) :: fins)
+          }
+          outer <- restore(resource.extract(inner).fold(identity, F.pure))
+        } yield (outer, key)
+    }
+  }
+
+  def release(key: Key)(implicit F: Applicative2[F]): F[E, Unit] = {
+    finalizers.modify {
+      map =>
+        map.find(_._1 == key) match {
+          case Some((_, release)) => release.map(_ -> map.filter(_._1 != key))
+          case None => F.pure(() -> map)
+        }
+    }
+  }
+
+  def releaseAll()(implicit F: Panic2[F]): F[Nothing, Unit] = {
+    for {
+      finalizers <- finalizers.modify(m => F.pure(m -> List.empty))
+      _ <- finalizers.iterator
+        .map(_._2)
+        .foldLeft(F.unit) {
+          // use `guarantee` to make all finalizers execute even if previous finalizer failed
+          _ guarantee _.catchAll {
+            case e: Throwable => F.terminate(e)
+            case e => F.terminate(TypedError(e))
+          }
+        }
+    } yield ()
+  }
+
+  final class Key
+
+}
+
+object LifecycleAggregator {
+  def make[F[+_, +_]: Panic2: Primitives2]: Lifecycle[F[Throwable, _], LifecycleAggregator[F, Throwable]] = {
+    Lifecycle.make(makeImpl[F, Throwable])(_.releaseAll())
+  }
+
+  def makeGeneric[F[+_, +_]: Panic2: Primitives2, E]: Lifecycle[F[E, _], LifecycleAggregator[F, E]] = {
+    Lifecycle.make(makeImpl[F, E])(_.releaseAll())
+  }
+
+  private[this] def makeImpl[F[+_, +_]: Panic2: Primitives2, E]: F[Nothing, LifecycleAggregator[F, E]] = {
+    for {
+      finalizers <- F.mkRefM(List.empty[(LifecycleAggregator[F, E]#Key, F[E, Unit])])
+    } yield new LifecycleAggregator[F, E](finalizers)
+  }
+}
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Module.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Module.scala
index 4d5d0cf0f..c03f3a602 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Module.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/Module.scala
@@ -12,7 +12,5 @@ object Module {
     }
   }
 
-  implicit val moduleApi: ModuleMake[Module] = new ModuleMake[Module] {
-    override def make(bindings: Set[Binding]): Module = Module.make(bindings)
-  }
+  implicit val moduleApi: ModuleMake[Module] = Module.make
 }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala
index f5de6ea3a..41b04d928 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleBase.scala
@@ -34,9 +34,7 @@ object ModuleBase extends ModuleBaseLowPriorityInstances {
     }
   }
 
-  implicit val moduleBaseApi: ModuleMake[ModuleBase] = new ModuleMake[ModuleBase] {
-    override def make(bindings: Set[Binding]): ModuleBase = ModuleBase.make(bindings)
-  }
+  implicit val moduleBaseApi: ModuleMake[ModuleBase] = ModuleBase.make
 
   implicit final class ModuleDefSeqExt[S <: ModuleBase](private val defs: Iterable[S]) extends AnyVal {
     def merge[T <: ModuleBase](implicit T: ModuleMake.Aux[S, T]): T = {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala
index 7b4ce9bf0..67e6605e1 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/plan/repr/KeyFormatter.scala
@@ -6,9 +6,7 @@ trait KeyFormatter {
   def formatKey(key: DIKey): String
 }
 object KeyFormatter {
-  def minimized(minimizer: KeyMinimizer): KeyFormatter = new KeyFormatter {
-    override def formatKey(key: DIKey): String = minimizer.renderKey(key)
-  }
+  def minimized(minimizer: KeyMinimizer): KeyFormatter = minimizer.renderKey
   val Full: KeyFormatter = _.toString
 }
 
@@ -16,8 +14,6 @@ trait TypeFormatter {
   def formatType(key: SafeType): String
 }
 object TypeFormatter {
-  def minimized(minimizer: KeyMinimizer): TypeFormatter = new TypeFormatter {
-    override def formatType(key: SafeType): String = minimizer.renderType(key)
-  }
+  def minimized(minimizer: KeyMinimizer): TypeFormatter = minimizer.renderType
   val Full: TypeFormatter = _.tag.repr
 }
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/Functoid.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/Functoid.scala
index 0badafc7e..287cb02bd 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/Functoid.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/Functoid.scala
@@ -55,7 +55,7 @@ import scala.annotation.unused
   *   make[Unit].from(constructorMethod _) // Will work correctly: summon "special" Int
   * }}}
   *
-  * Prefer annotating parameter types, not parameters: `class1 X(i: Int @Id("special")) { ... }`
+  * Prefer annotating parameter types, not parameters: `class X(i: Int @Id("special")) { ... }`
   *
   * {{{
   *   final case class X(i: Int @Id("special"))
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala
index ad991efb7..3cabbdf14 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/provisioning/PlanInterpreter.scala
@@ -29,9 +29,7 @@ object PlanInterpreter {
     def filter(finalizers: collection.Seq[Finalizer[F]]): collection.Seq[Finalizer[F]]
   }
   object FinalizerFilter {
-    def all[F[_]]: FinalizerFilter[F] = new FinalizerFilter[F] {
-      override def filter(finalizers: collection.Seq[Finalizer[F]]): collection.Seq[Finalizer[F]] = finalizers
-    }
+    def all[F[_]]: FinalizerFilter[F] = identity
   }
 
   final case class Finalizer[+F[_]](key: DIKey, effect: () => F[Unit], fType: SafeType)
diff --git a/distage/distage-extension-config/src/main/scala-3/izumi/distage/config/codec/scala-2/izumi/distage/config/codec/PureconfigAutoDerive.scala b/distage/distage-extension-config/src/main/scala-3/izumi/distage/config/codec/scala-2/izumi/distage/config/codec/PureconfigAutoDerive.scala
index 305d9d2f0..b5ce3344f 100644
--- a/distage/distage-extension-config/src/main/scala-3/izumi/distage/config/codec/scala-2/izumi/distage/config/codec/PureconfigAutoDerive.scala
+++ b/distage/distage-extension-config/src/main/scala-3/izumi/distage/config/codec/scala-2/izumi/distage/config/codec/PureconfigAutoDerive.scala
@@ -2,7 +2,6 @@ package izumi.distage.config.codec
 
 import pureconfig.ConfigReader
 
-
 /**
   * Derive `pureconfig.ConfigReader` for A and for its fields recursively with `pureconfig-magnolia`
   *
diff --git a/distage/distage-extension-plugins/src/main/scala/distage/plugins/DistagePlugins.scala b/distage/distage-extension-plugins/src/main/scala-2/distage/plugins/DistagePlugins.scala
similarity index 100%
rename from distage/distage-extension-plugins/src/main/scala/distage/plugins/DistagePlugins.scala
rename to distage/distage-extension-plugins/src/main/scala-2/distage/plugins/DistagePlugins.scala
diff --git a/distage/distage-extension-plugins/src/main/scala/distage/plugins/package.scala b/distage/distage-extension-plugins/src/main/scala-2/distage/plugins/package.scala
similarity index 100%
rename from distage/distage-extension-plugins/src/main/scala/distage/plugins/package.scala
rename to distage/distage-extension-plugins/src/main/scala-2/distage/plugins/package.scala
diff --git a/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/BootstrapPluginDef.scala b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/BootstrapPluginDef.scala
similarity index 52%
rename from distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/BootstrapPluginDef.scala
rename to distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/BootstrapPluginDef.scala
index bada5ae00..4b594b7e6 100644
--- a/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/BootstrapPluginDef.scala
+++ b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/BootstrapPluginDef.scala
@@ -4,4 +4,4 @@ import izumi.distage.model.definition.BootstrapModuleDef
 import scala.annotation.unused
 
 /** @see [[izumi.distage.plugins.PluginDef]] */
-abstract class BootstrapPluginDef[T]()(implicit @unused recompilationToken: ForcedRecompilationToken[T]) extends BootstrapPlugin with BootstrapModuleDef
+abstract class BootstrapPluginDef[T](implicit @unused recompilationToken: ForcedRecompilationToken[T]) extends BootstrapPlugin with BootstrapModuleDef
diff --git a/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/ForcedRecompilationToken.scala b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/ForcedRecompilationToken.scala
index 06842b3b7..2bc24f235 100644
--- a/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/ForcedRecompilationToken.scala
+++ b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/ForcedRecompilationToken.scala
@@ -27,6 +27,10 @@ final abstract class ForcedRecompilationToken[T]
 object ForcedRecompilationToken {
   implicit def materialize[T]: ForcedRecompilationToken[T] = macro UniqueRecompilationTokenMacro.whiteboxMaterializeImpl
 
+  object disabled {
+    implicit def disable: ForcedRecompilationToken[Unit] = null
+  }
+
   object UniqueRecompilationTokenMacro {
     final val compilerLaunchId = java.util.UUID.randomUUID().toString
     var cachedTypedTree: Universe#Tree = null
@@ -68,10 +72,6 @@ object ForcedRecompilationToken {
     }
   }
 
-  object disabled {
-    implicit def disable: ForcedRecompilationToken[Unit] = null
-  }
-
   // an implementation for better days!
   // As of IDEA 2020.3 EAP, Intellij "Incrementality type: IDEA" doesn't regard changes in singleton types as "real",
   // so instead we have to use the trick above to encode the UUID as Eithers.
diff --git a/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/PluginDef.scala b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/PluginDef.scala
similarity index 89%
rename from distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/PluginDef.scala
rename to distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/PluginDef.scala
index 24313c2bc..5ac11a9ee 100644
--- a/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/PluginDef.scala
+++ b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/PluginDef.scala
@@ -24,4 +24,4 @@ import scala.annotation.unused
   * @see [[https://izumi.7mind.io/distage/distage-framework#plugins Plugins]]
   * @see [[https://izumi.7mind.io/distage/distage-framework#compile-time-checks Compile-time checks]]
   */
-abstract class PluginDef[T]()(implicit @unused recompilationToken: ForcedRecompilationToken[T]) extends PluginBase with ModuleDef
+abstract class PluginDef[T](implicit @unused recompilationToken: ForcedRecompilationToken[T]) extends PluginBase with ModuleDef
diff --git a/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/load/package.scala b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/load/package.scala
new file mode 100644
index 000000000..3420301d7
--- /dev/null
+++ b/distage/distage-extension-plugins/src/main/scala-2/izumi/distage/plugins/load/package.scala
@@ -0,0 +1,5 @@
+package izumi.distage.plugins
+
+package object load {
+  private[load] type PluginDefType = PluginDef[?]
+}
diff --git a/distage/distage-extension-plugins/src/main/scala-3/distage/plugins/DistagePlugins.scala b/distage/distage-extension-plugins/src/main/scala-3/distage/plugins/DistagePlugins.scala
new file mode 100644
index 000000000..b4b425336
--- /dev/null
+++ b/distage/distage-extension-plugins/src/main/scala-3/distage/plugins/DistagePlugins.scala
@@ -0,0 +1,29 @@
+package distage.plugins
+
+import izumi.distage.plugins
+import izumi.distage.plugins.{StaticPluginLoader, load}
+
+trait DistagePlugins {
+
+  type PluginBase = plugins.PluginBase
+  val PluginBase: plugins.PluginBase.type = plugins.PluginBase
+
+  type PluginDef = plugins.PluginDef
+
+  type BootstrapPlugin = plugins.BootstrapPlugin
+  val BootstrapPlugin: plugins.BootstrapPlugin.type = plugins.BootstrapPlugin
+
+  type BootstrapPluginDef = plugins.BootstrapPluginDef
+
+  type PluginLoader = load.PluginLoader
+  val PluginLoader: load.PluginLoader.type = load.PluginLoader
+
+  val StaticPlugingLoader: StaticPluginLoader.type = plugins.StaticPluginLoader
+
+  type PluginLoaderDefaultImpl = load.PluginLoaderDefaultImpl
+  val PluginLoaderDefaultImpl: load.PluginLoaderDefaultImpl.type = load.PluginLoaderDefaultImpl
+
+  type PluginConfig = plugins.PluginConfig
+  val PluginConfig: plugins.PluginConfig.type = plugins.PluginConfig
+
+}
diff --git a/distage/distage-extension-plugins/src/main/scala-3/distage/plugins/package.scala b/distage/distage-extension-plugins/src/main/scala-3/distage/plugins/package.scala
new file mode 100644
index 000000000..8817abf07
--- /dev/null
+++ b/distage/distage-extension-plugins/src/main/scala-3/distage/plugins/package.scala
@@ -0,0 +1,28 @@
+package distage
+
+import izumi.distage.plugins.load
+
+package object plugins extends DistagePlugins {
+
+  override type PluginBase = izumi.distage.plugins.PluginBase
+  override val PluginBase: izumi.distage.plugins.PluginBase.type = izumi.distage.plugins.PluginBase
+
+  override type PluginDef = izumi.distage.plugins.PluginDef
+
+  override type BootstrapPlugin = izumi.distage.plugins.BootstrapPlugin
+  override val BootstrapPlugin: izumi.distage.plugins.BootstrapPlugin.type = izumi.distage.plugins.BootstrapPlugin
+
+  override type BootstrapPluginDef = izumi.distage.plugins.BootstrapPluginDef
+
+  override type PluginLoader = load.PluginLoader
+  override val PluginLoader: load.PluginLoader.type = load.PluginLoader
+
+  override val StaticPlugingLoader: izumi.distage.plugins.StaticPluginLoader.type = izumi.distage.plugins.StaticPluginLoader
+
+  override type PluginLoaderDefaultImpl = load.PluginLoaderDefaultImpl
+  override val PluginLoaderDefaultImpl: load.PluginLoaderDefaultImpl.type = load.PluginLoaderDefaultImpl
+
+  override type PluginConfig = izumi.distage.plugins.PluginConfig
+  override val PluginConfig: izumi.distage.plugins.PluginConfig.type = izumi.distage.plugins.PluginConfig
+
+}
diff --git a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/BootstrapPluginDef.scala b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/BootstrapPluginDef.scala
new file mode 100644
index 000000000..82474c3c8
--- /dev/null
+++ b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/BootstrapPluginDef.scala
@@ -0,0 +1,7 @@
+package izumi.distage.plugins
+
+import izumi.distage.model.definition.BootstrapModuleDef
+import scala.annotation.unused
+
+/** @see [[izumi.distage.plugins.PluginDef]] */
+abstract class BootstrapPluginDef(implicit @unused recompilationToken: ForcedRecompilationToken[?]) extends BootstrapPlugin with BootstrapModuleDef
diff --git a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/ForcedRecompilationToken.scala b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/ForcedRecompilationToken.scala
index 67ceb3828..26f78abdf 100644
--- a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/ForcedRecompilationToken.scala
+++ b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/ForcedRecompilationToken.scala
@@ -1,6 +1,7 @@
 package izumi.distage.plugins
 
 import scala.annotation.implicitNotFound
+import scala.quoted.{Expr, Quotes, Type}
 
 /**
   * This macro allows `distage`'s compile-time checks to cooperate with Scala's incremental compilation:
@@ -22,9 +23,25 @@ in which case you'll have to put a dummy implicit in scope, such as by using:
 final abstract class ForcedRecompilationToken[T]
 
 object ForcedRecompilationToken {
-  implicit def materialize[T]: ForcedRecompilationToken[T] = ???
+
+  transparent inline implicit def materialize[T]: ForcedRecompilationToken[T] = ${ UniqueRecompilationTokenMacro.materializeImpl }
 
   object disabled {
     implicit def disable: ForcedRecompilationToken[Unit] = null
   }
+
+  object UniqueRecompilationTokenMacro {
+    final val compilerLaunchId = java.util.UUID.randomUUID().toString
+
+    // TODO: research if caching typed trees optimization is possible and meaningful in Dotty
+    def materializeImpl[T](using quotes: Quotes): Expr[ForcedRecompilationToken[T]] = {
+      import quotes.reflect.*
+      val typeTree = ConstantType(StringConstant("abc"))
+      typeTree.asType.asInstanceOf[Type[T]] match {
+        case given Type[uuid] =>
+          '{ null.asInstanceOf[ForcedRecompilationToken[uuid]] }
+      }
+    }
+  }
+
 }
diff --git a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/PluginConfigStatic.scala b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/PluginConfigStatic.scala
index 4bd3f5fa2..ce5833c98 100644
--- a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/PluginConfigStatic.scala
+++ b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/PluginConfigStatic.scala
@@ -1,6 +1,21 @@
 package izumi.distage.plugins
 
+import scala.compiletime.error
 
 trait PluginConfigStatic {
+  /** Scan the specified package *at compile-time* for classes and objects that inherit [[PluginBase]]
+    *
+    * WARN: may interact badly with incremental compilation
+    * WARN: will _not_ find plugins defined in the current module, only those defined in dependency modules
+    * (similarly to how you cannot call Scala macros defined in the current module)
+    */
+  inline def compileTime(pluginsPackage: String): PluginConfig = error("unimplemented")
 
+  /** Scan the the current source file's package *at compile-time* for classes and objects that inherit [[PluginBase]]
+    *
+    * WARN: may interact badly with incremental compilation
+    * WARN: will _not_ find plugins defined in the current module, only those defined in dependency modules
+    * (similarly to how you cannot call Scala macros defined in the current module)
+    */
+  inline def compileTimeThisPkg: PluginConfig = error("unimplemented")
 }
diff --git a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/PluginDef.scala b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/PluginDef.scala
new file mode 100644
index 000000000..d6794ad57
--- /dev/null
+++ b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/PluginDef.scala
@@ -0,0 +1,27 @@
+package izumi.distage.plugins
+
+import izumi.distage.model.definition.ModuleDef
+import scala.annotation.unused
+
+/**
+  * Use it to define Plugins using [[izumi.distage.model.definition.dsl.ModuleDefDSL]] syntax
+  *
+  * {{{
+  *   object MyPlugin extends PluginDef {
+  *     include(myModule[F])
+  *
+  *     make[Xa[F]].from[Xa.Impl[F]]
+  *   }
+  * }}}
+  *
+  * @note Since this is an abstract class, you cannot mix it with other classes or use it as a mixin.
+  *       Instead, you may inherit from [[PluginBase]], which is a trait – but in that case compile-time checks will not
+  *       re-run when the class is updated in that case. Alternatively, you may use [[izumi.distage.model.definition.dsl.IncludesDSL#include]]
+  *       to compose modules as values instead of using inheritance.
+  *
+  * @param recompilationToken Makes compile-time checks re-run when the source code of this `PluginDef` is changed, if it's used in the checked role.
+  *
+  * @see [[https://izumi.7mind.io/distage/distage-framework#plugins Plugins]]
+  * @see [[https://izumi.7mind.io/distage/distage-framework#compile-time-checks Compile-time checks]]
+  */
+abstract class PluginDef(implicit @unused recompilationToken: ForcedRecompilationToken[?]) extends PluginBase with ModuleDef
diff --git a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/StaticPluginLoader.scala b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/StaticPluginLoader.scala
index 876e05cee..f80a5c4a3 100644
--- a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/StaticPluginLoader.scala
+++ b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/StaticPluginLoader.scala
@@ -1,5 +1,7 @@
 package izumi.distage.plugins
 
+import scala.compiletime.error
+
 /** Scan the specified package *at compile-time* for classes and objects that inherit [[PluginBase]]
   *
   * WARN: may interact badly with incremental compilation
@@ -10,4 +12,6 @@ package izumi.distage.plugins
   */
 object StaticPluginLoader {
 
+  inline def scanCompileTime(pluginsPackage: String): List[PluginBase] = error("unimplemented")
+
 }
diff --git a/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/load/package.scala b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/load/package.scala
new file mode 100644
index 000000000..ab2df67c7
--- /dev/null
+++ b/distage/distage-extension-plugins/src/main/scala-3/izumi/distage/plugins/load/package.scala
@@ -0,0 +1,5 @@
+package izumi.distage.plugins
+
+package object load {
+  private[load] type PluginDefType = PluginDef
+}
diff --git a/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/load/PluginLoaderDefaultImpl.scala b/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/load/PluginLoaderDefaultImpl.scala
index ceee48977..20105d40c 100644
--- a/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/load/PluginLoaderDefaultImpl.scala
+++ b/distage/distage-extension-plugins/src/main/scala/izumi/distage/plugins/load/PluginLoaderDefaultImpl.scala
@@ -1,7 +1,7 @@
 package izumi.distage.plugins.load
 
 import io.github.classgraph.ClassGraph
-import izumi.distage.plugins.{PluginBase, PluginConfig, PluginDef}
+import izumi.distage.plugins.{PluginBase, PluginConfig}
 import izumi.fundamentals.platform.cache.SyncCache
 import izumi.fundamentals.reflection.TypeUtil
 
@@ -25,7 +25,7 @@ class PluginLoaderDefaultImpl extends PluginLoader {
     val disabledPackages = config.packagesDisabled
 
     val pluginBase = classOf[PluginBase]
-    val pluginDef = classOf[PluginDef[?]]
+    val pluginDef = classOf[PluginDefType]
     val whitelistedClasses = Seq(pluginDef.getName)
 
     def loadPkgs(pkgs: Seq[String]): Seq[PluginBase] = {
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala
index 129168c5e..325beae19 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala
@@ -62,7 +62,7 @@ abstract class RoleAppMain[F[_]](
     *
     *       {{{
     *       override def pluginConfig: PluginConfig = {
-    *         super.pluginConfig overriddenBy new PluginDef() {
+    *         super.pluginConfig overriddenBy new PluginDef {
     *           make[MyComponentX]]
     *         }
     *       }
diff --git a/logstage/logstage-core/src/main/scala/izumi/logstage/api/Log.scala b/logstage/logstage-core/src/main/scala/izumi/logstage/api/Log.scala
index 632cdf2ad..cb300d132 100644
--- a/logstage/logstage-core/src/main/scala/izumi/logstage/api/Log.scala
+++ b/logstage/logstage-core/src/main/scala/izumi/logstage/api/Log.scala
@@ -185,14 +185,15 @@ object Log {
     }
     def +(that: Message): Message = ++(that)
   }
+  /** Construct [[Message]] from a string interpolation using [[Message.apply]] */
   object Message extends MessageMat {
-
     def raw(message: String): Message = Message(StringContext(message), Nil)
 
     def empty: Message = raw("")
   }
 
-  object StrictMessage {
+  /** Construct [[Message]] from a string interpolation using [[StrictMessage.apply]] */
+  object StrictMessage extends StrictMessageMat {
     def empty: Message = Message.empty
   }
 }


Test patch:
diff --git a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/sneaky/SneakyPlugin.scala b/distage/distage-extension-plugins/src/test/scala-2/com/github/pshirshov/test/sneaky/SneakyPlugin.scala
similarity index 74%
rename from distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/sneaky/SneakyPlugin.scala
rename to distage/distage-extension-plugins/src/test/scala-2/com/github/pshirshov/test/sneaky/SneakyPlugin.scala
index eb915293c..feb001734 100644
--- a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/sneaky/SneakyPlugin.scala
+++ b/distage/distage-extension-plugins/src/test/scala-2/com/github/pshirshov/test/sneaky/SneakyPlugin.scala
@@ -8,4 +8,4 @@ import izumi.fundamentals.platform.build.ExposedTestScope
   * This is just to verify that plugin enumerator picks up transitively inherited plugins
   */
 @ExposedTestScope
-abstract class SneakyPlugin[T]()(implicit val ev: ForcedRecompilationToken[T]) extends PluginBase with ModuleDef
+abstract class SneakyPlugin[T](implicit val ev: ForcedRecompilationToken[T]) extends PluginBase with ModuleDef
diff --git a/distage/distage-extension-plugins/src/test/scala-3/com/github/pshirshov/test/sneaky/SneakyPlugin.scala b/distage/distage-extension-plugins/src/test/scala-3/com/github/pshirshov/test/sneaky/SneakyPlugin.scala
new file mode 100644
index 000000000..04409b129
--- /dev/null
+++ b/distage/distage-extension-plugins/src/test/scala-3/com/github/pshirshov/test/sneaky/SneakyPlugin.scala
@@ -0,0 +1,11 @@
+package com.github.pshirshov.test.sneaky
+
+import izumi.distage.model.definition.ModuleDef
+import izumi.distage.plugins.{ForcedRecompilationToken, PluginBase}
+import izumi.fundamentals.platform.build.ExposedTestScope
+
+/**
+  * This is just to verify that plugin enumerator picks up transitively inherited plugins
+  */
+@ExposedTestScope
+abstract class SneakyPlugin(implicit val ev: ForcedRecompilationToken[?]) extends PluginBase with ModuleDef
diff --git a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/DependingPlugin.scala b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/DependingPlugin.scala
index 710d52b21..9100d544c 100644
--- a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/DependingPlugin.scala
+++ b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/DependingPlugin.scala
@@ -4,14 +4,14 @@ import com.github.pshirshov.test.sneaky.SneakyPlugin
 import izumi.fundamentals.platform.build.ExposedTestScope
 
 @ExposedTestScope
-class DependingPlugin extends SneakyPlugin() {
+class DependingPlugin extends SneakyPlugin {
   make[String].from((_: TestDep, _: TestDep3, _: TestService) => "abc")
 }
 
 @ExposedTestScope
 object DependingPlugin extends App {
-  class NestedDoublePlugin extends SneakyPlugin()
-  object NestedDoublePlugin extends SneakyPlugin() {
+  class NestedDoublePlugin extends SneakyPlugin
+  object NestedDoublePlugin extends SneakyPlugin {
     make[TestDepending]
   }
 }
diff --git a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/EmptyTestPlugin.scala b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/EmptyTestPlugin.scala
index c3a2f6e3b..8899c0e29 100644
--- a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/EmptyTestPlugin.scala
+++ b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/EmptyTestPlugin.scala
@@ -2,4 +2,4 @@ package com.github.pshirshov.test.plugins
 
 import com.github.pshirshov.test.sneaky.SneakyPlugin
 
-object EmptyTestPlugin extends SneakyPlugin()
+object EmptyTestPlugin extends SneakyPlugin
diff --git a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/ObjectTestPlugin.scala b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/ObjectTestPlugin.scala
index a2a76aefd..a6e0af716 100644
--- a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/ObjectTestPlugin.scala
+++ b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/ObjectTestPlugin.scala
@@ -2,6 +2,6 @@ package com.github.pshirshov.test.plugins
 
 import com.github.pshirshov.test.sneaky.SneakyPlugin
 
-object ObjectTestPlugin extends SneakyPlugin() {
+object ObjectTestPlugin extends SneakyPlugin {
   make[TestDep3]
 }
diff --git a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/StaticTestPlugin.scala b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/StaticTestPlugin.scala
index bf2c5cd60..116787f94 100644
--- a/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/StaticTestPlugin.scala
+++ b/distage/distage-extension-plugins/src/test/scala/com/github/pshirshov/test/plugins/StaticTestPlugin.scala
@@ -11,7 +11,7 @@ object Test extends Axis {
 }
 
 @ExposedTestScope
-class StaticTestPlugin extends SneakyPlugin() with ConfigModuleDef {
+class StaticTestPlugin extends SneakyPlugin with ConfigModuleDef {
   make[TestDep].tagged(Test.X).from[TestDep1]
   make[TestDep].tagged(Test.Y).from[TestDep2]
   make[TestService]
diff --git a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
index 7cb2140f2..ee853b5d8 100644
--- a/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
+++ b/distage/distage-framework-docker/src/test/scala/izumi/distage/testkit/docker/fixtures/DockerPlugin.scala
@@ -29,7 +29,7 @@ class PgSvcExample(
   }
 }
 
-object DockerPlugin extends PluginDef() {
+object DockerPlugin extends PluginDef {
   include(DockerSupportModule[Task])
   make[DynamoDocker.Container].fromResource {
     DynamoDocker.make[Task]
diff --git a/distage/distage-framework/src/test/scala/com/github/pshirshov/test/plugins/StaticTestMain.scala b/distage/distage-framework/src/test/scala/com/github/pshirshov/test/plugins/StaticTestMain.scala
index 6dfd29bef..d314406cc 100644
--- a/distage/distage-framework/src/test/scala/com/github/pshirshov/test/plugins/StaticTestMain.scala
+++ b/distage/distage-framework/src/test/scala/com/github/pshirshov/test/plugins/StaticTestMain.scala
@@ -33,7 +33,7 @@ class StaticTestMainLogIO2[F[+_, +_]: TagKK: Async2: DefaultModule2] extends Rol
     PluginConfig
       .cached("com.github.pshirshov.test.plugins")
       .++(staticTestMainPlugin[F[Throwable, _], F[Throwable, _]])
-      .++(new PluginDef() {
+      .++(new PluginDef {
         modify[StaticTestRole[F[Throwable, _]]]
           .addDependency[LogIO2[F]]
       })
diff --git a/distage/distage-framework/src/test/scala/com/github/pshirshov/test2/plugins/Fixture2.scala b/distage/distage-framework/src/test/scala/com/github/pshirshov/test2/plugins/Fixture2.scala
index f4f3afaf0..bb00183b6 100644
--- a/distage/distage-framework/src/test/scala/com/github/pshirshov/test2/plugins/Fixture2.scala
+++ b/distage/distage-framework/src/test/scala/com/github/pshirshov/test2/plugins/Fixture2.scala
@@ -14,7 +14,7 @@ object Fixture2 {
     override protected def pluginConfig: PluginConfig = PluginConfig.cached("com.github.pshirshov.test2.plugins")
   }
 
-  final class TestPlugin extends PluginDef() with RoleModuleDef {
+  final class TestPlugin extends PluginDef with RoleModuleDef {
     make[Dep].tagged(Mode.Prod, Repo.Prod).from[DepGood]
     make[Dep].tagged(Mode.Prod, Repo.Dummy).from[DepGood]
 
diff --git a/distage/distage-framework/src/test/scala/com/github/pshirshov/test3/plugins/Fixture3.scala b/distage/distage-framework/src/test/scala/com/github/pshirshov/test3/plugins/Fixture3.scala
index b58928631..28b1e13c3 100644
--- a/distage/distage-framework/src/test/scala/com/github/pshirshov/test3/plugins/Fixture3.scala
+++ b/distage/distage-framework/src/test/scala/com/github/pshirshov/test3/plugins/Fixture3.scala
@@ -17,12 +17,12 @@ object Fixture3 {
 
   object TestRoleAppMainFailing extends RoleAppMain.LauncherIdentity {
     override protected def pluginConfig: PluginConfig = PluginConfig.cachedThisPkg
-    override protected def bootstrapPluginConfig: PluginConfig = PluginConfig.cached("com.github.pshirshov.test3.bootstrap") overriddenBy new PluginDef() {
+    override protected def bootstrapPluginConfig: PluginConfig = PluginConfig.cached("com.github.pshirshov.test3.bootstrap") overriddenBy new PluginDef {
       modify[BootstrapComponent].addDependency[UnsatisfiedDep]
     }
   }
 
-  final class TestPlugin extends PluginDef() with RoleModuleDef {
+  final class TestPlugin extends PluginDef with RoleModuleDef {
     makeRole[Fixture3Role]
   }
 
diff --git a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
index 9c5e8400f..c2fba6ce3 100644
--- a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
+++ b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/RoleAppTest.scala
@@ -39,7 +39,7 @@ class RoleAppTest extends AnyWordSpec with WithProperties {
     "testservice.systemPropList.1" -> "222",
   )
 
-  class XXX_TestWhiteboxProbe extends PluginDef() {
+  class XXX_TestWhiteboxProbe extends PluginDef {
     val resources = new XXX_ResourceEffectsRecorder[IO]
     private var locator0: LocatorRef = null
     lazy val locator: Locator = locator0.get
@@ -89,7 +89,7 @@ class RoleAppTest extends AnyWordSpec with WithProperties {
               new TestPluginCatsIO,
               new AdaptedAutocloseablesCasePlugin,
               probe,
-              new PluginDef() {
+              new PluginDef {
                 make[TestResource[IO]].from[IntegrationResource0[IO]]
                 many[TestResource[IO]]
                   .ref[TestResource[IO]]
diff --git a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/AdaptedAutocloseablesCasePlugin.scala b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/AdaptedAutocloseablesCasePlugin.scala
index 28383b701..9851ca4eb 100644
--- a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/AdaptedAutocloseablesCasePlugin.scala
+++ b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/AdaptedAutocloseablesCasePlugin.scala
@@ -9,7 +9,7 @@ import izumi.fundamentals.platform.cli.model.raw.RawEntrypointParams
 import izumi.logstage.api.Log
 import izumi.logstage.api.logger.LogSink
 
-class AdaptedAutocloseablesCasePlugin extends PluginDef() {
+class AdaptedAutocloseablesCasePlugin extends PluginDef {
   make[AdaptedAutocloseablesCase]
   many[LogSink].add[BrokenSink]
   many[LogSink].add[BrokenSink2]
diff --git a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/ResourcesPlugin.scala b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/ResourcesPlugin.scala
index 4323c77e0..4ecd52593 100644
--- a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/ResourcesPlugin.scala
+++ b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/ResourcesPlugin.scala
@@ -10,7 +10,7 @@ import izumi.distage.roles.test.fixtures.Fixture._
 import izumi.distage.roles.test.fixtures.ResourcesPlugin._
 import izumi.fundamentals.platform.functional.Identity
 
-class ConflictPlugin extends PluginDef() {
+class ConflictPlugin extends PluginDef {
   make[Conflict].tagged(Mode.Prod).from[Conflict1]
   make[Conflict].tagged(Mode.Test).from[Conflict2]
   make[Conflict].from[Conflict3]
@@ -49,7 +49,7 @@ trait ResourcesPluginBase extends ModuleDef {
     .ref[JustResource3[IO]]
 }
 
-class ResourcesPlugin extends PluginDef() with ResourcesPluginBase {
+class ResourcesPlugin extends PluginDef with ResourcesPluginBase {
   make[XXX_ResourceEffectsRecorder[IO]]
 
   make[IntegrationResource0[IO]]
diff --git a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/TestPlugin.scala b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/TestPlugin.scala
index dcee65d05..a3e1a0f5a 100644
--- a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/TestPlugin.scala
+++ b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/fixtures/TestPlugin.scala
@@ -14,7 +14,7 @@ import izumi.distage.roles.test.fixtures.roles.TestRole00.{IntegrationOnlyCfg, I
 import izumi.fundamentals.platform.resources.ArtifactVersion
 import izumi.reflect.TagK
 
-class TestPluginBase[F[_]: TagK] extends PluginDef() with ConfigModuleDef with RoleModuleDef {
+class TestPluginBase[F[_]: TagK] extends PluginDef with ConfigModuleDef with RoleModuleDef {
   tag(Mode.Prod)
 
   include(BundledRolesModule[F] overriddenBy new ModuleDef {
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala
index da615cab1..544275937 100644
--- a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/DistageTestExample.scala
@@ -94,7 +94,7 @@ object DistageTestExampleBase {
 abstract class DistageTestExampleBase[F[_]: TagK: DefaultModule](implicit F: QuasiIO[F]) extends Spec1[F] with DistageMemoizeExample[F] {
 
   override protected def config: TestConfig = super.config.copy(
-    pluginConfig = super.config.pluginConfig.enablePackage("xxx") ++ new PluginDef() {
+    pluginConfig = super.config.pluginConfig.enablePackage("xxx") ++ new PluginDef {
       make[SetCounter]
 
       make[SetElement1]
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala
index 624ff6c1d..3464af613 100644
--- a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/fixtures/Fixtures.scala
@@ -19,7 +19,7 @@ object MockAppCatsIOPlugin extends MockAppPlugin[CIO]
 object MockAppZioPlugin extends MockAppPlugin[Task]
 object MockAppIdPlugin extends MockAppPlugin[Identity]
 
-abstract class MockAppPlugin[F[_]: TagK] extends PluginDef() {
+abstract class MockAppPlugin[F[_]: TagK] extends PluginDef {
   make[MockPostgresDriver[F]]
   make[MockUserRepository[F]]
   make[MockPostgresCheck[F]]
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/memoized/DistageMemoizationEnvsTest.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/memoized/DistageMemoizationEnvsTest.scala
index 06c910199..34ae35f6f 100644
--- a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/memoized/DistageMemoizationEnvsTest.scala
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/memoized/DistageMemoizationEnvsTest.scala
@@ -46,7 +46,7 @@ abstract class DistageMemoizationEnvsTest extends Spec3[ZIO] with AssertZIO {
           1 -> Set(DIKey[MemoizedInstance], DIKey.get[MemoizedLevel1]),
           2 -> Set(DIKey[MemoizedLevel2]),
         ),
-        pluginConfig = super.config.pluginConfig.enablePackage("izumi.distage.testkit.distagesuite") ++ new PluginDef() {
+        pluginConfig = super.config.pluginConfig.enablePackage("izumi.distage.testkit.distagesuite") ++ new PluginDef {
           make[MemoizedInstance].from {
             MemoizationEnv.makeInstance(MemoizationEnv.memoizedInstance)(MemoizationEnv.MemoizedInstance)
           }
@@ -98,7 +98,7 @@ class SameLevel_1_WithoutLastMemoizationLevel extends DistageMemoizationEnvsTest
       memoizationRoots = Map(
         1 -> Set(DIKey.get[MemoizedInstance], DIKey.get[MemoizedLevel1])
       ),
-      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef() {
+      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef {
         make[MemoizedLevel2].from(MemoizedLevel2(UUID.randomUUID()))
       },
       activation = distage.Activation(Repo -> Repo.Prod),
@@ -133,7 +133,7 @@ class SameLevel_1_2_WithAdditionalLevel3 extends DistageMemoizationEnvsTest {
 class SameLevel_1_WithModuleOverride extends DistageMemoizationEnvsTest {
   override protected def config: TestConfig = {
     super.config.copy(
-      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef() {
+      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef {
         make[TestInstance].from(MemoizationEnv.anotherTestInstance)
       }
     )
@@ -155,7 +155,7 @@ class SameLevel_1_WithActivationsOverride extends DistageMemoizationEnvsTest {
 trait DifferentLevelsWithLevel1 extends DistageMemoizationEnvsTest {
   override protected def config: TestConfig = {
     super.config.copy(
-      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef() {
+      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef {
         make[MemoizedInstance].from(MemoizedInstance(UUID.randomUUID()))
         make[MemoizedLevel1].from(MemoizedLevel1(UUID.randomUUID()))
         make[MemoizedLevel2].from(MemoizedLevel2(UUID.randomUUID()))
@@ -174,7 +174,7 @@ class DifferentLevelsWithLevel1InstanceOverride1 extends DifferentLevelsWithLeve
 class DifferentLevelsWithLevel1InstanceOverride2 extends DifferentLevelsWithLevel1 {
   override protected def config: TestConfig = {
     super.config.copy(
-      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef() {
+      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef {
         make[MemoizedLevel2].from(MemoizedLevel2(UUID.randomUUID()))
       }
     )
@@ -188,7 +188,7 @@ class DifferentLevelsWithLevel1InstanceOverride2 extends DifferentLevelsWithLeve
 class SameLevel_1_WithLevel2InstanceOverride extends DistageMemoizationEnvsTest {
   override protected def config: TestConfig = {
     super.config.copy(
-      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef() {
+      pluginConfig = super.config.pluginConfig overriddenBy new PluginDef {
         make[MemoizedLevel2].from(MemoizedLevel2(UUID.randomUUID()))
       }
     )
diff --git a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/tagged/DistageTestTaggedAxesExampleBase.scala b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/tagged/DistageTestTaggedAxesExampleBase.scala
index 928feaa41..bf5ea2a00 100644
--- a/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/tagged/DistageTestTaggedAxesExampleBase.scala
+++ b/distage/distage-testkit-scalatest/src/test/scala/izumi/distage/testkit/distagesuite/tagged/DistageTestTaggedAxesExampleBase.scala
@@ -16,7 +16,7 @@ abstract class DistageTestTaggedAxesExampleBase extends Spec3[ZIO] with AssertZI
       Set(Repo.Prod) -> Set(DIKey[PrdDep]),
       Set(Repo.Dummy) -> Set(DIKey[DummyDep]),
     ),
-    pluginConfig = super.config.pluginConfig.enablePackage("izumi.distage.testkit.distagesuite") ++ new PluginDef() {
+    pluginConfig = super.config.pluginConfig.enablePackage("izumi.distage.testkit.distagesuite") ++ new PluginDef {
       make[PrdDep]
       make[DummyDep]
       make[DepsCounters]