Repository: 7mind/izumi
Pull request #850 (2020-01-22 20:47:36)

dealias types in constructor macros & ensure equality for generated singleton-type constructors


Patch:
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala
index 8135cc76d..97dfa8d08 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/AnyConstructorMacro.scala
@@ -91,7 +91,7 @@ object AnyConstructorMacro {
     val macroUniverse = StaticDIUniverse(c)
     val reflectionProvider = ReflectionProviderDefaultImpl(macroUniverse)
 
-    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T])
+    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T].dealias)
     requireConcreteTypeConstructor(c)("AnyConstructor", targetType)
 
     if (reflectionProvider.isConcrete(targetType)) {
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ClassConstructorMacro.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ClassConstructorMacro.scala
index a5ed08aea..6254e8d7e 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ClassConstructorMacro.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/ClassConstructorMacro.scala
@@ -16,7 +16,7 @@ object ClassConstructorMacro {
   def mkClassConstructor[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[ClassConstructor[T]] = {
     import c.universe._
 
-    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T])
+    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T].dealias)
     requireConcreteTypeConstructor(c)("ClassConstructor", targetType)
 
     targetType match {
@@ -28,7 +28,7 @@ object ClassConstructorMacro {
           case _ => q"${t.termSymbol}"
         }
         c.Expr[ClassConstructor[T]] {
-          q"{ new ${weakTypeOf[ClassConstructor[T]]}($providerMagnet.pure[$targetType]($term)) }"
+          q"{ new ${weakTypeOf[ClassConstructor[T]]}($providerMagnet.singleton[$targetType]($term)) }"
         }
 
       case _ =>
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala
index e4373bf0a..f21eca7a8 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/FactoryConstructorMacro.scala
@@ -25,7 +25,7 @@ object FactoryConstructorMacro {
     import macroUniverse.Wiring._
     import macroUniverse._
 
-    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T])
+    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T].dealias)
     requireConcreteTypeConstructor(c)("FactoryConstructor", targetType)
 
     val factory@Factory(factoryMethods, factoryTraitDependencies) = reflectionProvider.symbolToWiring(targetType)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/TraitConstructorMacro.scala b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/TraitConstructorMacro.scala
index a25ceb812..d2ac0253d 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/TraitConstructorMacro.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/constructors/macros/TraitConstructorMacro.scala
@@ -16,7 +16,7 @@ object TraitConstructorMacro {
   def mkTraitConstructor[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[TraitConstructor[T]] = {
     import c.universe._
 
-    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T])
+    val targetType = ReflectionUtil.norm(c.universe: c.universe.type)(weakTypeOf[T].dealias)
     requireConcreteTypeConstructor(c)("FactoryConstructor", targetType)
 
     val macroUniverse = StaticDIUniverse(c)
diff --git a/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala b/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala
index df8756851..afe280a31 100644
--- a/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala
+++ b/distage/distage-core-api/src/main/scala/izumi/distage/model/providers/ProviderMagnet.scala
@@ -187,6 +187,17 @@ object ProviderMagnet {
     )
   }
 
+  def singleton[A <: Singleton: Tag](a: A): ProviderMagnet[A] = {
+    new ProviderMagnet[A](
+      Provider.ProviderImpl[A](
+        parameters = Seq.empty,
+        ret = SafeType.get[A],
+        fun = (_: Seq[Any]) => a,
+        isGenerated = true,
+      )
+    )
+  }
+
   def identityKey(key: DIKey): ProviderMagnet[_] = {
     val tpe = key.tpe
     val symbolInfo = firstParamSymbolInfo(tpe)


Test patch:
diff --git a/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala b/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala
index 0a02a1ff2..2fd9af478 100644
--- a/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala
+++ b/distage/distage-core/src/test/scala/izumi/distage/impl/ProviderMagnetTest.scala
@@ -5,6 +5,8 @@ import izumi.distage.fixtures.BasicCases.BasicCase4.ClassTypeAnnT
 import izumi.distage.fixtures.ProviderCases.ProviderCase1
 import izumi.distage.model.providers.ProviderMagnet
 import izumi.distage.model.reflection.universe.RuntimeDIUniverse.TypedRef
+import izumi.fundamentals.platform.build.ProjectAttributeMacro
+import izumi.fundamentals.platform.language.IzScala.ScalaRelease
 import izumi.fundamentals.platform.language.Quirks._
 import org.scalatest.wordspec.AnyWordSpec
 
@@ -305,6 +307,29 @@ class ProviderMagnetTest extends AnyWordSpec {
       assert(fn.get.ret == SafeType.get[Int])
     }
 
+    "ProviderMagnet.singleton is correct" in {
+      val xa = new {}
+      val fn = ProviderMagnet.singleton[xa.type](xa)
+
+      assert(fn.get.unsafeApply(Seq()).asInstanceOf[AnyRef] eq xa)
+      assert(fn.get.parameters.isEmpty)
+      assert(fn.get.ret == SafeType.get[xa.type])
+    }
+
+    "ProviderMagnet.singleton is correct with constant types" in {
+      import Ordering.Implicits._
+      assume(ScalaRelease.parse(ProjectAttributeMacro.extractScalaVersion().get) >= ScalaRelease.`2_13`(0))
+      assertCompiles(
+        """
+      val fn = ProviderMagnet.singleton["xa"]("xa")
+
+      assert(fn.get.unsafeApply(Seq()) == "xa")
+      assert(fn.get.parameters.isEmpty)
+      assert(fn.get.ret == SafeType.get["xa"])
+        """
+      )
+    }
+
     "generic parameters without TypeTag should fail" in {
       assertTypeError(
         """def fn[T]  = ProviderMagnet.apply((x: T @Id("gentypeann")) => x).get"""