Scalaマクロのerrorとabortの違い
Scalaのマクロで、コンパイルエラーにしてしまうときは Context.error
を使う。
def someMethod_impl(c: Context)(arg: c.Expr[String]): c.Expr[Unit] = { // ... if (cond) { c.error(c.enclosingPosition, "a message") } // ... }
でもこれが微妙に使いづらくて、なぜなら戻り値が Unit
だから。Unit
だと:
val _arg = arg.tree match { case Literal(Constant(value: String)) => value case _ => c.error(c.enclosingPosition, "a message") }
とかが出来ません。この場合変数 _arg
は String
になってほしいのですが、実際は String
と Unit
の共通の親である Any
になってしまうわけです。
で、登場するのが Context.abort
。こちらは戻り値が Nothing
になっているので、上記のようなケースで上手く動作します。
val _arg = arg.tree match { case Literal(Constant(value: String)) => value case _ => c.abort(c.enclosingPosition, "a message") } // 変数 `_arg` はちゃんと `String`
ケースに応じて使い分ければ良さそうですね。