Consider the following simple macro fragment:
val lstConstructor = weakTypeTag[List[String]].tpe.typeConstructor
println(c.typecheck(tq"$lstConstructor[String]", mode = c.TYPEmode))
This seemed to be pretty straightforward piece of code fails with the following no that informative exception:
[error] scala.reflect.macros.TypecheckException: Any does not take type parameters
[error] at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$3(Typers.scala:44)
[error] at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$2(Typers.scala:38)
[error] at scala.reflect.macros.contexts.Typers.doTypecheck$1(Typers.scala:37)
[error] at scala.reflect.macros.contexts.Typers.typecheck(Typers.scala:51)
[error] at scala.reflect.macros.contexts.Typers.typecheck$(Typers.scala:32)
[error] at scala.reflect.macros.contexts.Context.typecheck(Context.scala:18)
[error] at scala.reflect.macros.contexts.Context.typecheck(Context.scala:18)
What is the right way to aoply a type argument to a type constructor?
UPD:
Manually specifying hardcoded name of the type constructor as
println(c.typecheck(tq"List[String]", mode = c.TYPEmode))
works perfectly fine
Welcome to undocumented land of untyped compiler guts.
The quasiquote
tq"List[String]"makes the following tree:Notice that the first parameter is not a
Type, it's anIdent. So your quasiquote,tq"$lstConstructor[String]", silently replaces the unappropriately typed tree with an emptyTypeTree():I'm pretty sure that is equivalent to
Any, so you get the error.Now, to get an
Identout of aType, you can use.typeSymbolmethod (though idents don't have type param info, it doesn't matter whether you did.typeConstructorbefore or not). This should work:Code on Scastie (using runtime universe) here.