From 5e4ee5a6f446e62276f686a72fc8629dbb5b0ac6 Mon Sep 17 00:00:00 2001 From: Kai <450507+neko-kai@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:39:13 +0100 Subject: [PATCH] Fix #1648 forbid implicit trait construction, add explicit `makeTrait` and `fromTrait` methods --- .../distage/constructors/constructors.scala | 5 +- .../macros/AnyConstructorMacro.scala | 7 ++- .../constructors/AnyConstructorMacro.scala | 9 ++-- .../distage/constructors/constructors.scala | 5 +- .../distage/model/definition/ModuleDef.scala | 2 + .../dsl/AbstractBindingDefDSL.scala | 9 +++- .../model/definition/dsl/ModuleDefDSL.scala | 49 +++++++++++-------- .../injector/CglibProxiesTestJvm.scala | 2 +- .../injector/CompactPlanFormatterTest.scala | 4 +- .../scala/izumi/distage/StaticDSLTest.scala | 4 +- .../compat/ModuleBaseInstancesTest.scala | 12 ++--- .../scala/izumi/distage/dsl/DSLTest.scala | 34 ++++++------- .../distage/injector/AdvancedTypesTest.scala | 20 ++++---- .../izumi/distage/injector/ArityTest.scala | 8 +-- .../distage/injector/AutoTraitsTest.scala | 38 +++++++------- .../izumi/distage/injector/BasicTest.scala | 8 +-- .../injector/CircularDependenciesTest.scala | 14 +++--- .../distage/injector/FactoriesTest.scala | 10 ++-- .../distage/injector/HigherKindsTest.scala | 2 +- .../injector/ResourceEffectBindingsTest.scala | 6 +-- doc/microsite/src/main/tut/distage/basics.md | 13 +++-- .../src/main/tut/distage/reference.md | 2 + 22 files changed, 144 insertions(+), 119 deletions(-) diff --git a/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/constructors.scala b/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/constructors.scala index 28a87e61d6..6bd7ecabe4 100644 --- a/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/constructors.scala +++ b/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/constructors.scala @@ -15,9 +15,10 @@ import scala.language.experimental.macros as enableMacros * An implicitly summonable constructor for a type `T`, can generate constructors for: * * - concrete classes (using [[ClassConstructor]]) - * - traits and abstract classes ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]], using [[TraitConstructor]]) * - * Since version `1.1.0`, does not generate constructors "factory-like" traits and abstract classes, instead use [[FactoryConstructor]]. + * Since version `1.2.0`, does not generate constructors for traits and abstract classes, or for "factory-like" traits + * and abstract classes, instead use [[TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits]]) + * and [[FactoryConstructor]] respectively. ([[https://izumi.7mind.io/distage/basics#auto-factories Auto-Factories]]) * * Use [[ZEnvConstructor]] to generate constructors for `zio.ZEnvironment` values. * diff --git a/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/macros/AnyConstructorMacro.scala b/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/macros/AnyConstructorMacro.scala index 4d99a6776b..aefe5eb657 100644 --- a/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/macros/AnyConstructorMacro.scala +++ b/distage/distage-core-api/src/main/scala-2/izumi/distage/constructors/macros/AnyConstructorMacro.scala @@ -101,11 +101,14 @@ object AnyConstructorMacro { if (reflectionProvider.isConcrete(targetType)) { ClassConstructorMacro.mkClassConstructor[T](c) } else if (reflectionProvider.isWireableAbstract(targetType)) { - TraitConstructorMacro.mkTraitConstructor[T](c) + c.abort( + c.enclosingPosition, + s"AnyConstructor failure: $targetType is a trait or an abstract class, use makeTrait or fromTrait to wire traits.", + ) } else if (reflectionProvider.isFactory(targetType)) { c.abort( c.enclosingPosition, - s"""AnyConstructor failure: $targetType is a Factory, use makeFactory or fromFactory to wire factories.""".stripMargin, + s"AnyConstructor failure: $targetType is a Factory, use makeFactory or fromFactory to wire factories.", ) } else { c.abort( diff --git a/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/AnyConstructorMacro.scala b/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/AnyConstructorMacro.scala index a0d4b86ae4..0e62a4a723 100644 --- a/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/AnyConstructorMacro.scala +++ b/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/AnyConstructorMacro.scala @@ -33,13 +33,14 @@ object AnyConstructorMacro { tpeDeref match { case _: ConstantType | _: TermRef => true; case _ => false } }) { ClassConstructorMacro.makeImpl[R](util) - } else if ({ - context.isWireableTrait - }) { + } else if (context.isWireableTrait) { TraitConstructorMacro.makeImpl[R](util, context) + report.errorAndAbort( + s"AnyConstructor failure: ${Type.show[R]} is a trait or an abstract class, use makeTrait or fromTrait to wire traits." + ) } else if (context.isFactoryOrTrait) { report.errorAndAbort( - s"""AnyConstructor failure: ${Type.show[R]} is a Factory, use makeFactory or fromFactory to wire factories.""".stripMargin + s"AnyConstructor failure: ${Type.show[R]} is a Factory, use makeFactory or fromFactory to wire factories." ) } else { report.errorAndAbort( diff --git a/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/constructors.scala b/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/constructors.scala index ed66b10dcb..6d323f010b 100644 --- a/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/constructors.scala +++ b/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/constructors.scala @@ -15,9 +15,10 @@ import zio.ZEnvironment * An implicitly summonable constructor for a type `T`, can generate constructors for: * * - concrete classes (using [[ClassConstructor]]) - * - traits and abstract classes ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]], using [[TraitConstructor]]) * - * Since version `1.1.0`, does not generate constructors "factory-like" traits and abstract classes, instead use [[FactoryConstructor]]. + * Since version `1.2.0`, does not generate constructors for traits and abstract classes, or for "factory-like" traits + * and abstract classes, instead use [[TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits]]) + * and [[FactoryConstructor]] respectively. ([[https://izumi.7mind.io/distage/basics#auto-factories Auto-Factories]]) * * Use [[ZEnvConstructor]] to generate constructors for `zio.ZEnvironment` values. * diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleDef.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleDef.scala index a13c5a4428..bc7b668c72 100644 --- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleDef.scala +++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/ModuleDef.scala @@ -22,8 +22,10 @@ import izumi.distage.model.definition.dsl.ModuleDefDSL * * Singleton bindings: * - `make[X]` = create X using its constructor + * - `makeTrait[X]` = create an abstract class or a trait `X` using [[izumi.distage.constructors.TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]]) * - `makeFactory[X]` = create a "factory-like" abstract class or a trait `X` using [[izumi.distage.constructors.FactoryConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]]) * - `make[X].from[XImpl]` = bind X to its subtype XImpl using XImpl's constructor + * - `make[X].fromTrait[XImpl]` = bind X to its abstract class or a trait subtype XImpl, deriving constructor using [[izumi.distage.constructors.TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]]) * - `make[X].fromFactory[XImpl]` = bind X to its "factory-like" abstract class or a trait subtype XImpl, deriving constructor using [[izumi.distage.constructors.FactoryConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]]) * - `make[X].from(myX)` = bind X to an already existing instance `myX` * - `make[X].from { y: Y => new X(y) }` = bind X to an instance of X constructed by a given [[izumi.distage.model.providers.Functoid Functoid]] requesting an Y parameter diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala index ddc7abdaf0..f13182bed9 100644 --- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala +++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/AbstractBindingDefDSL.scala @@ -1,6 +1,6 @@ package izumi.distage.model.definition.dsl -import izumi.distage.constructors.FactoryConstructor +import izumi.distage.constructors.{FactoryConstructor, TraitConstructor} import izumi.distage.model.definition.* import izumi.distage.model.definition.Binding.{EmptySetBinding, ImplBinding, SetElementBinding, SingletonBinding} import izumi.distage.model.definition.dsl.AbstractBindingDefDSL.SetElementInstruction.ElementAddTags @@ -149,6 +149,12 @@ trait AbstractBindingDefDSL[BindDSL[_], BindDSLAfterFrom[_], SetDSL[_]] extends _bindDSL[T](ref) } + /** @see [[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]] */ + final protected[this] def makeTrait[T: Tag: TraitConstructor]: BindDSLAfterFrom[T] = { + val ref = _registered(new SingletonRef(Bindings.provider[T](TraitConstructor[T]))) + _bindDSLAfterFrom[T](ref) + } + /** @see [[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]] */ final protected[this] def makeFactory[T: Tag: FactoryConstructor]: BindDSLAfterFrom[T] = { val ref = _registered(new SingletonRef(Bindings.provider[T](FactoryConstructor[T]))) @@ -194,6 +200,7 @@ trait AbstractBindingDefDSL[BindDSL[_], BindDSLAfterFrom[_], SetDSL[_]] extends final protected[this] def _make[T: Tag](provider: Functoid[T])(implicit pos: CodePositionMaterializer): BindDSL[T] = self._make[T](provider) final protected[this] def makeFactory[T: Tag: FactoryConstructor]: BindDSLAfterFrom[T] = self.makeFactory[T] + final protected[this] def makeTrait[T: Tag: TraitConstructor]: BindDSLAfterFrom[T] = self.makeTrait[T] /** * Avoid `discarded non-Unit value` warning. diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala index 970686cec7..b0e6f2cb87 100644 --- a/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala +++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/definition/dsl/ModuleDefDSL.scala @@ -1,7 +1,7 @@ package izumi.distage.model.definition.dsl import izumi.distage.LocalContext -import izumi.distage.constructors.{AnyConstructor, FactoryConstructor, ZEnvConstructor} +import izumi.distage.constructors.{AnyConstructor, FactoryConstructor, TraitConstructor, ZEnvConstructor} import izumi.distage.model.definition.* import izumi.distage.model.definition.dsl.AbstractBindingDefDSL.* import izumi.distage.model.definition.dsl.AbstractBindingDefDSL.MultiSetElementInstruction.MultiAddTags @@ -41,8 +41,10 @@ import scala.collection.immutable.HashSet * * Singleton bindings: * - `make[X]` = create X using its constructor + * - `makeTrait[X]` = create an abstract class or a trait `X` using [[izumi.distage.constructors.TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]]) * - `makeFactory[X]` = create a "factory-like" abstract class or a trait `X` using [[izumi.distage.constructors.FactoryConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]]) * - `make[X].from[XImpl]` = bind X to its subtype XImpl using XImpl's constructor + * - `make[X].fromTrait[XImpl]` = bind X to its abstract class or a trait subtype XImpl, deriving constructor using [[izumi.distage.constructors.TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]]) * - `make[X].fromFactory[XImpl]` = bind X to its "factory-like" abstract class or a trait subtype XImpl, deriving constructor using [[izumi.distage.constructors.FactoryConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]]) * - `make[X].from(myX)` = bind X to an already existing instance `myX` * - `make[X].from { y: Y => new X(y) }` = bind X to an instance of X constructed by a given [[izumi.distage.model.providers.Functoid Functoid]] requesting an Y parameter @@ -116,24 +118,6 @@ object ModuleDefDSL { final def fromValue[I <: T: Tag](instance: I): AfterBind = bind(ImplDef.InstanceImpl(SafeType.get[I], instance)) - /** - * Defines local context with empty local module and local keys - */ - def fromLocalContext[F[_], R](defn: LocalContextDef[F[R]])(implicit @unused ev: T =:= LocalContext[F, R]): LocalContextDSL[F, R, AfterBind] = { - new LocalContextDSL[F, R, AfterBind](defn.module, Set.empty, bind, defn.function).bound() - } - - /** - * Defines local context with empty local module and local keys, specialised for Identity - */ - def fromLocalContext[R]( - defn: LocalContextDef[R] - )(implicit ev: T =:= LocalContext[Identity, R], - dummyImplicit: DummyImplicit, - ): LocalContextDSL[Identity, R, AfterBind] = { - fromLocalContext[Identity, R](defn) - } - /** * A function that receives its arguments from DI object graph, including named instances via [[izumi.distage.model.definition.Id]] annotation. * @@ -194,9 +178,30 @@ object ModuleDefDSL { final def from[I <: T](function: Functoid[I]): AfterBind = bind(ImplDef.ProviderImpl(function.get.ret, function.get)) + /** @see [[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]] */ + final def fromTrait[I <: T: TraitConstructor]: AfterBind = + from[I](TraitConstructor[I]) + /** @see [[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]] */ - final def fromFactory[I <: T: FactoryConstructor]: AfterBind = { + final def fromFactory[I <: T: FactoryConstructor]: AfterBind = from[I](FactoryConstructor[I]) + + /** + * Defines local context with empty local module and local keys + */ + def fromLocalContext[F[_], R](defn: LocalContextDef[F[R]])(implicit @unused ev: T =:= LocalContext[F, R]): LocalContextDSL[F, R, AfterBind] = { + new LocalContextDSL[F, R, AfterBind](defn.module, Set.empty, bind, defn.function).bound() + } + + /** + * Defines local context with empty local module and local keys, specialised for Identity + */ + def fromLocalContext[R]( + defn: LocalContextDef[R] + )(implicit ev: T =:= LocalContext[Identity, R], + dummyImplicit: DummyImplicit, + ): LocalContextDSL[Identity, R, AfterBind] = { + fromLocalContext[Identity, R](defn) } /** @@ -360,6 +365,10 @@ object ModuleDefDSL { final def addValue[I <: T: Tag](instance: I)(implicit pos: CodePositionMaterializer): AfterAdd = appendElement(ImplDef.InstanceImpl(SafeType.get[I], instance), pos) + /** @see [[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]] */ + final def addTrait[I <: T: Tag: TraitConstructor](implicit pos: CodePositionMaterializer): AfterAdd = + add[I](TraitConstructor[I]) + /** @see [[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]] */ final def addFactory[I <: T: Tag: FactoryConstructor](implicit pos: CodePositionMaterializer): AfterAdd = add[I](FactoryConstructor[I]) diff --git a/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala b/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala index 349eb485b5..e30fd2d536 100644 --- a/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala +++ b/distage/distage-core/.jvm/src/test/scala/izumi/distage/injector/CglibProxiesTestJvm.scala @@ -22,7 +22,7 @@ class CglibProxiesTestJvm extends AnyWordSpec with MkInjector with ScalatestGuar val definition = PlannerInput.everything(new ModuleDef { make[Circular2] - make[Circular1] + makeTrait[Circular1] }) val injector = mkInjector() diff --git a/distage/distage-core/src/test/scala-2/izumi/distage/injector/CompactPlanFormatterTest.scala b/distage/distage-core/src/test/scala-2/izumi/distage/injector/CompactPlanFormatterTest.scala index a5a8071303..8ed6c35182 100644 --- a/distage/distage-core/src/test/scala-2/izumi/distage/injector/CompactPlanFormatterTest.scala +++ b/distage/distage-core/src/test/scala-2/izumi/distage/injector/CompactPlanFormatterTest.scala @@ -29,8 +29,8 @@ class CompactPlanFormatterTest extends AnyWordSpec with MkInjector { make[JustTrait].from[Impl1] make[OptionT[scala.Either[Nothing, _], Unit]].from(OptionT[Either[Nothing, _], Unit](Right(None))) make[K1[T1]].from(new K1[T1] {}) - make[W1.T2] - make[W2.T2] + makeTrait[W1.T2] + makeTrait[W2.T2] })) val formatted = plan.render().replaceAll("\u001B\\[[;\\d]*m", "") diff --git a/distage/distage-core/src/test/scala/izumi/distage/StaticDSLTest.scala b/distage/distage-core/src/test/scala/izumi/distage/StaticDSLTest.scala index deeb7a553c..2efbc38bcc 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/StaticDSLTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/StaticDSLTest.scala @@ -20,7 +20,7 @@ class StaticDSLTest extends AnyWordSpec { .from[TestClass] make[TestDependency0] .named("named.test.dependency.0") - .from[TestDependency0] + .fromTrait[TestDependency0] make[TestInstanceBinding] .named("named.test") .from(TestInstanceBinding()) @@ -29,7 +29,7 @@ class StaticDSLTest extends AnyWordSpec { many[JustTrait] .add[Impl0] .add(new Impl1) - .add[JustTrait] + .addTrait[JustTrait] many[JustTrait] .named("named.set") .add(new Impl2()) diff --git a/distage/distage-core/src/test/scala/izumi/distage/compat/ModuleBaseInstancesTest.scala b/distage/distage-core/src/test/scala/izumi/distage/compat/ModuleBaseInstancesTest.scala index 5576f8c158..9dd73dbed0 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/compat/ModuleBaseInstancesTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/compat/ModuleBaseInstancesTest.scala @@ -1,9 +1,9 @@ package izumi.distage.compat -import cats.syntax.all._ -import izumi.distage.fixtures.BasicCases._ -import izumi.distage.model.definition.Bindings.binding -import izumi.distage.model.definition._ +import cats.syntax.all.* +import izumi.distage.fixtures.BasicCases.* +import izumi.distage.model.definition.Bindings.{binding, bindingTrait} +import izumi.distage.model.definition.* import org.scalatest.wordspec.AnyWordSpec final class ModuleBaseInstancesTest extends AnyWordSpec { @@ -20,12 +20,12 @@ final class ModuleBaseInstancesTest extends AnyWordSpec { } val mod3_1: Module = new ModuleDef { - make[TestDependency1] + makeTrait[TestDependency1] } val mod3_2 = Module.empty - val mod3 = (mod3_1 |+| mod3_2) :+ binding[NotInContext] + val mod3 = (mod3_1 |+| mod3_2) :+ bindingTrait[NotInContext] val mod4 = Module.make( Set( diff --git a/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala b/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala index f6a6fcbd04..b63ad80e42 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/dsl/DSLTest.scala @@ -30,7 +30,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { make[TestClass] .named("named.test.class") - make[TestDependency0] + makeTrait[TestDependency0] .named("named.test.dependency.0") make[TestInstanceBinding] .named("named.test") @@ -47,7 +47,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { .add[Impl3] make[TestDependency0].namedByImpl.from[TestImpl0] - make[TestDependency0].namedByImpl + makeTrait[TestDependency0].namedByImpl } assert(definition != null) @@ -161,12 +161,12 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { } val mod3_1 = new ModuleDef { - make[TestDependency1] + makeTrait[TestDependency1] } val mod3_2 = Module.empty - val mod3 = (mod3_1 ++ mod3_2) :+ Bindings.binding[NotInContext] + val mod3 = (mod3_1 ++ mod3_2) :+ Bindings.bindingTrait[NotInContext] val mod4: ModuleBase = Module.make { Set( @@ -201,7 +201,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { make[TestClass] } object mod2 extends ModuleDef { - make[TestDependency0] + makeTrait[TestDependency0] } mod1 ++ mod2 @@ -214,7 +214,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { make[TestClass] } class mod2 extends ModuleDef { - make[TestDependency0] + makeTrait[TestDependency0] } val _: Module = new mod1 ++ new mod2 @@ -226,11 +226,11 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { val definition: ModuleBase = new ModuleDef { tag("tag1") make[TestClass] - make[TestDependency0].tagged("sniv") + makeTrait[TestDependency0].tagged("sniv") tag("tag2") } - assert(definition.bindings == Set(Bindings.binding[TestClass].addTags(Set("tag1", "tag2")), Bindings.binding[TestDependency0].addTags(Set("tag1", "tag2", "sniv")))) + assert(definition.bindings == Set(Bindings.binding[TestClass].addTags(Set("tag1", "tag2")), Bindings.bindingTrait[TestDependency0].addTags(Set("tag1", "tag2", "sniv")))) } "ModuleBuilder supports tags; same bindings with different tags are NOT merged (tag merging removed in 0.11.0)" in { @@ -299,8 +299,8 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { import BasicCase1._ val def1 = new ModuleDef { - make[TestDependency0].tagged("a") - make[TestDependency0].tagged("b") + makeTrait[TestDependency0].tagged("a") + makeTrait[TestDependency0].tagged("b") tag("1") } @@ -308,7 +308,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { val def2 = new ModuleDef { tag("2") - make[TestDependency0].tagged("x").tagged("y") + makeTrait[TestDependency0].tagged("x").tagged("y") } val definition = def1 ++ def2 @@ -324,7 +324,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { val tags12: Seq[BindingTag] = Seq("1", "2") val def1 = new ModuleDef { - make[TestDependency0].tagged("a").tagged("b") + makeTrait[TestDependency0].tagged("a").tagged("b") tag(tags12: _*) } @@ -332,7 +332,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { val def2 = new ModuleDef { tag("2", "3") - make[TestDependency0].tagged("x").tagged("y") + makeTrait[TestDependency0].tagged("x").tagged("y") } val definition = def1 overriddenBy def2 @@ -344,14 +344,14 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { "support zero element" in { import BasicCase1._ val def1 = new ModuleDef { - make[TestDependency0] + makeTrait[TestDependency0] } val def2 = new ModuleDef { - make[TestDependency0] + makeTrait[TestDependency0] } val def3 = new ModuleDef { - make[TestDependency1] + makeTrait[TestDependency1] } assert((def1 overriddenBy Module.empty) == def1) @@ -363,7 +363,7 @@ class DSLTest extends AnyWordSpec with MkInjector with should.Matchers { import BasicCase1._ trait Def1 extends ModuleDef { - make[TestDependency0] + makeTrait[TestDependency0] tag("tag2") } diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/AdvancedTypesTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/AdvancedTypesTest.scala index 31f73f89aa..77487f6de5 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/AdvancedTypesTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/AdvancedTypesTest.scala @@ -54,7 +54,7 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards val definition = PlannerInput.everything(new ModuleDef { make[DepA] - make[TestTrait] + makeTrait[TestTrait] }) val injector = mkInjector() @@ -69,7 +69,7 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards val definition = PlannerInput.everything(new ModuleDef { make[Dependency1 @Id("special")] - make[Trait1] + makeTrait[Trait1] }) val injector = mkInjector() @@ -88,7 +88,7 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards val definition = PlannerInput.everything(new ModuleDef { make[Dep] make[Dep2] - make[Trait2 with Trait1].from[Trait6] + make[Trait2 with Trait1].fromTrait[Trait6] }) val injector = mkInjector() @@ -106,9 +106,9 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards val definition = PlannerInput.everything(new ModuleDef { make[Dep] make[Dep2] - make[Trait1 { def dep: Dep2 }].from[Trait3[Dep2]] - make[Trait1 { def dep: Dep }].from[Trait3[Dep]] - make[{ def dep: Dep }].from[Trait6] + make[Trait1 { def dep: Dep2 }].fromTrait[Trait3[Dep2]] + make[Trait1 { def dep: Dep }].fromTrait[Trait3[Dep]] + make[{ def dep: Dep }].fromTrait[Trait6] }) val injector = mkInjector() @@ -132,7 +132,7 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards make[Dep2] locally { type X[A] = Trait1[Dep, A] - make[X[T]] + makeTrait[X[T]] } } @@ -149,7 +149,7 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards "light type tags can handle abstract structural refinement types" in { import TypesCase3._ - class Definition[T >: Null: Tag, G <: T { def dep: Dep }: Tag: AnyConstructor] extends ModuleDef { + class Definition[T >: Null: Tag, G <: T { def dep: Dep }: Tag: TraitConstructor] extends ModuleDef { make[Dep] make[T { def dep2: Dep }].from(() => null.asInstanceOf[T { def dep2: Dep }]) make[T { def dep: Dep }].from[G] @@ -170,7 +170,7 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards "handle abstract `with` types" in { import TypesCase3._ - class Definition[T: Tag, G <: T with Trait1: Tag: AnyConstructor, C <: T with Trait4: Tag: AnyConstructor] extends ModuleDef { + class Definition[T: Tag, G <: T with Trait1: Tag: TraitConstructor, C <: T with Trait4: Tag: TraitConstructor] extends ModuleDef { make[Dep] make[T with Trait4].from[C] make[T with Trait1].from[G] @@ -201,7 +201,7 @@ class AdvancedTypesTest extends AnyWordSpec with MkInjector with ScalatestGuards class Definition[T <: Dep: Tag: AnyConstructor, K >: Trait5[T]: Tag] extends ModuleDef { make[T] - make[Trait3[T] with K].from[Trait5[T]] + make[Trait3[T] with K].fromTrait[Trait5[T]] } val definition = PlannerInput.everything(new Definition[Dep, Trait4]) diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/ArityTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/ArityTest.scala index f6daf11dda..d2052d51f2 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/ArityTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/ArityTest.scala @@ -25,7 +25,7 @@ class ArityTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[Beep[Int]] - make[BopTrait[Int]] + makeTrait[BopTrait[Int]] }) val context = Injector.Standard().produce(definition).unsafeGet() @@ -39,7 +39,7 @@ class ArityTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[Beep[Int]] - make[BopAbstractClass[Int]] + makeTrait[BopAbstractClass[Int]] }) val context = Injector.Standard().produce(definition).unsafeGet() @@ -72,8 +72,8 @@ class ArityTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[NoArgClass] - make[NoArgTrait] - make[NoArgAbstractClass] + makeTrait[NoArgTrait] + makeTrait[NoArgAbstractClass] }) val context = Injector.Standard().produce(definition).unsafeGet() diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/AutoTraitsTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/AutoTraitsTest.scala index 2011464251..9d4e1f9c49 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/AutoTraitsTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/AutoTraitsTest.scala @@ -1,7 +1,7 @@ package izumi.distage.injector -import izumi.distage.constructors.AnyConstructor -import izumi.distage.fixtures.TraitCases._ +import izumi.distage.constructors.TraitConstructor +import izumi.distage.fixtures.TraitCases.* import izumi.distage.fixtures.TypesCases.TypesCase3 import izumi.distage.fixtures.TypesCases.TypesCase6 import izumi.distage.model.PlannerInput @@ -19,7 +19,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { } "construct a basic trait" in { - val traitCtor = AnyConstructor[Aaa].get + val traitCtor = TraitConstructor[Aaa].get val value = traitCtor.unsafeApply(Seq(TypedRef.byName(5), TypedRef.byName(false))).asInstanceOf[Aaa] @@ -32,7 +32,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { val definition = new ModuleDef { make[Dependency1] - make[TestTrait] + makeTrait[TestTrait] } val injector = mkNoCyclesInjector() @@ -49,7 +49,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { val definition = new ModuleDef { make[Dependency1] - make[TestTrait].named("named-trait").from[TestTrait] + make[TestTrait].named("named-trait").fromTrait[TestTrait] } val injector = mkNoCyclesInjector() @@ -65,9 +65,9 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { import TraitCase2._ val definition = new ModuleDef { - make[Trait3] - make[Trait2] - make[Trait1] + makeTrait[Trait3] + makeTrait[Trait2] + makeTrait[Trait1] make[Dependency3] make[Dependency2] make[Dependency1] @@ -93,7 +93,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { import TraitCase2._ val definition = new ModuleDef { - make[Trait2].from[Trait3] + make[Trait2].fromTrait[Trait3] make[Dependency3] make[Dependency2] make[Dependency1] @@ -112,7 +112,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { import TraitCase3._ val definition = PlannerInput.everything(new ModuleDef { - make[ATraitWithAField] + makeTrait[ATraitWithAField] }) val injector = mkInjector() @@ -128,8 +128,8 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[Dep].named("A").from[DepA] make[Dep].named("B").from[DepB] - make[Trait] - make[Trait1] + makeTrait[Trait] + makeTrait[Trait1] }) val injector = mkInjector() @@ -150,7 +150,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { import TraitCase5._ val definition = PlannerInput.everything(new ModuleDef { - make[TestTrait] + makeTrait[TestTrait] make[Dep] }) @@ -167,7 +167,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { import TraitCase5._ val definition = PlannerInput.everything(new ModuleDef { - make[TestTraitAny { def dep: Dep }] + makeTrait[TestTraitAny { def dep: Dep }] make[Dep] }) @@ -181,7 +181,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { "can instantiate structural types" in { val definition = PlannerInput.everything(new ModuleDef { - make[{ def a: Int }] + makeTrait[{ def a: Int }] make[Int].from(5) }) @@ -198,7 +198,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[Dep] make[Dep2] - make[Trait2 with (Trait2 with (Trait2 with Trait1))] + makeTrait[Trait2 with (Trait2 with (Trait2 with Trait1))] }) val injector = mkNoCyclesInjector() @@ -217,7 +217,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[Dep] make[Dep2] - make[Trait1 with Trait2] + makeTrait[Trait1 with Trait2] }) val injector = mkNoCyclesInjector() @@ -236,7 +236,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[Dep] make[AnyValDep] - make[TestTrait] + makeTrait[TestTrait] }) val injector = mkInjector() @@ -255,7 +255,7 @@ class AutoTraitsTest extends AnyWordSpec with MkInjector { val definition = PlannerInput.everything(new ModuleDef { make[Dependency1] make[Dependency2] - make[X].from[XImpl] + make[X].fromTrait[XImpl] }) val injector = mkInjector() diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/BasicTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/BasicTest.scala index 6204c626e2..403604e505 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/BasicTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/BasicTest.scala @@ -23,9 +23,9 @@ class BasicTest extends AnyWordSpec with MkInjector with ScalatestGuards { val definition = PlannerInput( new ModuleDef { make[TestClass] - make[TestDependency3] + makeTrait[TestDependency3] make[TestDependency0].from[TestImpl0] - make[TestDependency1] + makeTrait[TestDependency1] make[TestCaseClass] make[LocatorDependent] make[TestInstanceBinding].from(TestInstanceBinding()) @@ -132,7 +132,7 @@ class BasicTest extends AnyWordSpec with MkInjector with ScalatestGuards { many[JustTrait].named("named.empty.set") many[JustTrait] - .add[JustTrait] + .addTrait[JustTrait] .add(new Impl1) many[JustTrait] @@ -312,7 +312,7 @@ class BasicTest extends AnyWordSpec with MkInjector with ScalatestGuards { import BasicCase4.* val definition = PlannerInput.everything(new ModuleDef { - make[Dependency].named("special") + makeTrait[Dependency].named("special") make[TestClass] }) diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala index baf6115cfd..b28d3f4308 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/CircularDependenciesTest.scala @@ -16,8 +16,8 @@ class CircularDependenciesTest extends AnyWordSpec with MkInjector with Scalates import CircularCase2._ val definition = PlannerInput.everything(new ModuleDef { - make[CircularBad1] - make[CircularBad2] + makeTrait[CircularBad1] + makeTrait[CircularBad2] }) val injector = mkInjector() @@ -35,10 +35,10 @@ class CircularDependenciesTest extends AnyWordSpec with MkInjector with Scalates import CircularCase2._ val definition = PlannerInput.everything(new ModuleDef { - make[Circular3] - make[Circular1] - make[Circular2] - make[Circular5] + makeTrait[Circular3] + makeTrait[Circular1] + makeTrait[Circular2] + makeTrait[Circular5] makeFactory[Circular4] }) @@ -82,7 +82,7 @@ class CircularDependenciesTest extends AnyWordSpec with MkInjector with Scalates import CircularCase3._ val definition = PlannerInput.everything(new ModuleDef { - make[TraitSelfReference] + makeTrait[TraitSelfReference] }) val injector = mkNoProxiesInjector() diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/FactoriesTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/FactoriesTest.scala index 0b6f7972df..e6874d152b 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/FactoriesTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/FactoriesTest.scala @@ -17,7 +17,7 @@ class FactoriesTest extends AnyWordSpec with MkInjector with ScalatestGuards { val definition = PlannerInput.everything(new ModuleDef { makeFactory[Factory] - make[Dependency] + makeTrait[Dependency] makeFactory[OverridingFactory] makeFactory[AssistedFactory] makeFactory[AbstractFactory] @@ -74,7 +74,7 @@ class FactoriesTest extends AnyWordSpec with MkInjector with ScalatestGuards { val definition = PlannerInput.everything(new ModuleDef { makeFactory[NamedAssistedFactory] - make[Dependency] + makeTrait[Dependency] make[Dependency].named("special").from(SpecialDep()) make[Dependency].named("veryspecial").from(VerySpecialDep()) }) @@ -100,7 +100,7 @@ class FactoriesTest extends AnyWordSpec with MkInjector with ScalatestGuards { val definition = PlannerInput.everything(new ModuleDef { makeFactory[MixedAssistendNonAssisted] - make[Dependency] + makeTrait[Dependency] }) val injector = mkInjector() @@ -239,7 +239,7 @@ class FactoriesTest extends AnyWordSpec with MkInjector with ScalatestGuards { import FactoryCase1.* val definition = PlannerInput.everything(new ModuleDef { - make[Dependency] + makeTrait[Dependency] make[TestClass] makeFactory[Factory] }) @@ -290,7 +290,7 @@ class FactoriesTest extends AnyWordSpec with MkInjector with ScalatestGuards { import FactoryCase1.* val definition = PlannerInput.everything(new ModuleDef { - make[Dependency] + makeTrait[Dependency] make[TestClass] makeFactory[AbstractClassFactory] }) diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala index 2e979fadea..a39a2eff6b 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/HigherKindsTest.scala @@ -16,7 +16,7 @@ class HigherKindsTest extends AnyWordSpec with MkInjector { make[TestTrait].from[TestServiceClass[F]] make[TestServiceClass[F]] - make[TestServiceTrait[F]] + makeTrait[TestServiceTrait[F]] make[Int].named("TestService").from(getResult) make[F[String]].from { (res: Int @Id("TestService")) => Pointed[F].point(s"Hello $res!") diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/ResourceEffectBindingsTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/ResourceEffectBindingsTest.scala index f1f7aab481..ca3866ae60 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/ResourceEffectBindingsTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/ResourceEffectBindingsTest.scala @@ -363,11 +363,11 @@ class ResourceEffectBindingsTest extends AnyWordSpec with MkInjector with GivenW import BasicCase1._ val definition = PlannerInput.everything(new ModuleDef { - make[NotInContext] + makeTrait[NotInContext] make[TestClass] - make[TestDependency3] + makeTrait[TestDependency3] make[TestDependency0].from[TestImpl0] - make[TestDependency1] + makeTrait[TestDependency1] make[TestCaseClass] make[LocatorDependent] make[TestInstanceBinding].fromResource(new Lifecycle.Basic[Option, TestInstanceBinding] { diff --git a/doc/microsite/src/main/tut/distage/basics.md b/doc/microsite/src/main/tut/distage/basics.md index 5142b4b14d..dca8e11bed 100644 --- a/doc/microsite/src/main/tut/distage/basics.md +++ b/doc/microsite/src/main/tut/distage/basics.md @@ -1125,12 +1125,11 @@ runtime.unsafeRun { ## Auto-Traits -distage can instantiate traits and structural types. All unimplemented fields in a trait, or a refinement are filled in from the object graph. +distage can instantiate traits and structural types. -Trait implementations are derived at compile-time by @scaladoc[TraitConstructor](izumi.distage.constructors.TraitConstructor) macro -and can be summoned at need. +Use `makeTrait[X]` or `make[X].fromTrait[Y]` to wire traits, abstract classes or a structural types. -If a suitable trait is specified as an implementation class for a binding, `TraitConstructor` will be used automatically: +All unimplemented fields in a trait, or a refinement are filled in from the object graph. Trait implementations are derived at compile-time by @scaladoc[TraitConstructor](izumi.distage.constructors.TraitConstructor) macro and can be summoned at need. Example: @@ -1195,8 +1194,8 @@ object PlusedInt { def module = new ModuleDef { make[Int].named("a").from(1) make[Int].named("b").from(2) - make[Pluser] - make[PlusedInt].from[PlusedInt.Impl] + makeTrait[Pluser] + make[PlusedInt].fromTrait[PlusedInt.Impl] } Injector().produceRun(module) { @@ -1250,7 +1249,7 @@ it with a trait instead. Example: } Injector().produceRun(module overriddenBy new ModuleDef { - make[PlusedInt].from[OverridenPlusedIntImpl] + make[PlusedInt].fromTrait[OverridenPlusedIntImpl] }) { plusedInt: PlusedInt => plusedInt.result() diff --git a/doc/microsite/src/main/tut/distage/reference.md b/doc/microsite/src/main/tut/distage/reference.md index 7685087292..5961c867d4 100644 --- a/doc/microsite/src/main/tut/distage/reference.md +++ b/doc/microsite/src/main/tut/distage/reference.md @@ -5,8 +5,10 @@ ``` Singleton bindings: - `make[X]` = create X using its constructor + - `makeTrait[X]` = create an abstract class or a trait `X` using [[izumi.distage.constructors.TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]]) - `makeFactory[X]` = create a "factory-like" abstract class or a trait `X` using [[izumi.distage.constructors.FactoryConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]]) - `make[X].from[XImpl]` = bind X to its subtype XImpl using XImpl's constructor + - `make[X].fromTrait[XImpl]` = bind X to its abstract class or a trait subtype XImpl, deriving constructor using [[izumi.distage.constructors.TraitConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-traits Auto-Traits feature]]) - `make[X].fromFactory[XImpl]` = bind X to its "factory-like" abstract class or a trait subtype XImpl, deriving constructor using [[izumi.distage.constructors.FactoryConstructor]] ([[https://izumi.7mind.io/distage/basics.html#auto-factories Auto-Factories feature]]) - `make[X].from(myX)` = bind X to an already existing instance `myX` - `make[X].from { y: Y => new X(y) }` = bind X to an instance of X constructed by a given [[izumi.distage.model.providers.Functoid Functoid]] requesting an Y parameter