Skip to content

Commit 4f1f16f

Browse files
authored
handle type params in constructor (#355)
1 parent 1b153eb commit 4f1f16f

File tree

2 files changed

+52
-24
lines changed

2 files changed

+52
-24
lines changed

macros/src/main/scala-3/com/softwaremill/macwire/internals/ConstructorCrimper.scala

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,28 @@ private[macwire] class ConstructorCrimper[Q <: Quotes, T: Type](using val q: Q)(
5151
ctor
5252
}
5353

54-
lazy val constructorParamLists: Option[List[List[Symbol]]] = constructor.map(_.paramSymss)
54+
private def constructorParamTypes(ctorType: TypeRepr): List[List[TypeRepr]] = {
55+
ctorType match {
56+
case MethodType(_, paramTypes, retType) =>
57+
paramTypes.map(_.widen.simplified) :: constructorParamTypes(retType.simplified)
58+
case _ =>
59+
Nil
60+
}
61+
}
62+
63+
lazy val constructorParamLists: Option[List[List[(Symbol, TypeRepr)]]] = {
64+
constructor.map { c =>
65+
// paramSymss contains both type arg symbols (generic types) and value arg symbols
66+
val symLists = c.paramSymss.filter(_.forall(!_.isTypeDef))
67+
val ctorType =
68+
if (targetType.typeArgs.isEmpty) targetType.memberType(c)
69+
else targetType.memberType(c).appliedTo(targetType.typeArgs)
70+
val typeLists = constructorParamTypes(ctorType)
71+
symLists.zip(typeLists).map { case (syms, tpes) =>
72+
syms.zip(tpes)
73+
}
74+
}
75+
}
5576

5677
lazy val constructorArgs: Option[List[List[Term]]] = log.withBlock("Looking for targetConstructor arguments") {
5778
constructorParamLists.map(wireConstructorParamsWithImplicitLookups)
@@ -62,35 +83,28 @@ private[macwire] class ConstructorCrimper[Q <: Quotes, T: Type](using val q: Q)(
6283
constructorValue <- constructor
6384
constructorArgsValue <- constructorArgs
6485
} yield {
65-
val constructionMethodTree: Term = Select(New(TypeIdent(targetType.typeSymbol)), constructorValue)
86+
val constructionMethodTree: Term = {
87+
val ctor = Select(New(TypeIdent(targetType.typeSymbol)), constructorValue)
88+
if (targetType.typeArgs.isEmpty) ctor else ctor.appliedToTypes(targetType.typeArgs)
89+
}
6690
constructorArgsValue.foldLeft(constructionMethodTree)((acc: Term, args: List[Term]) => Apply(acc, args))
6791
}
6892
}
6993

70-
def wireConstructorParams(paramLists: List[List[Symbol]]): List[List[Term]] =
71-
paramLists.map(_.map(p => dependencyResolver.resolve(p, /*SI-4751*/ paramType(p))))
72-
73-
def wireConstructorParamsWithImplicitLookups(paramLists: List[List[Symbol]]): List[List[Term]] = paramLists.map {
74-
case params if params.forall(_.flags is Flags.Implicit) => params.map(resolveImplicitOrFail)
75-
case params => params.map(p => dependencyResolver.resolve(p, /*SI-4751*/ paramType(p)))
76-
}
77-
78-
private def resolveImplicitOrFail(param: Symbol): Term = Implicits.search(paramType(param)) match {
79-
case iss: ImplicitSearchSuccess => iss.tree
80-
case isf: ImplicitSearchFailure => report.throwError(s"Failed to resolve an implicit for [$param].")
81-
}
94+
def wireConstructorParams(paramLists: List[List[(Symbol, TypeRepr)]]): List[List[Term]] =
95+
paramLists.map(_.map(p => dependencyResolver.resolve(p._1, /*SI-4751*/ p._2)))
8296

83-
private def paramType(param: Symbol): TypeRepr = {
84-
// val (sym: Symbol, tpeArgs: List[Type]) = targetTypeD match {
85-
// case TypeRef(_, sym, tpeArgs) => (sym, tpeArgs)
86-
// case t => abort(s"Target type not supported for wiring: $t. Please file a bug report with your use-case.")
87-
// }
88-
// val pTpe = param.signature.substituteTypes(sym.asClass.typeParams, tpeArgs)
89-
// if (param.asTerm.isByNameParam) pTpe.typeArgs.head else pTpe
97+
def wireConstructorParamsWithImplicitLookups(paramLists: List[List[(Symbol, TypeRepr)]]): List[List[Term]] =
98+
paramLists.map {
99+
case params if params.forall(_._1.flags is Flags.Implicit) => params.map(resolveImplicitOrFail)
100+
case params => params.map(p => dependencyResolver.resolve(p._1, /*SI-4751*/ p._2))
101+
}
90102

91-
//FIXME assertion error in test inheritanceHKT.success, selfTypeHKT.success
92-
Ref(param).tpe.widen
93-
}
103+
private def resolveImplicitOrFail(param: Symbol, paramType: TypeRepr): Term =
104+
Implicits.search(paramType) match {
105+
case iss: ImplicitSearchSuccess => iss.tree
106+
case isf: ImplicitSearchFailure => report.throwError(s"Failed to resolve an implicit for [$param].")
107+
}
94108

95109
/** In some cases there is one extra (phantom) constructor. This happens when extended trait has implicit param:
96110
*
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include commonHKTClasses
2+
3+
case class LocalA[X]()
4+
case class LocalB[X](la: LocalA[X])
5+
6+
object Test {
7+
val la = wire[LocalA[Int]]
8+
val lb = wire[LocalB[Int]]
9+
val a = wire[A[IO]]
10+
val b = wire[B[IO]]
11+
}
12+
13+
require(Test.lb.la == Test.la)
14+
require(Test.b.a == Test.a)

0 commit comments

Comments
 (0)