I have the following macro
object Example {
def doIt(s: String): String = macro doItImpl
def doItImpl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
import c.{ universe => u }
import u._
???
}
}
Instead of the ??? I would like to inspect the line where the method doIt was called to check if the result of the method was used (in an assignment, method call or whatever). If the result is not used I respond with an error-message.
Call-example:
val s: String = doIt("Hallo") // alright
doIt("Hallo") // ERROR!
Is there a simple way to get the Tree of the whole line?
For completeness, here's a lightly adapted version of the solution I mention above:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object Example {
def doIt(s: String): String = macro doItImpl
def doItImpl(c: Context)(s: c.Expr[String]): c.Expr[String] = {
import c.universe._
c.enclosingClass.collect {
case ValDef(_, name, _, rhs) if rhs.pos == c.macroApplication.pos =>
c.literal(s"Okay, defining a variable named ${name.decoded}.")
}.headOption.getOrElse(
c.abort(c.enclosingPosition, "Not a valid application.")
)
}
}
Now in a REPL:
scala> import Example._
import Example._
scala> object Test1 { val x = doIt("foo") }
defined module Test1
scala> Test1.x
res0: String = Okay, defining a variable named x.
And in the case that we don't have an definition:
scala> object Test2 { doIt("foo") }
<console>:13: error: Not a valid application.
object Test2 { doIt("foo") }
^
As expected. See the comments on the question linked above for some caveats, but unless your real use case is much more complicated, this approach should work fine.
Related
Does Scala have any equivalent to GCC's typeofextension? (Or C++ decltype?)
I'm generating code that references some external code (which may not be available yet), and I need a way to reference the type of that code in a method definition
For singleton objects, I could use Foo.type, but if Foo is an arbitrary expression, that doesn't work.
Update:
Here is a simplified example that shows the problem:
def f(x: typeof(Foo))(implicit M: Monoid[typeof(Foo)]) =
M.append(Foo, M.append(x, Foo))
The code I am working on doesn't know anything about Foo other than that it is a string representation of a Scala expression. It is outputting the above code to a .scala file which is to be later compiled as part of a separate project.
Of course the typeof(Foo) bits don't work. Using Foo.type would work only if Foo is a singleton.
Basically, I want to know if there is something I could substitute in place of typeof(Foo) that would work for arbitrary Scala expressions.
In Scala there is no typeof of that sort.
We can try to modify the method adding type parameter
def f[F](foo: F)(x: F)(implicit M: Monoid[F]) =
M.append(foo, M.append(x, foo))
and call it like f(Foo)(...), where Foo is the expression to be substituted, then F should be inferred upon compilation.
Otherwise I can imagine the following workflow. We could generate string represenation of the type of expression Foo from string represenation of Foo itself with Scalameta's SemanticDB and then insert string representation of expression Foo and this generated string represenation of the type.
One more option is to generate tree with macro annotation
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
class generate(foo: String) extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro generateMacro.impl
}
object generateMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val str: String = c.prefix.tree match {
case q"new generate($s)" => c.eval[String](c.Expr(s))
}
val tree = c.typecheck(c.parse(str))
val tpe = tree.tpe.widen
annottees match {
case q"$mods def $name[..$_](...$_): $_ = $_" :: _ =>
q"""
$mods def $name(x: $tpe)(implicit M: Monoid[$tpe]): $tpe =
M.append($tree, M.append(x, $tree))
"""
}
}
}
#generate("1 + 1")
def f(): Unit = ()
// def f(x: Int)(implicit M: Monoid[Int]): Int = M.append(2, M.append(x, 2))
https://github.com/travisbrown/type-provider-examples/
https://docs.scala-lang.org/overviews/macros/typeproviders.html
Actually I guess this is close to what was asked
class TypeOf[A](a: A) {
type T = A
}
val tp = new TypeOf(Foo)
def f(x: tp.T)(implicit M: Monoid[tp.T]) = M.append(Foo, M.append(x, Foo))
Do you have a reference class for the type you want to use? Else define a custom class, and use:
classOf [Class_Name]
is equivalent typeOf
And if you re trying to know the class of your custom object, then use:
object_name.getClass
I have some problems with scala macros and identifying the realised type of a constructor.
Not sure if i am doing something wrong here or what the correct call would be.
From the documentation, it looks like typeSignatureIn should return the correct information, e.g. ClassTag[Int], but when I run the macro, I actually get ClassTag[U] which fails to compile as U is the type parameter, rather than the realised type.
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T]
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map {
constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock)
val constructorArguments = constructor.paramss
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext))
}
}
println(typeToMock)
println(constructorArgumentsTypes)
c.literalUnit
}
def foo[T] = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
running it:
scala> foo[Foo[Int]]
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[U]))
I need to get the ClassTag[Int] somehow to be able to generate the correct Tree later, any ideas?
Try using dealias at each place you resolve a type. Scala keeps references in place, even when it knows to what they refer. dealias gets you a copy (?) of the type that has the references replaced.
You should also choose either blackbox or whitebox macros, rather than just scala.reflect.macros.Context.
This seems to work:
import scala.language.experimental.macros
import scala.reflect.ClassTag
import scala.reflect.macros.whitebox.Context
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val typeToMock = weakTypeOf[T].dealias
val primaryConstructorOpt = typeToMock.members.collectFirst {
case method: MethodSymbolApi if method.isPrimaryConstructor => method
}
val constructorArgumentsTypes = primaryConstructorOpt.map { constructor =>
val constructorTypeContext = constructor.typeSignatureIn(typeToMock).dealias
val constructorArguments = constructorTypeContext.paramLists
constructorArguments.map { symbols =>
symbols.map(_.typeSignatureIn(constructorTypeContext).dealias)
}
}
println(typeToMock)
println(constructorArgumentsTypes)
q"()"
}
def foo[T]: Any = macro macroImpl[T]
class Foo[U: ClassTag]
foo[Foo[Int]]
Result
Foo[Int]
Some(List(List(), List(scala.reflect.ClassTag[Int])))
Let's say I define some type in a trait, that should implement some type class (like functor):
import cats.Functor
import cats.syntax.functor.toFunctorOps
trait Library {
type T[+A]
implicit val isFunctor: Functor[T]
}
Now, I want to use this library. The following works fine:
trait LibraryUser {
val l: Library
import l._
def use: T[Boolean] = {
val t: T[Int] = ???
t.map(_ => true)
}
}
But when using it in a method with a parameter instead, the import of the implicit isn't working (out commented line doesn't compile) and you have to write the implicit for yourself instead:
object LibraryUser1 {
def use(l: Library): l.T[Boolean] = {
import l._
val t: T[Int] = ???
//t.map(_ => true)
toFunctorOps(t)(isFunctor).map(_ => true)
}
}
Why is this the case / what can be done against it.
This has previously been filed as a bug, specifically SI-9625. Implicits values that are path-dependent and return higher-kinded types fail to resolve. Here is a simplified example using the standard library:
trait TC[F[_]]
trait Foo {
type T[A]
implicit val ta: TC[T]
}
object Bar {
def use(foo: Foo) = {
import foo._
implicitly[TC[T]] // fails to resolve, but `implicitly[TC[T]](ta)` is fine
}
}
Sadly, even the most obvious use of the implicit fails:
object Bar {
def use(foo: Foo) = {
implicit val ta: TC[foo.T] = null
implicitly[TC[foo.T]] // nope!
}
}
c.inferImplicitValue infers implicit values in the call site scope. Is it possible to infer implicits using the c.prefix scope?
This is not valid code, but expresses what I need:
c.prefix.inferImplicitValue
I'm currently using a naive implementation for this purpose[1], but it has some limitations like not inferring implicit values from defs and detecting duplicated/ambiguous implicit values.
[1] https://github.com/getquill/quill/blob/9a28d4e6c901d3fa07e7d5838e2f4c1f3c16732b/quill-core/src/main/scala/io/getquill/util/InferImplicitValueWithFallback.scala#L12
Simply generating a block with an appropriate (local) import followed by a call to implicitly does the trick:
q"""{import ${c.prefix}._; _root_.scala.Predef.implicitly[$T] }
Where T is an instance of Type representing the type of the implicit value to lookup.
To check if the implicit lookup actually succeeded, you can call Context.typeCheck with silent=true and check if the resulting tree is empty or not.
As an illustration, here is an example that implements an infer method returning None if the implicit was not found in the members of the target object, and otherwise wraps the result in a Some.
import scala.reflect.macros.Context
import scala.language.experimental.macros
def inferImplicitInPrefixContext[T:c.WeakTypeTag](c: Context): c.Tree = {
import c.universe._
val T = weakTypeOf[T]
c.typeCheck(
q"""{
import ${c.prefix}._
_root_.scala.Predef.implicitly[$T]
}""",
silent = true
)
}
def infer_impl[T:c.WeakTypeTag](c: Context): c.Expr[Option[T]] = {
import c.universe._
c.Expr[Option[T]](
inferImplicitInPrefixContext[T](c) match {
case EmptyTree => q"_root_.scala.None"
case tree => q"_root_.scala.Some($tree)"
}
)
}
trait InferOp {
def infer[T]: Option[T] = macro infer_impl[T]
}
Let's test it:
object Foo extends InferOp {
implicit val s = "hello"
}
Foo.infer[String] // res0: Some[String] = Some(hello)
Foo.infer[Int] // res1: None.type = None
implicit val lng: Long = 123L
Foo.infer[Long] // res2: Some[Long] = Some(123)
I'm attempting to write a macro that would wrap a function and deducting a parameter from the value its invocation will be assigned to.
object TestMacros {
def foo(name: String): String = name.toUpper
def bar = macro barImpl
def barImpl(c: Context): c.Expr[String] = {
import c.universe._
//TODO extract value name (should be baz)
c.Expr[String](Apply(
Select(newTermName("TestMacros"), newTermName("foo")), // Probably wrong, just typed it quickly for demonstration purposes
List(Literal(Constant("test"))))) // Should replace test by value name
}
}
object TestUsage {
val baz = bar // should be BAZ
}
I don't know if this is clear enough. I've investigated both c.prefix and c.macroApplication without success. I'm using Scala 2.10.2 without the macro-paradise compiler plugin.
This is very possible. I know, because I've done something like it before. The trick is to search the enclosing tree for a value whose right-hand side has the same position as the macro application:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object TestMacros {
def foo(name: String): String = name.toUpperCase
def bar = macro barImpl
def barImpl(c: Context): c.Expr[String] = {
import c.universe._
c.enclosingClass.collect {
case ValDef(_, name, _, rhs)
if rhs.pos == c.macroApplication.pos => c.literal(foo(name.decoded))
}.headOption.getOrElse(
c.abort(c.enclosingPosition, "Not a valid application.")
)
}
}
And then:
scala> object TestUsage { val baz = TestMacros.bar }
defined module TestUsage
scala> TestUsage.baz
res0: String = BAZ
scala> class TestClassUsage { val zab = TestMacros.bar }
defined class TestClassUsage
scala> (new TestClassUsage).zab
res1: String = ZAB
Note that you can apply foo at compile-time, since you know the name of the val at compile-time. If you wanted it to be applied at runtime that would also be possible, of course.
I had a similar problem when I wanted to simplify some property initializations. So your code helped me to find out how that is possible, but I got deprecation warnings. As scala macros evolve the enclosingClass got deprecated in Scala 2.11. The documentation states to use c.internal.enclosingOwner instead. The quasiquotes feature makes things easier now - my sample to retrieve just the name as in val baz = TestMacros.getName looks like this:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
object TestMacros {
def getName(): String = macro getNameImpl
def getNameImpl(c: Context)() = {
import c.universe._
val term = c.internal.enclosingOwner.asTerm
val name = term.name.decodedName.toString
// alternatively use term.fullName to get package+class+value
c.Expr(q"${name}")
}
}