diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2014-03-07 14:52:23 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-03-07 18:56:35 +0100 |
commit | b10f45a78217b002f8ac6e2051ff932a1ac2e029 (patch) | |
tree | fe781db5f7290794ddbec794aa53f2e399f12af8 | |
parent | 2dddb03b267770afcd0249ad700e55d53019e637 (diff) | |
download | scala-b10f45a78217b002f8ac6e2051ff932a1ac2e029.tar.gz scala-b10f45a78217b002f8ac6e2051ff932a1ac2e029.tar.bz2 scala-b10f45a78217b002f8ac6e2051ff932a1ac2e029.zip |
SI-8375 saner binary incompat errors for macros
Inspired by Brian McKenna's RC1 migration experience, this commit improves
macro impl binding validation in order to provide more helpful diagnostic
for this quite frequent class of errors.
19 files changed, 79 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 2043eb5d5d..156f9d4f4a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -725,8 +725,9 @@ trait ContextErrors { NormalTypeError(expandee, "too many argument lists for " + fun) } - def MacroIncompatibleEngineError(macroEngine: String) = { - val message = s"macro cannot be expanded, because it was compiled by an incompatible macro engine $macroEngine" + def MacroIncompatibleEngineError(diagnostic: String) = { + var message = s"macro cannot be expanded, because it was compiled by an incompatible macro engine" + if (macroDebugLite || macroDebugVerbose) message += s" (internal diagnostic: $diagnostic)" issueNormalTypeError(lastTreeToTyper, message) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 677c94e063..f1dd00d4cd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -224,7 +224,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { val Apply(_, pickledPayload) = wrapped val payload = pickledPayload.map{ case Assign(k, v) => (unpickleAtom(k), unpickleAtom(v)) }.toMap - def fail(msg: String) = abort(s"bad macro impl binding: $msg") + def fail(msg: String) = typer.TyperErrorGen.MacroIncompatibleEngineError(msg) def unpickle[T](field: String, clazz: Class[T]): T = { def failField(msg: String) = fail(s"$field $msg") if (!payload.contains(field)) failField("is supposed to be there") @@ -237,7 +237,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { } val macroEngine = unpickle("macroEngine", classOf[String]) - if (self.macroEngine != macroEngine) typer.TyperErrorGen.MacroIncompatibleEngineError(macroEngine) + if (self.macroEngine != macroEngine) typer.TyperErrorGen.MacroIncompatibleEngineError(s"expected = ${self.macroEngine}, actual = $macroEngine") val isBundle = unpickle("isBundle", classOf[Boolean]) val isBlackbox = unpickle("isBlackbox", classOf[Boolean]) diff --git a/test/files/lib/macro210.jar.desired.sha1 b/test/files/lib/macro210.jar.desired.sha1 new file mode 100644 index 0000000000..ff87a55129 --- /dev/null +++ b/test/files/lib/macro210.jar.desired.sha1 @@ -0,0 +1 @@ +3794ec22d9b27f2b179bd34e9b46db771b934ec3 ?macro210.jar diff --git a/test/files/neg/macro-incompatible-macro-engine-a.check b/test/files/neg/macro-incompatible-macro-engine-a.check new file mode 100644 index 0000000000..8ae08bd164 --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-a.check @@ -0,0 +1,7 @@ +Test_3.scala:2: error: macro cannot be expanded, because it was compiled by an incompatible macro engine + Macros.foo + ^ +Test_3.scala:3: error: macro cannot be expanded, because it was compiled by an incompatible macro engine + Macros.foo + ^ +two errors found diff --git a/test/files/neg/macro-incompatible-macro-engine/Macros_2.flags b/test/files/neg/macro-incompatible-macro-engine-a/Macros_2.flags index 966df731d0..966df731d0 100644 --- a/test/files/neg/macro-incompatible-macro-engine/Macros_2.flags +++ b/test/files/neg/macro-incompatible-macro-engine-a/Macros_2.flags diff --git a/test/files/neg/macro-incompatible-macro-engine/Macros_2.scala b/test/files/neg/macro-incompatible-macro-engine-a/Macros_2.scala index 39708eee49..39708eee49 100644 --- a/test/files/neg/macro-incompatible-macro-engine/Macros_2.scala +++ b/test/files/neg/macro-incompatible-macro-engine-a/Macros_2.scala diff --git a/test/files/neg/macro-incompatible-macro-engine/Plugin_1.scala b/test/files/neg/macro-incompatible-macro-engine-a/Plugin_1.scala index 44ed91d2fb..44ed91d2fb 100644 --- a/test/files/neg/macro-incompatible-macro-engine/Plugin_1.scala +++ b/test/files/neg/macro-incompatible-macro-engine-a/Plugin_1.scala diff --git a/test/files/neg/macro-incompatible-macro-engine/Test_3.scala b/test/files/neg/macro-incompatible-macro-engine-a/Test_3.scala index 7e4fae5236..7e4fae5236 100644 --- a/test/files/neg/macro-incompatible-macro-engine/Test_3.scala +++ b/test/files/neg/macro-incompatible-macro-engine-a/Test_3.scala diff --git a/test/files/neg/macro-incompatible-macro-engine/scalac-plugin.xml b/test/files/neg/macro-incompatible-macro-engine-a/scalac-plugin.xml index 42b9cdd75d..42b9cdd75d 100644 --- a/test/files/neg/macro-incompatible-macro-engine/scalac-plugin.xml +++ b/test/files/neg/macro-incompatible-macro-engine-a/scalac-plugin.xml diff --git a/test/files/neg/macro-incompatible-macro-engine-b.check b/test/files/neg/macro-incompatible-macro-engine-b.check new file mode 100644 index 0000000000..2a7510cf86 --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-b.check @@ -0,0 +1,7 @@ +Test_3.scala:2: error: macro cannot be expanded, because it was compiled by an incompatible macro engine (internal diagnostic: expected = v7.0 (implemented in Scala 2.11.0-M8), actual = vxxx (implemented in the incompatibleMacroEngine plugin)) + Macros.foo + ^ +Test_3.scala:3: error: macro cannot be expanded, because it was compiled by an incompatible macro engine (internal diagnostic: expected = v7.0 (implemented in Scala 2.11.0-M8), actual = vxxx (implemented in the incompatibleMacroEngine plugin)) + Macros.foo + ^ +two errors found diff --git a/test/files/neg/macro-incompatible-macro-engine-b.flags b/test/files/neg/macro-incompatible-macro-engine-b.flags new file mode 100644 index 0000000000..037a693bbd --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-b.flags @@ -0,0 +1 @@ +-Ymacro-debug-lite
\ No newline at end of file diff --git a/test/files/neg/macro-incompatible-macro-engine-b/Macros_2.flags b/test/files/neg/macro-incompatible-macro-engine-b/Macros_2.flags new file mode 100644 index 0000000000..966df731d0 --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-b/Macros_2.flags @@ -0,0 +1 @@ +-Xplugin:.
\ No newline at end of file diff --git a/test/files/neg/macro-incompatible-macro-engine-b/Macros_2.scala b/test/files/neg/macro-incompatible-macro-engine-b/Macros_2.scala new file mode 100644 index 0000000000..39708eee49 --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-b/Macros_2.scala @@ -0,0 +1,7 @@ +import scala.language.experimental.macros +import scala.reflect.macros.blackbox.Context + +object Macros { + def impl(c: Context) = c.universe.Literal(c.universe.Constant(())) + def foo: Unit = macro impl +}
\ No newline at end of file diff --git a/test/files/neg/macro-incompatible-macro-engine-b/Plugin_1.scala b/test/files/neg/macro-incompatible-macro-engine-b/Plugin_1.scala new file mode 100644 index 0000000000..44ed91d2fb --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-b/Plugin_1.scala @@ -0,0 +1,35 @@ +package incompatibleMacroEngine + +import scala.tools.nsc.Global +import scala.tools.nsc.plugins.{Plugin => NscPlugin} + +class Plugin(val global: Global) extends NscPlugin { + import global._ + import analyzer._ + + val name = "incompatibleMacroEngine" + val description = "A sample analyzer plugin that crafts a macro impl binding with a non-standard macro engine." + val components = Nil + addMacroPlugin(MacroPlugin) + + object MacroPlugin extends MacroPlugin { + def fixupBinding(tree: Tree) = new Transformer { + override def transform(tree: Tree) = { + tree match { + case Literal(const @ Constant(x)) if tree.tpe == null => tree setType ConstantType(const) + case _ if tree.tpe == null => tree setType NoType + case _ => ; + } + super.transform(tree) + } + }.transform(tree) + + override def pluginsTypedMacroBody(typer: Typer, ddef: DefDef): Option[Tree] = { + val result = standardTypedMacroBody(typer, ddef) + val List(AnnotationInfo(atp, List(Apply(nucleus, _ :: others)), Nil)) = ddef.symbol.annotations + val updatedBinding = Apply(nucleus, Assign(Literal(Constant("macroEngine")), Literal(Constant("vxxx (implemented in the incompatibleMacroEngine plugin)"))) :: others) + ddef.symbol.setAnnotations(List(AnnotationInfo(atp, List(fixupBinding(updatedBinding)), Nil))) + Some(result) + } + } +}
\ No newline at end of file diff --git a/test/files/neg/macro-incompatible-macro-engine-b/Test_3.scala b/test/files/neg/macro-incompatible-macro-engine-b/Test_3.scala new file mode 100644 index 0000000000..7e4fae5236 --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-b/Test_3.scala @@ -0,0 +1,4 @@ +object Test extends App { + Macros.foo + Macros.foo +}
\ No newline at end of file diff --git a/test/files/neg/macro-incompatible-macro-engine-b/scalac-plugin.xml b/test/files/neg/macro-incompatible-macro-engine-b/scalac-plugin.xml new file mode 100644 index 0000000000..42b9cdd75d --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-b/scalac-plugin.xml @@ -0,0 +1,4 @@ +<plugin> + <name>incompatible-macro-engine</name> + <classname>incompatibleMacroEngine.Plugin</classname> +</plugin>
\ No newline at end of file diff --git a/test/files/neg/macro-incompatible-macro-engine-c.check b/test/files/neg/macro-incompatible-macro-engine-c.check new file mode 100644 index 0000000000..804669f8b5 --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-c.check @@ -0,0 +1,4 @@ +macro-incompatible-macro-engine-c.scala:2: error: macro cannot be expanded, because it was compiled by an incompatible macro engine + MacroLibCompiledByScala210x.foo + ^ +one error found diff --git a/test/files/neg/macro-incompatible-macro-engine-c.scala b/test/files/neg/macro-incompatible-macro-engine-c.scala new file mode 100644 index 0000000000..037ac5f456 --- /dev/null +++ b/test/files/neg/macro-incompatible-macro-engine-c.scala @@ -0,0 +1,3 @@ +object Test extends App { + MacroLibCompiledByScala210x.foo +}
\ No newline at end of file diff --git a/test/files/neg/macro-incompatible-macro-engine.check b/test/files/neg/macro-incompatible-macro-engine.check deleted file mode 100644 index 1d582e5ed6..0000000000 --- a/test/files/neg/macro-incompatible-macro-engine.check +++ /dev/null @@ -1,7 +0,0 @@ -Test_3.scala:2: error: macro cannot be expanded, because it was compiled by an incompatible macro engine vxxx (implemented in the incompatibleMacroEngine plugin) - Macros.foo - ^ -Test_3.scala:3: error: macro cannot be expanded, because it was compiled by an incompatible macro engine vxxx (implemented in the incompatibleMacroEngine plugin) - Macros.foo - ^ -two errors found |