2013-10-15 2 views
3

Я пытаюсь создать макрос, который позволит мне захватить текст выражения, передаваемого конструктору. Я хочу текст выражения для целей отладки. Макрос реализация выглядит следующим образом:Ошибка типа при использовании параметра типа в качестве аргумента типа для другого типа, передаваемого в реализацию макроса

package nimrandsLibrary.react.macroImpl 

object Macros { 
    def applyImpl[T : context.WeakTypeTag, U : context.WeakTypeTag](context : scala.reflect.macros.Context) (expression : context.Expr[T]) : context.Expr[U] = { 
     import context.universe._ 
     context.Expr[U](context.universe.New(context.universe.weakTypeOf[U], expression.tree, context.universe.Literal(context.universe.Constant(expression.tree.toString())))) 
    } 
} 

definiation выглядит следующим образом:

class Signal(expression : => T, expressionText : String) { 
    ... 
} 

object Signal { 
    def apply[T](expression : T) = macro nimrandsLibrary.react.macroImpl.Macros.applyImpl[T, Signal[T]] 
} 

Однако, где бы я это называю, как показано ниже, я получаю сообщение об ошибке.

val mySignal = Signal{ 2 } //type mismatch; found : Int required : T 

Но, конечно, тип для T является Int, поэтому ошибка не имеет смысла.

Кажется, что каким-то образом в расширении макроса компилятор забывает заменить Signal [T] сигналом [Int]. В качестве эксперимента, я попытался изменить место определения так, что оба типа должны быть предусмотрены, например, так:

def apply[T, U](expression : T) = macro nimrandsLibrary.react.macroImpl.Macros.applyImpl[T, U] 

Тогда, я называю это так:

Signal[Int, Signal[Int]]{ 2 } 

И это работает. Но, конечно, это вовсе не синтаксис, к которому я стремлюсь. Является ли это ошибкой, или я делаю это неправильно? Есть ли обходной путь?

ответ

4

Проблема заключается в том, что тег слабого типа для U в реализации макроса имеет в качестве аргумента то, что по существу является символом T, а не Int.

Далее будет работать (обратите внимание, что я укоротить некоторые имена для ясности и заменить устаревшие методы):

import scala.language.experimental.macros 
import scala.reflect.macros.Context 

object Macros { 
    def applyImpl[ 
    T: c.WeakTypeTag, 
    U: c.WeakTypeTag 
    ](c: Context)(e: c.Expr[T]): c.Expr[U] = { 
    import c.universe._ 

    c.Expr[U](
     Apply(
     Select(
      New(
      TypeTree(
       appliedType(weakTypeOf[U].typeConstructor, weakTypeOf[T] :: Nil) 
      ) 
     ), 
      nme.CONSTRUCTOR 
     ), 
     List(e.tree, Literal(Constant(e.tree.toString))) 
    ) 
    ) 
    } 
} 

class Signal[T](val expression: T, val expressionText: String) 

object Signal { 
    def apply[T](e: T) = macro Macros.applyImpl[T, Signal[T]] 
} 

И потом:

scala> Signal(1).expressionText 
res0: String = 1 

Как и следовало ожидать.


Как Майлз Сабин points out on Twitter, было бы лучше, чтобы иметь U быть конструктором типа, так как в версии выше макро реализации делает некоторые предположения о U, которые не учитываются в типах. Ниже более безопасный подход в этом отношении:

import scala.language.experimental.macros 
import scala.language.higherKinds 
import scala.reflect.macros.Context 

object Macros { 
    def applyImpl[ 
    T: c.WeakTypeTag, 
    U[_] 
    ](c: Context)(e: c.Expr[T])(implicit u: c.WeakTypeTag[U[_]]): c.Expr[U[T]] = { 
    import c.universe._ 

    c.Expr[U[T]](
     Apply(
     Select(
      New(
      TypeTree(
       appliedType(u.tpe.typeConstructor, weakTypeOf[T] :: Nil) 
      ) 
     ), 
      nme.CONSTRUCTOR 
     ), 
     List(e.tree, Literal(Constant(e.tree.toString))) 
    ) 
    ) 
    } 
} 

class Signal[T](val expression: T, val expressionText: String) 

object Signal { 
    def apply[T](e: T) = macro Macros.applyImpl[T, Signal] 
} 

Примечание особенно изменение второго аргумента applyImpl в Signal.

+0

Я не уверен, почему у тега Weak Type есть T вместо Int, но это исправлено. – Nimrand

+0

Интересное редактирование. Я попытался это сделать, но ему не понравился синтаксис U [_]: WeakTypeTag, поэтому я предположил, что у вас не может быть WeakTypeTag более высокого типа. Наверное, я ошибся. Я не думал однозначно определять неявный параметр (я не могу поверить, что просто сказал это). – Nimrand

Смежные вопросы