2014-01-21 2 views
3

Quasiquotes упрощают многие вещи при написании макросов в Scala. Однако я заметил, что макросы, содержащие квазикокты, могут быть перекомпилированы каждый раз, когда запускается компиляция в SBT, хотя ни реализация макроса, ни какие-либо из его сайтов вызовов не были изменены и нуждаются в перекомпиляции.Избегание перекомпиляции с квазикварталами

Это, похоже, не происходит, если код в квазикварталах довольно прост, это происходит, только если есть зависимость от другого класса. Я заметил, что переписывание всего с помощью «reify», похоже, решает проблему перекомпиляции, но мне не удается переписать последнюю часть без квазикварталов ...

У меня есть следующие классы:

object ExportedFunction { 
    def apply[R: Manifest](f: Function0[R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction0[R] { 
    def apply: R = f() 
    val functionDescription = fd 
    } 

    def apply[T1: Manifest, R: Manifest](f: Function1[T1, R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction1[T1, R] { 
    def apply(t1: T1): R = f(t1) 
    val functionDescription = fd 
    } 

    ... and so on... until Function17... 
} 

я тогда анализировать object и экспортировать любую функцию члена с помощью описанного интерфейса следующим образом:

def export(registrar: FunctionRegistrar, 
      root: Object, 
      <...more args...>) = macro exportImpl 

def exportImpl(c: Context)(registrar: c.Expr[FunctionRegistrar], 
          root: c.Expr[Object], 
          <...>): c.Expr[Any] = {    

    import c.universe._ 

    <... the following is simplified ...> 
    root.typeSignature.members.flatMap { 
    case x if x.isMethod => 
     val method = x.asMethod  

     val callee = c.Expr(method)) 

     val desc = q"""FunctionDescription(<...result from reflective lookup...>)""" 
     val export = q"ExportedFunction($callee _, $desc)" 
     q"$registrar.+=({$export})" 

я могу переписать первую и последнюю строку с но мне не удается переписать вторую строчку, мой лучший снимок с квазикварталами:

val export = reify { 
    ... 
    ExportedFunction(c.Expr(q"""$callee _"""), desc) 
    ... 
}.tree 

Но это приводит:

overloaded method value apply with alternatives... cannot be applied to (c.Expr[Nothing], c.universe.Expr[FunctionDescription]) 

Я думаю, что компилятор пропускает implicits, или, возможно, этот код будет работать только для функции с фиксированным числом аргументов, так как он должен знать, на макроуровне время компиляции хау много аргументов метод имеет? Однако он работает, если все написано с использованием квазикварталов ...

ответ

6

Из описания проблемы SBT я могу предположить, что вы используете макрос рай для 2.10.x и сталкиваетесь с https://github.com/scalamacros/paradise/issues/11. На этой неделе я планировал решить эту проблему, поэтому исправление должно начаться очень скоро. В то же время вы можете использовать обходной путь, описанный на странице проблемы.

Что касается проблемы reify, не все квазивоты могут быть переписаны с использованием reify. Ограничения, такие как тот, с которым вы столкнулись здесь, были очень сильным стимулом для смещения нашего внимания к квазикварталам в Scala 2.11.

+0

Спасибо большое за последний релиз! Он исправляет проблему ;-) – gbasler

+0

Однако, имея макросы в проекте, увеличилось время компиляции (даже если файлы не будут перекомпилированы) от 37s до 82s в нашем проекте ... – gbasler

+0

Не могли бы вы предоставить более подробную информацию? Было бы очень полезно увидеть проект sbt, который заработал 37 секунд, и другой проект, который теперь составляет 82s для компиляции. –

0

Для записи, эти параметры SBT (обновление до более новой версии) установил его:

... 
settings = Seq(
    libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, 
    libraryDependencies += "org.scalamacros" % "quasiquotes" % "2.0.0-M3" cross CrossVersion.full, 
    autoCompilerPlugins := true, 
    addCompilerPlugin("org.scalamacros" % "paradise" % "2.0.0-M3" cross CrossVersion.full) 
) 
Смежные вопросы