summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala26
-rw-r--r--test/files/pos/t8064.flags1
-rw-r--r--test/files/pos/t8064/Client_2.scala8
-rw-r--r--test/files/pos/t8064/Macro_1.scala10
-rw-r--r--test/files/pos/t8064b.flags1
-rw-r--r--test/files/pos/t8064b/Client_2.scala6
-rw-r--r--test/files/pos/t8064b/Macro_1.scala11
7 files changed, 62 insertions, 1 deletions
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}"
+ }
+}