42

所以我有这个宏:

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)
}

我已经说过三遍我想foo返回 a Foo,但我可以执行以下操作(在 2.10.0-RC3 中):

scala> FooExample.foo
res0: Bar = Bar@4118f8dd

scala> res0.launchMissiles
res1: String = launching

如果我删除任何一个上的类型参数,也会发生同样的事情c.Expr。如果我真的想确保打电话的人foo看不到他们得到了 a Bar,我必须在树本身中添加一个类型归属。

这实际上非常棒——例如,这意味着我可以将宏指向某种模式,并Vocabulary使用表示词汇表中术语的成员方法创建某个类的匿名子类,这些将在返回的对象上可用。

不过,我想确切地了解我在做什么,所以我有几个问题。首先,该foo方法的返回类型实际上是什么?它仅可用于(可选)文档吗?它清楚地限制了返回类型(例如,在这种情况下我无法将其更改为Int),如果我完全删除它,我会收到如下错误:

scala> FooExample.foo
<console>:8: error: type mismatch;
 found   : Bar
 required: Nothing
              FooExample.foo
                         ^

但是我可以将其更改为AnyBar在调用foo.

其次,这种行为是否在某处指定?这似乎是一组相当基本的问题,但我无法找到明确的解释或讨论。

4

1 回答 1

22

This behavior is underspecified but intended, though it might appear confusing. We plan to elaborate on the role of return type in macro signatures, but at the moment I feel like the flexibility is a good thing to have.

Also at times the behavior is inconsistent, e.g. when the macro is caught in the middle of type inference, its static signature will be used (i.e. Foo in your example), not the type of the actual expansion. That's because macro expansion is intentionally delayed until type inference is done (so that macro implementations get to see inferred types, not type vars). This is a trade-off and not necessarily the best one, so we're planning to revisit it soon: https://issues.scala-lang.org/browse/SI-6755.

Another problem in this department is with implicit macros. When the return type of an implicit macro is generic and needs to be inferred from the requested type of an implicit value, bad things happen. This makes it currently impossible to use macros to generate type tags: https://issues.scala-lang.org/browse/SI-5923.

于 2012-12-02T21:18:44.277 回答