2015-01-10 1 views
1
def control(x: String): Option[String] = macro controlImpl 
def controlImpl(c: Context)(x: c.Expr[String]): c.Expr[Option[String]] = { 
    import c.universe._ 
    val result = x.tree match { 
     case Match(expr, cases) => 
      val matchz = Match(q"""List("hello")""", cases) 
      q"Some(List(5)).map{a => $matchz}" 
     case a => a 
    } 
    c.Expr[Option[String]](result) 
} 

Этого макрос падает во время макроподстановок со следующей ошибкой:Компилятор сбой в простом макросе манипулируя матч заявление

java.lang.IllegalArgumentException: Could not find proxy for val o7: Some in List(value o7, method apply, <$anon: Function1>, value f, method apply, <$anon: Function1>, method apply, <$anon: Function0>, value <local ApplicativeTest>, object ApplicativeTest, package scalaz, package <root>) (currentOwner= value one) 

Это макро точка приложения:

val f = IdiomBracket.control { 
    a.get match { 
     case List(one) => one 
     case _ => "" 
    } 
} 

Что нечетное заключается в том, что если вы замените q"Some(List(5)).map{a => $matchz}" на q"Some($matchz)", тогда сбой компилятора исчезнет.

ответ

2

«Простой макрос» - это оксюморон.

Аварийный сигнал в лямбда-лифте, который указывает на плохого владельца символа.

Вы можете осмотреть дерево, которое вы производите, с помощью -Ybrowse:typer.

Подумайте, что вы хотели бы произвести:

class X { 
    //def g = List("hello") match { case List(x) => x case _ => "" } 
    def f = Some(List(5)).map{a => List("hello") match { case List(x) => x case _ => "" } } 
} 

Значение переменной в случае принадлежит anonfun вы хотите создать:

Symbol: [has] value x 
Symbol owner: value $anonfun 

Ваш реальный результат:

Symbol: [has] value x 
Symbol owner: value <local Controlled> 

, где Controlled - мой образец, охватывающий объект для вашего кода.

Возможно, вам придется перестроить корпуса, а не только cases map (_.untypecheck).

https://github.com/scala/scala/blob/v2.11.5/src/reflect/scala/reflect/api/Trees.scala#L1100

+0

Что вы подразумеваете под восстановлением корпусов. Это также не работает: 'cases.map {case cq" $ x1 => $ x2 "=> cq" $ x1 => $ x2 "}' – jedesah

+0

Кстати, может быть важно отметить, что причина для этого является несоответствием в совпадении шаблонов. Избавьтесь от любой неприменимости, и макрос выше работает отлично. Возможно, мне следовало бы уделять больше внимания этому вопросу. – jedesah

+1

Да, это точка комментария в связанном коде, я думаю. Вы должны деконструировать деревья с помощью SELECTOR_DUMMY. Или, может быть, существует существующий механизм в шаблоне. Я еще не пробовал. –