I'm trying to determine the type of a parameter passed into a macro at compile time. It seems to work when I use <:<
but not when I use =:=
. I'm not sure why. Can anyone point me in the right direction? I've included example code below.
This macro:
import language.experimental.macros
import scala.reflect.macros.Context
object Macros {
def say(param: Any): Unit = macro impl
def impl(c: Context)(param: c.Expr[Any]): c.Expr[Unit] = {
if (param.actualType.<:<(c.universe.typeOf[String])) {
c.universe.reify { printf("string: %s\n", param.splice) }
} else if (param.actualType.<:<(c.universe.typeOf[Int])) {
c.universe.reify { printf("int: %d\n", param.splice) }
} else {
c.universe.reify { printf("any: %s\n", param.splice) }
}
}
}
Called by this code:
object Test extends App {
Macros.say("Hi")
Macros.say(1)
Macros.say(Blah)
}
case object Blah
Returns:
string: Hi
int: 1
any: Blah
But if I check for type equality (=:=
) instead the macro returns:
any: Hi
any: 1
any: Blah
Any help would be much appreciated.
That is because type of "Hi"
is not just String
, it's more specific type - String("Hi")
, which means this type contains information that it represents concrete string literal.
The same situation occurs with literal 1
- it's type is Int(1)
, not just Int
.
You can use widen
method on Type
to strip information about constant values:
object Macros {
def say(param: Any): Unit = macro impl
def impl(c: Context)(param: c.Expr[Any]): c.Expr[Unit] = {
if (param.actualType.widen.=:=(c.universe.typeOf[String])) {
c.universe.reify { printf("string: %s\n", param.splice) }
} else if (param.actualType.widen.=:=(c.universe.typeOf[Int])) {
c.universe.reify { printf("int: %d\n", param.splice) }
} else {
c.universe.reify { printf("any: %s\n", param.splice) }
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With