So I've got this macro:
import language.experimental.macros
import scala.reflect.macros.Context
class Foo
class Bar extends Foo { def launchMissiles = "launching" }
object FooExample {
def foo: Foo = macro foo_impl
def foo_impl(c: Context): c.Expr[Foo] =
c.Expr[Foo](c.universe.reify(new Bar).tree)
}
I've said three times that I want foo
to return a Foo
, and yet I can do the following (in 2.10.0-RC3):
scala> FooExample.foo
res0: Bar = Bar@4118f8dd
scala> res0.launchMissiles
res1: String = launching
The same thing happens if I remove the type parameters on either c.Expr
. If I really want to make sure that whoever's calling foo
can't see that they're getting a Bar
, I have to add a type ascription in the tree itself.
This is actually pretty great—it means for example that I can point a macro at a schema of some sort and create an anonymous subclass of some Vocabulary
class with member methods representing terms in the vocabulary, and these will be available on the returned object.
I'd like to understand exactly what I'm doing, though, so I have a couple of questions. First, what is the return type on the foo
method actually for? Is it just available for (optional) documentation? It clearly constrains the return type (e.g., I can't change it to Int
in this case), and if I remove it entirely I get an error like this:
scala> FooExample.foo
<console>:8: error: type mismatch;
found : Bar
required: Nothing
FooExample.foo
^
But I can change it to Any
and still get a statically typed Bar
when I call foo
.
Second, is this behavior specified somewhere? This seems like a fairly elementary set of issues, but I haven't been able to search up a clear explanation or discussion.