From d744921f855a6c5d4f4df62895bc3b17b8e0e532 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 18 Dec 2013 16:55:15 +0100 Subject: SI-8064 Automatic position repair for macro expansion - Replace NoPosition with the focus of the macro application - Focus all range positions, for example, those of spliced arguments --- .../scala/tools/nsc/typechecker/Macros.scala | 26 +++++++++++++++++++++- test/files/pos/t8064.flags | 1 + test/files/pos/t8064/Client_2.scala | 8 +++++++ test/files/pos/t8064/Macro_1.scala | 10 +++++++++ test/files/pos/t8064b.flags | 1 + test/files/pos/t8064b/Client_2.scala | 6 +++++ test/files/pos/t8064b/Macro_1.scala | 11 +++++++++ 7 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/files/pos/t8064.flags create mode 100644 test/files/pos/t8064/Client_2.scala create mode 100644 test/files/pos/t8064/Macro_1.scala create mode 100644 test/files/pos/t8064b.flags create mode 100644 test/files/pos/t8064b/Client_2.scala create mode 100644 test/files/pos/t8064b/Macro_1.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 006ab792fc..c32b986d9c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -760,7 +760,31 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { macroLogLite("" + expanded + "\n" + showRaw(expanded)) val freeSyms = expanded.freeTerms ++ expanded.freeTypes freeSyms foreach (sym => MacroFreeSymbolError(expandee, sym)) - Success(atPos(enclosingMacroPosition.focus)(expanded)) + // Macros might have spliced arguments with range positions into non-compliant + // locations, notably, under a tree without a range position. Or, they might + // splice a tree that `resetAttrs` has assigned NoPosition. + // + // Here, we just convert all positions in the tree to offset positions, and + // convert NoPositions to something sensible. + // + // Given that the IDE now sees the expandee (by using -Ymacro-expand:discard), + // this loss of position fidelity shouldn't cause any real problems. + // + // Alternatively, we could pursue a way to exclude macro expansions from position + // invariant checking, or find a way not to touch expansions that happen to validate. + // + // This would be useful for cases like: + // + // macro1 { macro2 { "foo" } } + // + // to allow `macro1` to see the range position of the "foo". + val expandedPos = enclosingMacroPosition.focus + def fixPosition(pos: Position) = + if (pos == NoPosition) expandedPos else pos.focus + expanded.foreach(t => t.pos = fixPosition(t.pos)) + + val result = atPos(enclosingMacroPosition.focus)(expanded) + Success(result) } expanded match { case expanded: Expr[_] if expandee.symbol.isTermMacro => validateResultingTree(expanded.tree) diff --git a/test/files/pos/t8064.flags b/test/files/pos/t8064.flags new file mode 100644 index 0000000000..281f0a10cd --- /dev/null +++ b/test/files/pos/t8064.flags @@ -0,0 +1 @@ +-Yrangepos diff --git a/test/files/pos/t8064/Client_2.scala b/test/files/pos/t8064/Client_2.scala new file mode 100644 index 0000000000..44106782c7 --- /dev/null +++ b/test/files/pos/t8064/Client_2.scala @@ -0,0 +1,8 @@ +object Test { + Macro { + def s = "" + Macro(s): @unchecked + ??? + } +} +// Was: a range position validation error (unpositioned tree) \ No newline at end of file diff --git a/test/files/pos/t8064/Macro_1.scala b/test/files/pos/t8064/Macro_1.scala new file mode 100644 index 0000000000..4fabd54a89 --- /dev/null +++ b/test/files/pos/t8064/Macro_1.scala @@ -0,0 +1,10 @@ +import language.experimental.macros +import scala.reflect.macros.Context + +object Macro { + def apply(a: Any): Any = macro impl + + def impl(c: Context)(a: c.Tree): c.Tree = { + c.resetLocalAttrs(a) + } +} diff --git a/test/files/pos/t8064b.flags b/test/files/pos/t8064b.flags new file mode 100644 index 0000000000..281f0a10cd --- /dev/null +++ b/test/files/pos/t8064b.flags @@ -0,0 +1 @@ +-Yrangepos diff --git a/test/files/pos/t8064b/Client_2.scala b/test/files/pos/t8064b/Client_2.scala new file mode 100644 index 0000000000..a7bf2b9fb4 --- /dev/null +++ b/test/files/pos/t8064b/Client_2.scala @@ -0,0 +1,6 @@ +object Test { + Macro { + "".reverse + } +} +// Was: a range position validation error (tree with offset position enclosing tree with range position) \ No newline at end of file diff --git a/test/files/pos/t8064b/Macro_1.scala b/test/files/pos/t8064b/Macro_1.scala new file mode 100644 index 0000000000..82582356c0 --- /dev/null +++ b/test/files/pos/t8064b/Macro_1.scala @@ -0,0 +1,11 @@ +import language.experimental.macros +import scala.reflect.macros.Context + +object Macro { + def apply(a: Any): Any = macro impl + def impl(c: Context)(a: c.Tree): c.Tree = { + import c.universe._ + + q"{$a; true}" + } +} -- cgit v1.2.3