Skip to content

Make positions fit for meta #1536

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 34 additions & 22 deletions src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ object desugar {
val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body)
val cls = TypeDef(clsName, clsTmpl)
.withMods(mods.toTypeFlags & RetainedModuleClassFlags | ModuleClassCreationFlags)
Thicket(modul, classDef(cls))
Thicket(modul, classDef(cls).withPos(mdef.pos))
Copy link
Contributor

@liufengyun liufengyun Sep 24, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pos for Thicket is synthesised via the overloaded def pos, this setting will be overridden.

What about providing a withDerivedPos method for Thicket, instead of overriding def pos?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the withPos applies to the classDef here, not the thicket.

}
}

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

/** If `pat` is a variable pattern,
Expand All @@ -534,9 +534,9 @@ object desugar {
* If the original pattern variable carries a type annotation, so does the corresponding
* ValDef or DefDef.
*/
def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match {
def makePatDef(original: Tree, mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match {
case VarPattern(named, tpt) =>
derivedValDef(named, tpt, rhs, mods)
derivedValDef(original, named, tpt, rhs, mods)
case _ =>
val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs)
val vars = getVariables(pat)
Expand All @@ -553,7 +553,7 @@ object desugar {
case Nil =>
matchExpr
case (named, tpt) :: Nil =>
derivedValDef(named, tpt, matchExpr, mods)
derivedValDef(original, named, tpt, matchExpr, mods)
case _ =>
val tmpName = ctx.freshName().toTermName
val patMods = mods & (AccessFlags | Lazy) | Synthetic
Expand All @@ -564,8 +564,8 @@ object desugar {
val restDefs =
for (((named, tpt), n) <- vars.zipWithIndex)
yield
if (mods is Lazy) derivedDefDef(named, tpt, selector(n), mods &~ Lazy)
else derivedValDef(named, tpt, selector(n), mods)
if (mods is Lazy) derivedDefDef(original, named, tpt, selector(n), mods &~ Lazy)
else derivedValDef(original, named, tpt, selector(n), mods)
flatTree(firstDef :: restDefs)
}
}
Expand Down Expand Up @@ -632,7 +632,7 @@ object desugar {
val selector = makeTuple(params.map(p => Ident(p.name)))

if (unchecked)
Function(params, Match(Annotated(New(ref(defn.UncheckedAnnotType)), selector), cases))
Function(params, Match(Annotated(selector, New(ref(defn.UncheckedAnnotType))), cases))
else
Function(params, Match(selector, cases))
}
Expand Down Expand Up @@ -661,16 +661,20 @@ object desugar {
* tree @cls
*/
def makeAnnotated(cls: Symbol, tree: Tree)(implicit ctx: Context) =
Annotated(untpd.New(untpd.TypeTree(cls.typeRef), Nil), tree)
Annotated(tree, untpd.New(untpd.TypeTree(cls.typeRef), Nil))

private def derivedValDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = {
val vdef = ValDef(named.name.asTermName, tpt, rhs).withMods(mods).withPos(named.pos)
private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = {
val vdef = ValDef(named.name.asTermName, tpt, rhs)
.withMods(mods)
.withPos(original.pos.withPoint(named.pos.start))
val mayNeedSetter = valDef(vdef)
mayNeedSetter
}

private def derivedDefDef(named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) =
DefDef(named.name.asTermName, Nil, Nil, tpt, rhs).withMods(mods).withPos(named.pos)
private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) =
DefDef(named.name.asTermName, Nil, Nil, tpt, rhs)
.withMods(mods)
.withPos(original.pos.withPoint(named.pos.start))

/** Main desugaring method */
def apply(tree: Tree)(implicit ctx: Context): Tree = {
Expand Down Expand Up @@ -760,7 +764,7 @@ object desugar {
*/
def makeLambda(pat: Tree, body: Tree): Tree = pat match {
case VarPattern(named, tpt) =>
Function(derivedValDef(named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body)
Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body)
case _ =>
makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false)
}
Expand Down Expand Up @@ -863,7 +867,7 @@ object desugar {
val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
val (defpat0, id0) = makeIdPat(pat)
val (defpats, ids) = (pats map makeIdPat).unzip
val pdefs = (defpats, rhss).zipped map (makePatDef(Modifiers(), _, _))
val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers(), _, _))
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
val allpats = pat :: pats
val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1)
Expand All @@ -885,7 +889,15 @@ object desugar {
Apply(
ref(defn.SymbolClass.companionModule.termRef),
Literal(Constant(str)) :: Nil)
case InterpolatedString(id, strs, elems) =>
case InterpolatedString(id, segments) =>
val strs = segments map {
case ts: Thicket => ts.trees.head
case t => t
}
val elems = segments flatMap {
case ts: Thicket => ts.trees.tail
case t => Nil
}
Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
case InfixOp(l, op, r) =>
if (ctx.mode is Mode.Type)
Expand All @@ -900,8 +912,8 @@ object desugar {
if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) {
val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType
Annotated(
New(ref(defn.RepeatedAnnotType), Nil :: Nil),
AppliedTypeTree(ref(seqType), t))
AppliedTypeTree(ref(seqType), t),
New(ref(defn.RepeatedAnnotType), Nil :: Nil))
} else {
assert(ctx.mode.isExpr || ctx.reporter.hasErrors, ctx.mode)
Select(t, op)
Expand Down Expand Up @@ -946,7 +958,7 @@ object desugar {
makeFor(nme.map, nme.flatMap, enums, body) orElse tree
case PatDef(mods, pats, tpt, rhs) =>
val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
flatTree(pats1 map (makePatDef(mods, _, rhs)))
flatTree(pats1 map (makePatDef(tree, mods, _, rhs)))
case ParsedTry(body, handler, finalizer) =>
handler match {
case Match(EmptyTree, cases) => Try(body, cases, finalizer)
Expand Down Expand Up @@ -1048,10 +1060,10 @@ object desugar {
case Alternative(trees) =>
for (tree <- trees; (vble, _) <- getVariables(tree))
ctx.error("illegal variable in pattern alternative", vble.pos)
case Annotated(annot, arg) =>
case Annotated(arg, _) =>
collect(arg)
case InterpolatedString(_, _, elems) =>
elems foreach collect
case InterpolatedString(_, segments) =>
segments foreach collect
case InfixOp(left, _, right) =>
collect(left)
collect(right)
Expand Down
9 changes: 4 additions & 5 deletions src/dotty/tools/dotc/ast/NavigateAST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ object NavigateAST {
case _ =>
val loosePath = untypedPath(tree, exactMatch = false)
throw new
Error(i"""no untyped tree for $tree, pos = ${tree.pos}, envelope = ${tree.envelope}
Error(i"""no untyped tree for $tree, pos = ${tree.pos}
|best matching path =\n$loosePath%\n====\n%
|path positions = ${loosePath.map(_.pos)}
|path envelopes = ${loosePath.map(_.envelope)}""")
|path positions = ${loosePath.map(_.pos)}""")
}

/** The reverse path of untyped trees starting with a tree that closest matches
Expand All @@ -40,7 +39,7 @@ object NavigateAST {
def untypedPath(tree: tpd.Tree, exactMatch: Boolean = false)(implicit ctx: Context): List[Positioned] =
tree match {
case tree: MemberDef[_] =>
untypedPath(tree.envelope) match {
untypedPath(tree.pos) match {
case path @ (last: DefTree[_]) :: _ => path
case path if !exactMatch => path
case _ => Nil
Expand Down Expand Up @@ -76,7 +75,7 @@ object NavigateAST {
path
}
def singlePath(p: Positioned, path: List[Positioned]): List[Positioned] =
if (p.envelope contains pos) childPath(p.productIterator, p :: path)
if (p.pos contains pos) childPath(p.productIterator, p :: path)
else path
singlePath(from, Nil)
}
Expand Down
84 changes: 73 additions & 11 deletions src/dotty/tools/dotc/ast/Positioned.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package ast

import util.Positions._
import util.DotClass
import core.Contexts.Context
import core.Decorators._
import core.Flags.JavaDefined
import core.StdNames.nme

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

/** Destructively update `curPos` to given position. Also, set any missing
/** Destructively update `curPos` to given position. Also, set any missing
* positions in children.
*/
protected def setPos(pos: Position): Unit = {
curPos = pos
if (pos.exists) setChildPositions(pos.toSynthetic)
}

/** The envelope containing the item in its entirety. Envelope is different from
* `pos` for definitions (instances of MemberDef).
*/
def envelope: Position = pos.toSynthetic

/** A positioned item like this one with the position set to `pos`.
* if the positioned item is source-derived, a clone is returned.
* If the positioned item is synthetic, the position is updated
Expand Down Expand Up @@ -106,16 +105,15 @@ abstract class Positioned extends DotClass with Product {
}
}

/** The initial, synthetic position. This is usually the union of all positioned children's
* envelopes.
/** The initial, synthetic position. This is usually the union of all positioned children's positions.
*/
protected def initialPos: Position = {
var n = productArity
var pos = NoPosition
while (n > 0) {
n -= 1
productElement(n) match {
case p: Positioned => pos = pos union p.envelope
case p: Positioned => pos = pos union p.pos
case xs: List[_] => pos = unionPos(pos, xs)
case _ =>
}
Expand All @@ -124,7 +122,7 @@ abstract class Positioned extends DotClass with Product {
}

private def unionPos(pos: Position, xs: List[_]): Position = xs match {
case (p: Positioned) :: xs1 => unionPos(pos union p.envelope, xs1)
case (p: Positioned) :: xs1 => unionPos(pos union p.pos, xs1)
case _ => pos
}

Expand All @@ -138,7 +136,7 @@ abstract class Positioned extends DotClass with Product {
false
}
(this eq that) ||
(this.envelope contains that.pos) && {
(this.pos contains that.pos) && {
var n = productArity
var found = false
while (n > 0 && !found) {
Expand All @@ -148,4 +146,68 @@ abstract class Positioned extends DotClass with Product {
found
}
}

/** Check that all positioned items in this tree satisfy the following conditions:
* - Parent positions contain child positions
* - If item is a non-empty tree, it has a position
*/
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)
p match {
case tree: Tree if !tree.isEmpty =>
assert(tree.pos.exists,
s"position error: position not set for $tree # ${tree.uniqueId}")
case _ =>
}
if (nonOverlapping) {
this match {
case _: WildcardFunction
if lastPositioned.isInstanceOf[ValDef] && !p.isInstanceOf[ValDef] =>
// ignore transition from last wildcard parameter to 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 _ =>
}
this match {
case tree: DefDef if tree.name == nme.CONSTRUCTOR && tree.mods.is(JavaDefined) =>
// Special treatment for constructors coming from Java:
// Leave out tparams, they are copied with wrong positions from parent class
check(tree.mods)
check(tree.vparamss)
case _ =>
val end = productArity
var n = 0
while (n < end) {
check(productElement(n))
n += 1
}
}
} catch {
case ex: AssertionError =>
println(i"error while checking $this")
throw ex
}
}
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
case RefinedTypeTree(tpt, refinements) => mayBeTypePat(tpt) || refinements.exists(_.isInstanceOf[Bind])
case AppliedTypeTree(tpt, args) => mayBeTypePat(tpt) || args.exists(_.isInstanceOf[Bind])
case SelectFromTypeTree(tpt, _) => mayBeTypePat(tpt)
case Annotated(_, tpt) => mayBeTypePat(tpt)
case Annotated(tpt, _) => mayBeTypePat(tpt)
case _ => false
}

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