Skip to content

Commit b2b475d

Browse files
authored
Merge pull request #1536 from dotty-staging/fixes-for-trees
Make positions fit for meta
2 parents 28940d3 + 6181525 commit b2b475d

22 files changed

+367
-240
lines changed

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ object desugar {
505505
val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body)
506506
val cls = TypeDef(clsName, clsTmpl)
507507
.withMods(mods.toTypeFlags & RetainedModuleClassFlags | ModuleClassCreationFlags)
508-
Thicket(modul, classDef(cls))
508+
Thicket(modul, classDef(cls).withPos(mdef.pos))
509509
}
510510
}
511511

@@ -516,7 +516,7 @@ object desugar {
516516
def patDef(pdef: PatDef)(implicit ctx: Context): Tree = {
517517
val PatDef(mods, pats, tpt, rhs) = pdef
518518
val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
519-
flatTree(pats1 map (makePatDef(mods, _, rhs)))
519+
flatTree(pats1 map (makePatDef(pdef, mods, _, rhs)))
520520
}
521521

522522
/** If `pat` is a variable pattern,
@@ -534,9 +534,9 @@ object desugar {
534534
* If the original pattern variable carries a type annotation, so does the corresponding
535535
* ValDef or DefDef.
536536
*/
537-
def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match {
537+
def makePatDef(original: Tree, mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match {
538538
case VarPattern(named, tpt) =>
539-
derivedValDef(named, tpt, rhs, mods)
539+
derivedValDef(original, named, tpt, rhs, mods)
540540
case _ =>
541541
val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs)
542542
val vars = getVariables(pat)
@@ -553,7 +553,7 @@ object desugar {
553553
case Nil =>
554554
matchExpr
555555
case (named, tpt) :: Nil =>
556-
derivedValDef(named, tpt, matchExpr, mods)
556+
derivedValDef(original, named, tpt, matchExpr, mods)
557557
case _ =>
558558
val tmpName = ctx.freshName().toTermName
559559
val patMods = mods & (AccessFlags | Lazy) | Synthetic
@@ -564,8 +564,8 @@ object desugar {
564564
val restDefs =
565565
for (((named, tpt), n) <- vars.zipWithIndex)
566566
yield
567-
if (mods is Lazy) derivedDefDef(named, tpt, selector(n), mods &~ Lazy)
568-
else derivedValDef(named, tpt, selector(n), mods)
567+
if (mods is Lazy) derivedDefDef(original, named, tpt, selector(n), mods &~ Lazy)
568+
else derivedValDef(original, named, tpt, selector(n), mods)
569569
flatTree(firstDef :: restDefs)
570570
}
571571
}
@@ -632,7 +632,7 @@ object desugar {
632632
val selector = makeTuple(params.map(p => Ident(p.name)))
633633

634634
if (unchecked)
635-
Function(params, Match(Annotated(New(ref(defn.UncheckedAnnotType)), selector), cases))
635+
Function(params, Match(Annotated(selector, New(ref(defn.UncheckedAnnotType))), cases))
636636
else
637637
Function(params, Match(selector, cases))
638638
}
@@ -661,16 +661,20 @@ object desugar {
661661
* tree @cls
662662
*/
663663
def makeAnnotated(cls: Symbol, tree: Tree)(implicit ctx: Context) =
664-
Annotated(untpd.New(untpd.TypeTree(cls.typeRef), Nil), tree)
664+
Annotated(tree, untpd.New(untpd.TypeTree(cls.typeRef), Nil))
665665

666-
private def derivedValDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = {
667-
val vdef = ValDef(named.name.asTermName, tpt, rhs).withMods(mods).withPos(named.pos)
666+
private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = {
667+
val vdef = ValDef(named.name.asTermName, tpt, rhs)
668+
.withMods(mods)
669+
.withPos(original.pos.withPoint(named.pos.start))
668670
val mayNeedSetter = valDef(vdef)
669671
mayNeedSetter
670672
}
671673

672-
private def derivedDefDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) =
673-
DefDef(named.name.asTermName, Nil, Nil, tpt, rhs).withMods(mods).withPos(named.pos)
674+
private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) =
675+
DefDef(named.name.asTermName, Nil, Nil, tpt, rhs)
676+
.withMods(mods)
677+
.withPos(original.pos.withPoint(named.pos.start))
674678

675679
/** Main desugaring method */
676680
def apply(tree: Tree)(implicit ctx: Context): Tree = {
@@ -760,7 +764,7 @@ object desugar {
760764
*/
761765
def makeLambda(pat: Tree, body: Tree): Tree = pat match {
762766
case VarPattern(named, tpt) =>
763-
Function(derivedValDef(named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body)
767+
Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body)
764768
case _ =>
765769
makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false)
766770
}
@@ -863,7 +867,7 @@ object desugar {
863867
val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
864868
val (defpat0, id0) = makeIdPat(pat)
865869
val (defpats, ids) = (pats map makeIdPat).unzip
866-
val pdefs = (defpats, rhss).zipped map (makePatDef(Modifiers(), _, _))
870+
val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers(), _, _))
867871
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
868872
val allpats = pat :: pats
869873
val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1)
@@ -885,7 +889,15 @@ object desugar {
885889
Apply(
886890
ref(defn.SymbolClass.companionModule.termRef),
887891
Literal(Constant(str)) :: Nil)
888-
case InterpolatedString(id, strs, elems) =>
892+
case InterpolatedString(id, segments) =>
893+
val strs = segments map {
894+
case ts: Thicket => ts.trees.head
895+
case t => t
896+
}
897+
val elems = segments flatMap {
898+
case ts: Thicket => ts.trees.tail
899+
case t => Nil
900+
}
889901
Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
890902
case InfixOp(l, op, r) =>
891903
if (ctx.mode is Mode.Type)
@@ -900,8 +912,8 @@ object desugar {
900912
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) {
901913
val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType
902914
Annotated(
903-
New(ref(defn.RepeatedAnnotType), Nil :: Nil),
904-
AppliedTypeTree(ref(seqType), t))
915+
AppliedTypeTree(ref(seqType), t),
916+
New(ref(defn.RepeatedAnnotType), Nil :: Nil))
905917
} else {
906918
assert(ctx.mode.isExpr || ctx.reporter.hasErrors, ctx.mode)
907919
Select(t, op)
@@ -946,7 +958,7 @@ object desugar {
946958
makeFor(nme.map, nme.flatMap, enums, body) orElse tree
947959
case PatDef(mods, pats, tpt, rhs) =>
948960
val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
949-
flatTree(pats1 map (makePatDef(mods, _, rhs)))
961+
flatTree(pats1 map (makePatDef(tree, mods, _, rhs)))
950962
case ParsedTry(body, handler, finalizer) =>
951963
handler match {
952964
case Match(EmptyTree, cases) => Try(body, cases, finalizer)
@@ -1048,10 +1060,10 @@ object desugar {
10481060
case Alternative(trees) =>
10491061
for (tree <- trees; (vble, _) <- getVariables(tree))
10501062
ctx.error("illegal variable in pattern alternative", vble.pos)
1051-
case Annotated(annot, arg) =>
1063+
case Annotated(arg, _) =>
10521064
collect(arg)
1053-
case InterpolatedString(_, _, elems) =>
1054-
elems foreach collect
1065+
case InterpolatedString(_, segments) =>
1066+
segments foreach collect
10551067
case InfixOp(left, _, right) =>
10561068
collect(left)
10571069
collect(right)

src/dotty/tools/dotc/ast/NavigateAST.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@ object NavigateAST {
1919
case _ =>
2020
val loosePath = untypedPath(tree, exactMatch = false)
2121
throw new
22-
Error(i"""no untyped tree for $tree, pos = ${tree.pos}, envelope = ${tree.envelope}
22+
Error(i"""no untyped tree for $tree, pos = ${tree.pos}
2323
|best matching path =\n$loosePath%\n====\n%
24-
|path positions = ${loosePath.map(_.pos)}
25-
|path envelopes = ${loosePath.map(_.envelope)}""")
24+
|path positions = ${loosePath.map(_.pos)}""")
2625
}
2726

2827
/** The reverse path of untyped trees starting with a tree that closest matches
@@ -40,7 +39,7 @@ object NavigateAST {
4039
def untypedPath(tree: tpd.Tree, exactMatch: Boolean = false)(implicit ctx: Context): List[Positioned] =
4140
tree match {
4241
case tree: MemberDef[_] =>
43-
untypedPath(tree.envelope) match {
42+
untypedPath(tree.pos) match {
4443
case path @ (last: DefTree[_]) :: _ => path
4544
case path if !exactMatch => path
4645
case _ => Nil
@@ -76,7 +75,7 @@ object NavigateAST {
7675
path
7776
}
7877
def singlePath(p: Positioned, path: List[Positioned]): List[Positioned] =
79-
if (p.envelope contains pos) childPath(p.productIterator, p :: path)
78+
if (p.pos contains pos) childPath(p.productIterator, p :: path)
8079
else path
8180
singlePath(from, Nil)
8281
}

src/dotty/tools/dotc/ast/Positioned.scala

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ package ast
33

44
import util.Positions._
55
import util.DotClass
6+
import core.Contexts.Context
7+
import core.Decorators._
8+
import core.Flags.JavaDefined
9+
import core.StdNames.nme
610

711
/** A base class for things that have positions (currently: modifiers and trees)
812
*/
@@ -16,19 +20,14 @@ abstract class Positioned extends DotClass with Product {
1620
*/
1721
def pos: Position = curPos
1822

19-
/** Destructively update `curPos` to given position. Also, set any missing
23+
/** Destructively update `curPos` to given position. Also, set any missing
2024
* positions in children.
2125
*/
2226
protected def setPos(pos: Position): Unit = {
2327
curPos = pos
2428
if (pos.exists) setChildPositions(pos.toSynthetic)
2529
}
2630

27-
/** The envelope containing the item in its entirety. Envelope is different from
28-
* `pos` for definitions (instances of MemberDef).
29-
*/
30-
def envelope: Position = pos.toSynthetic
31-
3231
/** A positioned item like this one with the position set to `pos`.
3332
* if the positioned item is source-derived, a clone is returned.
3433
* If the positioned item is synthetic, the position is updated
@@ -106,16 +105,15 @@ abstract class Positioned extends DotClass with Product {
106105
}
107106
}
108107

109-
/** The initial, synthetic position. This is usually the union of all positioned children's
110-
* envelopes.
108+
/** The initial, synthetic position. This is usually the union of all positioned children's positions.
111109
*/
112110
protected def initialPos: Position = {
113111
var n = productArity
114112
var pos = NoPosition
115113
while (n > 0) {
116114
n -= 1
117115
productElement(n) match {
118-
case p: Positioned => pos = pos union p.envelope
116+
case p: Positioned => pos = pos union p.pos
119117
case xs: List[_] => pos = unionPos(pos, xs)
120118
case _ =>
121119
}
@@ -124,7 +122,7 @@ abstract class Positioned extends DotClass with Product {
124122
}
125123

126124
private def unionPos(pos: Position, xs: List[_]): Position = xs match {
127-
case (p: Positioned) :: xs1 => unionPos(pos union p.envelope, xs1)
125+
case (p: Positioned) :: xs1 => unionPos(pos union p.pos, xs1)
128126
case _ => pos
129127
}
130128

@@ -138,7 +136,7 @@ abstract class Positioned extends DotClass with Product {
138136
false
139137
}
140138
(this eq that) ||
141-
(this.envelope contains that.pos) && {
139+
(this.pos contains that.pos) && {
142140
var n = productArity
143141
var found = false
144142
while (n > 0 && !found) {
@@ -148,4 +146,68 @@ abstract class Positioned extends DotClass with Product {
148146
found
149147
}
150148
}
149+
150+
/** Check that all positioned items in this tree satisfy the following conditions:
151+
* - Parent positions contain child positions
152+
* - If item is a non-empty tree, it has a position
153+
*/
154+
def checkPos(nonOverlapping: Boolean)(implicit ctx: Context): Unit = try {
155+
import untpd._
156+
var lastPositioned: Positioned = null
157+
var lastPos = NoPosition
158+
def check(p: Any): Unit = p match {
159+
case p: Positioned =>
160+
assert(pos contains p.pos,
161+
s"""position error, parent position does not contain child positon
162+
|parent = $this,
163+
|parent position = $pos,
164+
|child = $p,
165+
|child position = ${p.pos}""".stripMargin)
166+
p match {
167+
case tree: Tree if !tree.isEmpty =>
168+
assert(tree.pos.exists,
169+
s"position error: position not set for $tree # ${tree.uniqueId}")
170+
case _ =>
171+
}
172+
if (nonOverlapping) {
173+
this match {
174+
case _: WildcardFunction
175+
if lastPositioned.isInstanceOf[ValDef] && !p.isInstanceOf[ValDef] =>
176+
// ignore transition from last wildcard parameter to body
177+
case _ =>
178+
assert(!lastPos.exists || !p.pos.exists || lastPos.end <= p.pos.start,
179+
s"""position error, child positions overlap or in wrong order
180+
|parent = $this
181+
|1st child = $lastPositioned
182+
|1st child position = $lastPos
183+
|2nd child = $p
184+
|2nd child position = ${p.pos}""".stripMargin)
185+
}
186+
lastPositioned = p
187+
lastPos = p.pos
188+
}
189+
p.checkPos(nonOverlapping)
190+
case xs: List[_] =>
191+
xs.foreach(check)
192+
case _ =>
193+
}
194+
this match {
195+
case tree: DefDef if tree.name == nme.CONSTRUCTOR && tree.mods.is(JavaDefined) =>
196+
// Special treatment for constructors coming from Java:
197+
// Leave out tparams, they are copied with wrong positions from parent class
198+
check(tree.mods)
199+
check(tree.vparamss)
200+
case _ =>
201+
val end = productArity
202+
var n = 0
203+
while (n < end) {
204+
check(productElement(n))
205+
n += 1
206+
}
207+
}
208+
} catch {
209+
case ex: AssertionError =>
210+
println(i"error while checking $this")
211+
throw ex
212+
}
151213
}

src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
183183
case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind])
184184
case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind])
185185
case SelectFromTypeTree(tpt, _) => mayBeTypePat(tpt)
186-
case Annotated(_, tpt) => mayBeTypePat(tpt)
186+
case Annotated(tpt, _) => mayBeTypePat(tpt)
187187
case _ => false
188188
}
189189

@@ -480,7 +480,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
480480
require(sym.pos.exists)
481481
object accum extends TreeAccumulator[List[Tree]] {
482482
def apply(x: List[Tree], tree: Tree)(implicit ctx: Context): List[Tree] = {
483-
if (tree.envelope.contains(sym.pos))
483+
if (tree.pos.contains(sym.pos))
484484
if (definedSym(tree) == sym) tree :: x
485485
else {
486486
val x1 = foldOver(x, tree)

0 commit comments

Comments
 (0)