diff --git a/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/HasConstructorMacro.scala b/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/HasConstructorMacro.scala index 0b89011016..ce6c1c6c43 100644 --- a/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/HasConstructorMacro.scala +++ b/distage/distage-core-api/src/main/scala-3/izumi/distage/constructors/HasConstructorMacro.scala @@ -37,20 +37,30 @@ object HasConstructorMacro { } val lamExpr = util.wrapIntoFunctoidRawLambda[R](lamParams) { - case (_, allParams) => - allParams.zip(lamParams) match { + case (lambdaSym, allParams) => + (allParams.zip(lamParams) match { case (headParam, ParamRepr(_, _, TypeReprAsType('[t]))) :: params => + def addAccum[A <: zio.Has[?], B](exprAcc: Typed, arg: Term)(using Type[B]): Typed = { + val Typed(term, exprTpe) = exprAcc + given Type[A] = exprTpe.tpe.asType.asInstanceOf[Type[A]] + + val addExpr = '{ zio.Has.HasSyntax[A](${ term.asExprOf[A] }).add[B](${ arg.asExprOf[B] })(summonInline[Tag[B]]) } + Typed(addExpr.asTerm, TypeTree.of[A & zio.Has[B]]) + } + params - .foldLeft('{ zio.Has.apply[t](${ headParam.asExprOf[t] })(summonInline[Tag[t]]) }) { + .foldLeft( + Typed('{ zio.Has.apply[t](${ headParam.asExprOf[t] })(summonInline[Tag[t]]) }.asTerm, TypeTree.of[zio.Has[t]]) + ) { case (expr, (arg, ParamRepr(_, _, tpe))) => tpe.asType match { - case '[g] => - '{ $expr.add(${ arg.asExprOf[g] })(summonInline[Tag[g]]) } + case '[b] => + addAccum[zio.Has[?], b](expr, arg) } - }.asTerm + } case _ => report.errorAndAbort(s"Impossible happened, empty Has intersection or malformed type ${typeRepr.show} in HasConstructorMacro") - } + }).changeOwner(lambdaSym) } val f = util.makeFunctoid[R](lamParams, lamExpr, '{ ProviderType.ZIOHas }) diff --git a/distage/distage-core-api/src/main/scala-3/izumi/distage/model/providers/FunctoidMacroMethods.scala b/distage/distage-core-api/src/main/scala-3/izumi/distage/model/providers/FunctoidMacroMethods.scala index 0e98b00a12..8ec620877a 100644 --- a/distage/distage-core-api/src/main/scala-3/izumi/distage/model/providers/FunctoidMacroMethods.scala +++ b/distage/distage-core-api/src/main/scala-3/izumi/distage/model/providers/FunctoidMacroMethods.scala @@ -275,7 +275,7 @@ object FunctoidMacro { val strExpr = Expr(str) '{ new DIKey.IdKey($safeTpe, $strExpr, None)(scala.compiletime.summonInline[IdContract[String]]) } case None => - '{ new DIKey.TypeKey($safeTpe) } + '{ new DIKey.TypeKey($safeTpe, None) } } } diff --git a/distage/distage-core/src/test/scala/izumi/distage/injector/ZIOHasInjectionTest.scala b/distage/distage-core/src/test/scala/izumi/distage/injector/ZIOHasInjectionTest.scala index b71af3ecdc..ac27dc87dc 100644 --- a/distage/distage-core/src/test/scala/izumi/distage/injector/ZIOHasInjectionTest.scala +++ b/distage/distage-core/src/test/scala/izumi/distage/injector/ZIOHasInjectionTest.scala @@ -294,6 +294,28 @@ class ZIOHasInjectionTest extends AnyWordSpec with MkInjector { assert(context.get[TestTrait].anyValDep.d eq context.get[Dep]) } + "Scala 3 regression test: support more than 2 dependencies in HasConstructor" in { + trait OpenTracingService + + type OpenTracing = Has[OpenTracingService] + + trait SttpBackend[F[_], +P] + + trait MyEndpoints[F[_, _]] + + trait ZioStreams + trait WebSockets + + trait MyPublisher + trait MyClient + + object MyPlugin extends ModuleDef { + make[MyClient].fromHas[OpenTracing with Has[MyPublisher] with Has[SttpBackend[Task, ZioStreams with WebSockets]] with Has[MyEndpoints[IO]], Nothing, MyClient] { + ??? : zio.ZIO[OpenTracing with Has[MyPublisher] with Has[SttpBackend[Task, ZioStreams with WebSockets]] with Has[MyEndpoints[IO]], Nothing, MyClient] + } + } + } + } }