Неработающий пример макроса квазицитаты Scala
Я взял этот пример квазицитаты Scala из книги "Программирование Scala" (2-е издание)
Я получаю эту ошибку: https://issues.scala-lang.org/browse/SI-9711
Вывод типа говорит "Trees#Tree", но вывод типа выключен.
import scala.reflect.api.Trees // For Trees#Tree (TreeNode)
import scala.reflect.macros.blackbox._
import scala.reflect.runtime.universe._ // To use Scala runtime reflection
/**
* Represents a macro invariant which is checked over the corresponding statements.
* Example:
* '''
* var mustBeHello = "Hello"
* invariant.execute(mustBeHello.equals("Hello")) {
* mustBeHello = "Goodbye"
* }
* // Throws invariant.InvariantFailure
* '''
*/
object invariant {
case class InvariantFailure(message: String) extends RuntimeException(message)
type SyntaxTree = scala.reflect.runtime.universe.Tree
type TreeNode = Trees#Tree // a syntax tree node that is in and of itself a tree
// These two methods are the same, but one is a function call and the other is a macro function call
def execute[RetType] (myPredicate: => Boolean)(block: => RetType): RetType = macro executeMacro
def executeMacro(context: Context)(myPredicate: SyntaxTree)(block: SyntaxTree) = {
val predicateString: String = showCode(myPredicate) // turn this predicate into a String
val q"..$statements" = block // make the block into a sequence of statements
val myStatements: Seq[TreeNode] = statements // the statements are a sequence of SyntaxTreeNodes, each node a little Tree
val invariantStatements = statements.flatMap { statement =>
// Error here:
val statementString: String = showCode(statement) /* Type mismatch, expected Tree, actual Trees#Tree */
val message: String =
s"FAILURE! $predicateString == false, for statement: " + statementString
val tif: SyntaxTree =
q"throw new metaprogramming.invariant.InvariantFailure($message)"
val predicate2: SyntaxTree =
q"if (false == $myPredicate) $tif"
val toReturn: List[SyntaxTree] =
List(q"{ val temp = $myStatements; $predicate2; temp };")
toReturn
}
val tif: SyntaxTree =
q"throw new metaprogramming.invariant.InvariantFailure($predicateString)"
val predicate: SyntaxTree =
q"if (false == $predicate) $tif"
val toReturn: SyntaxTree =
q"$predicate; ..$invariantStatements"
toReturn
}
}
^ Документация должна быть самоочевидной. Вывод типа говорит Tree#Tree, но добавление ":Tree#Tree" в пример кода убивает компиляцию с ошибкой:
[info] Compiling 2 Scala sources to /home/johnreed/sbtProjects/scala-trace-debug/target/scala-2.11/test-classes...
[error] /home/johnreed/sbtProjects/scala-trace-debug/src/test/scala/mataprogramming/invariant2.scala:30: type mismatch;
[error] found : TreeNode
error scala.reflect.api.Trees#Tree
[error] required: context.universe.Tree
[error] val exceptionMessage = s"FAILURE! $predicateAsString == false, for statement: " + showCode(statement)
Я получаю "Несоответствие типов, ожидаемое дерево, фактические деревья # дерево" в IntelliJ
2 ответа
[info] Compiling 2 Scala sources to /home/johnreed/sbtProjects/scala-trace-debug/target/scala-2.11/test-classes...
[error] /home/johnreed/sbtProjects/scala-trace-debug/src/test/scala/mataprogramming/invariant2.scala:30: type mismatch;
[error] found : TreeNode
error scala.reflect.api.Trees#Tree
[error] required: context.universe.Tree
[error] val exceptionMessage = s"FAILURE! $predicateAsString == false, for statement: " + showCode(statement)
Есть что-то действительно классное с типами. Либо IntelliJ испортит типы, либо идея ускользает от меня.
"Нормальный" способ обнаружить предполагаемый тип - это один из следующих способов:
спросите REPL используя
:type
присвоить неверный тип и наблюдать сообщение об ошибке
вызвать функцию, которая отображает
TypeTag
вещи
Например,
[error] /home/apm/clones/prog-scala-2nd-ed-code-examples/src/main/scala/progscala2/metaprogramming/invariant2.scala:25: type mismatch;
[error] found : List[context.universe.Tree]
[error] required: Int
[error] val foo: Int = statements
[error] ^
Это показывает, что Tree
зависит от пути в контекстной вселенной.
Вы не можете накормить его только старым деревом.
Похожая проблема в этом вопросе.