From e2e1e8a43123de3c5594bad24af486b730e0b3c7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 24 Sep 2016 18:34:13 +0200 Subject: Check that (most) positions are non-overlapping. Check that children of a node have non-overlapping positions and that positions of successive children are monotonically increasing. This holds currently except for 3 exceptions: - Trees coming from Java as the Java parser also does desugarings which copy trees. - Functions coming from wildcard expressions - Interpolated strings We'll see whether we can do something about the latter two. --- src/dotty/tools/dotc/ast/Positioned.scala | 37 +++++++++++++++++++++++-------- src/dotty/tools/dotc/typer/FrontEnd.scala | 3 ++- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/dotty/tools/dotc/ast/Positioned.scala b/src/dotty/tools/dotc/ast/Positioned.scala index ab9c06ca1..1e992bd01 100644 --- a/src/dotty/tools/dotc/ast/Positioned.scala +++ b/src/dotty/tools/dotc/ast/Positioned.scala @@ -151,23 +151,41 @@ abstract class Positioned extends DotClass with Product { * - Parent positions contain child positions * - If item is a non-empty tree, it has a position */ - def checkPos(complete: Boolean)(implicit ctx: Context): Unit = try { + def checkPos(nonOverlapping: Boolean)(implicit ctx: Context): Unit = try { import untpd._ + var lastPositioned: Positioned = null + var lastPos = NoPosition def check(p: Any): Unit = p match { case p: Positioned => assert(pos contains p.pos, s"""position error, parent position does not contain child positon - |parent = $this, - |parent position = $pos, - |child = $p, - |child position = ${p.pos}""".stripMargin) + |parent = $this, + |parent position = $pos, + |child = $p, + |child position = ${p.pos}""".stripMargin) p match { case tree: Tree if !tree.isEmpty => assert(tree.pos.exists, s"position error: position not set for $tree # ${tree.uniqueId}") case _ => } - p.checkPos(complete) + if (nonOverlapping) { + this match { + case _: InterpolatedString => // ignore, strings and elements are interleaved in source, separated in tree + case _: Function => // ignore, functions produced from wildcards (e.g. (_ op _) mix parameters and body + case _ => + assert(!lastPos.exists || !p.pos.exists || lastPos.end <= p.pos.start, + s"""position error, child positions overlap or in wrong order + |parent = $this + |1st child = $lastPositioned + |1st child position = $lastPos + |2nd child = $p + |2nd child position = ${p.pos}""".stripMargin) + lastPositioned = p + lastPos = p.pos + } + } + p.checkPos(nonOverlapping) case xs: List[_] => xs.foreach(check) case _ => @@ -179,10 +197,11 @@ abstract class Positioned extends DotClass with Product { check(tree.mods) check(tree.vparamss) case _ => - var n = productArity - while (n > 0) { - n -= 1 + val end = productArity + var n = 0 + while (n < end) { check(productElement(n)) + n += 1 } } } catch { diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala index e008430a7..4ce24b633 100644 --- a/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -35,7 +35,8 @@ class FrontEnd extends Phase { else new Parser(unit.source).parse() val printer = if (ctx.settings.Xprint.value.contains("parser")) default else typr printer.println("parsed:\n" + unit.untpdTree.show) - if (Config.checkPositions) unit.untpdTree.checkPos(complete = true) + if (Config.checkPositions) + unit.untpdTree.checkPos(nonOverlapping = !unit.isJava && !ctx.reporter.hasErrors) } def enterSyms(implicit ctx: Context) = monitor("indexing") { -- cgit v1.2.3