Skip to content

Commit 46e646f

Browse files
committed
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
1 parent 7027dc3 commit 46e646f

File tree

7 files changed

+53
-1
lines changed

7 files changed

+53
-1
lines changed

src/compiler/scala/tools/nsc/typechecker/Macros.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,22 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
761761
macroLogLite("" + expanded + "\n" + showRaw(expanded))
762762
val freeSyms = expanded.freeTerms ++ expanded.freeTypes
763763
freeSyms foreach (sym => MacroFreeSymbolError(expandee, sym))
764-
Success(atPos(enclosingMacroPosition.focus)(expanded))
764+
// Macros might have spliced arguments with range positions into non-compliant
765+
// locations, notably, under a tree without a range position. Or, they might
766+
// spice a tree that `resetAttrs` has assigned NoPosition.
767+
//
768+
// Here, we just convert all positions in the tree to offset positions, and
769+
// convert NoPositions to something sensible.
770+
//
771+
// Given that the IDE now sees the expandee (by using -Ymacro-expand:discard),
772+
// this loss of position fidelity shouldn't cause any real problems.
773+
val expandedPos = enclosingMacroPosition.focus
774+
def fixPosition(pos: Position) =
775+
if (pos == NoPosition) expandedPos else pos.focus
776+
expanded.foreach(t => t.pos = fixPosition(t.pos))
777+
778+
val result = atPos(enclosingMacroPosition.focus)(expanded)
779+
Success(result)
765780
}
766781
expanded match {
767782
case expanded: Expr[_] if expandee.symbol.isTermMacro => validateResultingTree(expanded.tree)

test/files/pos/t8064.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Yrangepos

test/files/pos/t8064/Client_2.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object Test {
2+
Macro {
3+
def s = ""
4+
Macro(s): @unchecked
5+
???
6+
}
7+
}
8+
// Was: a range position validation error (unpositioned tree)

test/files/pos/t8064/Macro_1.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import language.experimental.macros
2+
import scala.reflect.macros.Context
3+
4+
object Macro {
5+
def apply(a: Any): Any = macro impl
6+
7+
def impl(c: Context)(a: c.Tree): c.Tree = {
8+
c.resetLocalAttrs(a)
9+
}
10+
}

test/files/pos/t8064b.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Yrangepos

test/files/pos/t8064b/Client_2.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object Test {
2+
Macro {
3+
"".reverse
4+
}
5+
}
6+
// Was: a range position validation error (tree with offset position enclosing tree with range position)

test/files/pos/t8064b/Macro_1.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import language.experimental.macros
2+
import scala.reflect.macros.Context
3+
4+
object Macro {
5+
def apply(a: Any): Any = macro impl
6+
def impl(c: Context)(a: c.Tree): c.Tree = {
7+
import c.universe._
8+
9+
q"{$a; true}"
10+
}
11+
}

0 commit comments

Comments
 (0)