From 0019bc2c4b7d89b61c71f18177823afdcd27bb78 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 7 Dec 2013 15:20:47 +0100 Subject: humane reporting of macro impl binding version errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Macro defs are linked to macro impls by the virtue of MacroImplBinding structures that are persisted between compilation runs serialized within instances of macroImpl annotations. Along with the evolution of our macro engine, we sometimes have to evolve the format of MacroImplBinding, which means that it has to be versioned. Version mismatches are checked upon every macro expansion, ensuring that macros that we expand were compiled with exactly the same version of the macro engine that we’re running. That’s all really cool apart from the fact that version mismatches result in aborting the entire compilation with an obscure message without giving a hint about the culprits. This commit improves the situation by providing pretty per-expansion compilation errors that tell the programmer what macro expansions are at fault and what macro engines were used to compile them. --- .../scala/tools/nsc/typechecker/ContextErrors.scala | 5 +++++ .../scala/tools/nsc/typechecker/Macros.scala | 21 ++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src/compiler/scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 719d04a7f9..352ae6c8b0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -730,6 +730,11 @@ trait ContextErrors { issueNormalTypeError(expandee, s"macro in $role role can only expand into $allowedExpansions") } + def MacroIncompatibleEngineError(macroEngine: String) = { + val message = s"macro cannot be expanded, because it was compiled by an incompatible macro engine $macroEngine" + issueNormalTypeError(lastTreeToTyper, message) + } + case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable protected def macroExpansionError(expandee: Tree, msg: String, pos: Position = NoPosition) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 72783a3a61..105e975c86 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -123,16 +123,15 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { * * @scala.reflect.macros.internal.macroImpl( * `macro`( + * "macroEngine" = , * "isBundle" = false, * "isBlackbox" = true, * "signature" = List(Other), * "methodName" = "impl", - * "versionFormat" = , * "className" = "Macros$")) */ + def macroEngine = "v7.0 (implemented in Scala 2.11.0-M8)" object MacroImplBinding { - val versionFormat = 6.0 - def pickleAtom(obj: Any): Tree = obj match { case list: List[_] => Apply(Ident(ListModule), list map pickleAtom) @@ -183,12 +182,12 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { } val payload = List[(String, Any)]( - "versionFormat" -> versionFormat, - "isBundle" -> isBundle, - "isBlackbox" -> isBlackbox, - "className" -> className, - "methodName" -> macroImpl.name.toString, - "signature" -> signature + "macroEngine" -> macroEngine, + "isBundle" -> isBundle, + "isBlackbox" -> isBlackbox, + "className" -> className, + "methodName" -> macroImpl.name.toString, + "signature" -> signature ) // the shape of the nucleus is chosen arbitrarily. it doesn't carry any payload. @@ -237,8 +236,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { raw.asInstanceOf[T] } - val pickleVersionFormat = unpickle("versionFormat", classOf[Double]) - if (versionFormat != pickleVersionFormat) fail(s"expected version format $versionFormat, actual $pickleVersionFormat") + val macroEngine = unpickle("macroEngine", classOf[String]) + if (self.macroEngine != macroEngine) typer.TyperErrorGen.MacroIncompatibleEngineError(macroEngine) val isBundle = unpickle("isBundle", classOf[Boolean]) val isBlackbox = unpickle("isBlackbox", classOf[Boolean]) -- cgit v1.2.3