summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-07-05 20:08:53 +0000
committerMartin Odersky <odersky@gmail.com>2009-07-05 20:08:53 +0000
commit64e41b43cc2f000ecbccb527d17425d9f0ce7f98 (patch)
treecd8e704b18cc40701f38e90d8ea7418454ec84a2
parentc93f64f7ea35b53cdec95cad4891f7bd84604888 (diff)
downloadscala-64e41b43cc2f000ecbccb527d17425d9f0ce7f98.tar.gz
scala-64e41b43cc2f000ecbccb527d17425d9f0ce7f98.tar.bz2
scala-64e41b43cc2f000ecbccb527d17425d9f0ce7f98.zip
Fixed positions
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala17
-rw-r--r--src/compiler/scala/tools/nsc/Main.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala8
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Parsers.scala10
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala118
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Global.scala7
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Positions.scala254
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/RangePositions.scala285
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala6
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala11
12 files changed, 406 insertions, 332 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 0cd9d46bd1..51a8495ece 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -134,13 +134,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
// ------------ Hooks for interactive mode-------------------------
- /** Return a position correponding to tree startaing at `start`, with tip
- * at `mid`, and ending at `end`. ^ batch mode errors point at tip.
- */
- def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
- if (settings.Yrangepos.value) new RangePosition(source, start, point, end)
- else new OffsetPosition(source, point)
-
/** Called every time an AST node is succesfully typedchecked in typerPhase.
*/
def signalDone(context: analyzer.Context, old: Tree, result: Tree) {}
@@ -149,16 +142,6 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
*/
def registerContext(c: analyzer.Context) {}
- /** Allow splits when positioning a tree */
- def withSplitAllowed(op: => Tree) = {
- splitAllowed = true
- try {
- op
- } finally {
- splitAllowed = false
- }
- }
-
// ------------------ Reporting -------------------------------------
import nsc.util.NoPosition
diff --git a/src/compiler/scala/tools/nsc/Main.scala b/src/compiler/scala/tools/nsc/Main.scala
index dbd9c496d6..799d9810f2 100644
--- a/src/compiler/scala/tools/nsc/Main.scala
+++ b/src/compiler/scala/tools/nsc/Main.scala
@@ -54,7 +54,9 @@ object Main extends AnyRef with EvalLoop {
command.settings.assemrefs.value + File.pathSeparator + libpath
}
try {
- object compiler extends Global(command.settings, reporter)
+ val compiler = if (command.settings.Yrangepos.value) new interactive.Global(command.settings, reporter)
+ else new Global(command.settings, reporter)
+
if (reporter.hasErrors) {
reporter.flush()
return
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 557b365974..5c4d7c1c37 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -243,7 +243,7 @@ abstract class TreeGen
// var m$: T = null; or, if class member: local var m$: T = _;
def mkModuleVarDef(accessor: Symbol) = {
- val mvar = accessor.owner.newVariable(accessor.pos, nme.moduleVarName(accessor.name))
+ val mvar = accessor.owner.newVariable(accessor.pos.toSynthetic, nme.moduleVarName(accessor.name))
.setInfo(accessor.tpe.finalResultType)
.setFlag(MODULEVAR);
if (mvar.owner.isClass) {
@@ -304,7 +304,7 @@ abstract class TreeGen
if (treeInfo.isPureExpr(expr)) {
within(() => expr);
} else {
- val temp = owner.newValue(expr.pos, unit.fresh.newName(expr.pos, "ev$"))
+ val temp = owner.newValue(expr.pos.toSynthetic, unit.fresh.newName(expr.pos, "ev$"))
.setFlag(SYNTHETIC).setInfo(expr.tpe);
atPos(expr.pos) {
Block(List(ValDef(temp, expr)), within(() => Ident(temp) setType expr.tpe))
@@ -318,7 +318,7 @@ abstract class TreeGen
if (treeInfo.isPureExpr(expr)) {
exprs1 += (() => expr)
} else {
- val temp = owner.newValue(expr.pos, unit.fresh.newName(expr.pos))
+ val temp = owner.newValue(expr.pos.toSynthetic, unit.fresh.newName(expr.pos))
.setFlag(SYNTHETIC).setInfo(expr.tpe)
vdefs += ValDef(temp, expr)
exprs1 += (() => Ident(temp) setType expr.tpe)
@@ -327,6 +327,6 @@ abstract class TreeGen
val prefix = vdefs.toList
val result = within(exprs1.toList)
if (prefix.isEmpty) result
- else Block(prefix, result) setPos prefix.head.pos
+ else Block(prefix, result) setPos (prefix.head.pos union result.pos)
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index e5eaf8a8e0..8378d4ba8f 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -117,7 +117,7 @@ self =>
/** the markup parser */
lazy val xmlp = new MarkupParser(this, true)
- object symbXMLBuilder extends SymbolicXMLBuilder(treeBuilder, this, true) { // DEBUG choices
+ object symbXMLBuilder extends SymbolicXMLBuilder(this, true) { // DEBUG choices
val global: self.global.type = self.global
def freshName(prefix: String): Name = UnitParser.this.freshName(prefix)
}
@@ -161,6 +161,7 @@ self =>
val global: self.global.type = self.global
def freshName(prefix: String): Name = Parser.this.freshName(prefix)
def o2p(offset: Int) = Parser.this.o2p(offset)
+ def r2p(start: Int, point: Int, end: Int) = Parser.this.r2p(start, point, end)
}
import treeBuilder.{global => _, _}
@@ -1795,7 +1796,10 @@ self =>
}
if (in.token == VIEWBOUND && (implicitViewBuf ne null))
implicitViewBuf += atPos(start, in.skipToken()) {
- makeFunctionTypeTree(List(Ident(pname)), typ())
+ val t = typ()
+ atPos(t.pos) {
+ makeFunctionTypeTree(List(Ident(pname)), t)
+ }
}
param
}
@@ -1822,7 +1826,7 @@ self =>
def bound(tok: Int, default: Name): Tree =
if (in.token == tok) { in.nextToken(); typ() }
- else rootScalaDot(default.toTypeName)
+ else atPos(o2p(in.lastOffset).toSynthetic) { rootScalaDot(default.toTypeName) }
/* -------- DEFS ------------------------------------------- */
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
index 71721389bf..6e73427a69 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
@@ -17,7 +17,7 @@ import symtab.Flags.MUTABLE
* @author Burak Emir
* @version 1.0
*/
-abstract class SymbolicXMLBuilder(make: TreeBuilder, p: Parsers#Parser, preserveWS: Boolean)
+abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean)
{
val global: Global
import global._
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 4ebacdd6bd..bef5ed0412 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -8,7 +8,7 @@ package scala.tools.nsc.ast.parser
import symtab.Flags._
import scala.collection.mutable.ListBuffer
-import scala.tools.nsc.util.Position
+import scala.tools.nsc.util.{Position, SyntheticOffsetPosition}
/** Methods for building trees, used in the parser. All the trees
* returned by this class must be untyped.
@@ -21,6 +21,7 @@ abstract class TreeBuilder {
def freshName(prefix: String): Name
def freshName(): Name = freshName("x$")
def o2p(offset: Int): Position
+ def r2p(start: Int, point: Int, end: Int): Position
def rootId(name: Name) = gen.rootId(name)
def rootScalaDot(name: Name) = gen.rootScalaDot(name)
@@ -65,12 +66,18 @@ abstract class TreeBuilder {
def init: Traverser = { buf.clear; this }
override def traverse(tree: Tree): Unit = tree match {
case Bind(name, Typed(tree1, tpt)) =>
- if ((name != nme.WILDCARD) && (buf.iterator forall (name !=)))
+ if ((name != nme.WILDCARD) && (buf.iterator forall (name !=))) {
buf += ((name, if (treeInfo.mayBeTypePat(tpt)) TypeTree() else tpt, tree.pos))
+ }
traverse(tree1)
case Bind(name, tree1) =>
- if ((name != nme.WILDCARD) && (buf.iterator forall (name !=)))
- buf += ((name, TypeTree(), tree.pos))
+ if ((name != nme.WILDCARD) && (buf.iterator forall (name !=))) {
+ // can assume only name range as position, as otherwise might overlap
+ // with binds embedded in pattern tree1
+ val start = tree.pos.start
+ val end = start + name.decode.length
+ buf += ((name, TypeTree(), r2p(start, start, end)))
+ }
traverse(tree1)
case _ =>
super.traverse(tree)
@@ -192,7 +199,7 @@ abstract class TreeBuilder {
/** Create tree representing a do-while loop */
def makeDoWhile(lname: Name, body: Tree, cond: Tree): Tree = {
val continu = Apply(Ident(lname), Nil)
- val rhs = Block(List(body), If(cond, continu, Literal(())))
+ val rhs = Block(List(body), atPos(o2p(body.pos.end)) { If(cond, continu, Literal(())) })
LabelDef(lname, Nil, rhs)
}
@@ -282,67 +289,92 @@ abstract class TreeBuilder {
* If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated
* and the variable constituting P_i is used instead of x_i
*
+ * @param mapName The name to be used for maps (either map or foreach)
+ * @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
+ * @param enums The enumerators in the for expression
+ * @param body The body of the for expression
*/
private def makeFor(mapName: Name, flatMapName: Name, enums: List[Enumerator], body: Tree): Tree = {
- def makeClosure(pat: Tree, body: Tree): Tree = {
+ /** make a closure pat => body.
+ * The closure is assigned a transparent position with the point at pos.point and
+ * the limits given by pat and body.
+ */
+ def makeClosure(pos: Position, pat: Tree, body: Tree): Tree = {
+ def splitpos = makeTransparent(wrappingPos(List(pat, body)).withPoint(pos.point))
matchVarPattern(pat) match {
case Some((name, tpt)) =>
- Function(List(ValDef(Modifiers(PARAM), name, tpt, EmptyTree)), body)
+ Function(
+ List(atPos(pat.pos) { ValDef(Modifiers(PARAM), name, tpt, EmptyTree) }),
+ body) setPos splitpos
case None =>
- makeVisitor(List(CaseDef(pat, EmptyTree, body)), false)
+ atPos(splitpos) {
+ makeVisitor(List(CaseDef(pat, EmptyTree, body)), false)
+ }
}
}
- def makeCombination(meth: Name, qual: Tree, pat: Tree, body: Tree): Tree =
- Apply(Select(qual, meth), List(makeClosure(pat, body)));
+ /** Make an application qual.meth(pat => body) positioned at `pos`.
+ */
+ def makeCombination(pos: Position, meth: Name, qual: Tree, pat: Tree, body: Tree): Tree =
+ Apply(Select(qual, meth) setPos qual.pos, List(makeClosure(pos, pat, body))) setPos pos
+ /** Optionally, if pattern is a `Bind`, the bound name, otherwise None.
+ */
def patternVar(pat: Tree): Option[Name] = pat match {
case Bind(name, _) => Some(name)
case _ => None
}
+ /** If `pat` is not yet a `Bind` wrap it in one with a fresh name
+ */
def makeBind(pat: Tree): Tree = pat match {
case Bind(_, _) => pat
- case _ => Bind(freshName(), pat)
+ case _ => Bind(freshName(), pat) setPos pat.pos
}
+ /** A reference to the name bound in Bind `pat`.
+ */
def makeValue(pat: Tree): Tree = pat match {
- case Bind(name, _) => Ident(name)
+ case Bind(name, _) => Ident(name) setPos pat.pos.toSynthetic
}
- withSplitAllowed {
- enums match {
- case ValFrom(pos, pat, rhs) :: Nil =>
- atPos(pos union body.pos) {
- makeCombination(mapName, rhs, pat, body)
- }
- case ValFrom(pos, pat, rhs) :: (rest @ (ValFrom(_, _, _) :: _)) =>
- atPos(pos union body.pos) {
- makeCombination(flatMapName, rhs, pat, makeFor(mapName, flatMapName, rest, body))
- }
- case ValFrom(pos, pat, rhs) :: Filter(_, test) :: rest =>
- makeFor(mapName, flatMapName,
- ValFrom(pos, pat, makeCombination(nme.filter, rhs, pat.syntheticDuplicate, test)) :: rest,
- body)
- case ValFrom(pos, pat, rhs) :: rest =>
- val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile(_.isInstanceOf[ValEq]);
- assert(!valeqs.isEmpty)
- val rest1 = rest.drop(valeqs.length)
- val pats = valeqs map { case ValEq(_, pat, _) => pat }
- val rhss = valeqs map { case ValEq(_, _, rhs) => rhs }
- val defpats = pats map (x => makeBind(x.syntheticDuplicate))
- val pdefs = List.flatten(List.map2(defpats, rhss)(makePatDef))
- val patX1 = makeBind(pat.syntheticDuplicate);
- val ids = (patX1 :: defpats) map makeValue
- val rhs1 = makeForYield(
- List(ValFrom(pos, patX1, rhs)),
- Block(pdefs, makeTupleTerm(ids, true)))
- makeFor(mapName, flatMapName, ValFrom(pos, makeTuple(pat :: pats, false), rhs1) :: rest1, body)
- case _ =>
- EmptyTree //may happen for erroneous input
- }
+ /** The position of the closure that starts with generator at position `genpos`.
+ */
+ def closurePos(genpos: Position) = r2p(genpos.start, genpos.point, body.pos.end)
+
+// val result =
+ enums match {
+ case ValFrom(pos, pat, rhs) :: Nil =>
+ makeCombination(closurePos(pos), mapName, rhs, pat, body)
+ case ValFrom(pos, pat, rhs) :: (rest @ (ValFrom(_, _, _) :: _)) =>
+ makeCombination(closurePos(pos), flatMapName, rhs, pat,
+ makeFor(mapName, flatMapName, rest, body))
+ case ValFrom(pos, pat, rhs) :: Filter(_, test) :: rest =>
+ makeFor(mapName, flatMapName,
+ ValFrom(pos, pat, makeCombination(closurePos(pos), nme.filter, rhs, pat.syntheticDuplicate, test)) :: rest,
+ body)
+ case ValFrom(pos, pat, rhs) :: rest =>
+ val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile(_.isInstanceOf[ValEq]);
+ assert(!valeqs.isEmpty)
+ val rest1 = rest.drop(valeqs.length)
+ val pats = valeqs map { case ValEq(_, pat, _) => pat }
+ val rhss = valeqs map { case ValEq(_, _, rhs) => rhs }
+ val defpat1 = makeBind(pat)
+ val defpats = pats map makeBind
+ val pdefs = List.flatten(List.map2(defpats, rhss)(makePatDef))
+ val ids = (defpat1 :: defpats) map makeValue
+ val rhs1 = makeForYield(
+ List(ValFrom(pos, defpat1, rhs)),
+ Block(pdefs, makeTupleTerm(ids, true) setPos wrappingPos(ids)) setPos wrappingPos(pdefs))
+ val allpats = (pat :: pats) map (_.syntheticDuplicate)
+ val vfrom1 = ValFrom(r2p(pos.start, pos.point, rhs1.pos.end), makeTuple(allpats, false), rhs1)
+ makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
+ case _ =>
+ EmptyTree //may happen for erroneous input
}
+// println("made for "+result)
+// result
}
/** Create tree for for-do comprehension &lt;for (enums) body&gt; */
diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala
index 68ae0f24a6..ee8865dec5 100755
--- a/src/compiler/scala/tools/nsc/interactive/Global.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Global.scala
@@ -15,7 +15,7 @@ import scala.tools.nsc.ast._
class Global(settings: Settings, reporter: Reporter)
extends nsc.Global(settings, reporter)
with CompilerControl
- with Positions
+ with RangePositions
with ContextTrees
with RichCompilationUnits {
self =>
@@ -52,9 +52,6 @@ self =>
// ----------- Overriding hooks in nsc.Global -----------------------
- override def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
- new RangePosition(source, start, point, end)
-
/** Called from typechecker, which signal hereby that a node has been completely typechecked.
* If the node is included in unit.targetPos, abandons run and returns newly attributed tree.
* Otherwise, if there's some higher priority work to be done, also abandons run with a FreshRunReq.
@@ -217,7 +214,7 @@ self =>
def parse(unit: RichCompilationUnit): Unit = {
currentTyperRun.compileLate(unit)
validatePositions(unit.body)
- println("parsed: [["+unit.body+"]]")
+ //println("parsed: [["+unit.body+"]]")
unit.status = JustParsed
}
diff --git a/src/compiler/scala/tools/nsc/interactive/Positions.scala b/src/compiler/scala/tools/nsc/interactive/Positions.scala
index 0f8124f630..277d35ec39 100755
--- a/src/compiler/scala/tools/nsc/interactive/Positions.scala
+++ b/src/compiler/scala/tools/nsc/interactive/Positions.scala
@@ -1,255 +1,23 @@
package scala.tools.nsc.interactive
import ast.Trees
-import scala.tools.nsc.util.{SourceFile, Position, RangePosition, OffsetPosition, NoPosition, WorkScheduler}
+import scala.tools.nsc.util.{SourceFile, Position, RangePosition, OffsetPosition, NoPosition, SyntheticOffsetPosition, WorkScheduler}
import scala.collection.mutable.ListBuffer
-/** Handling range positions
- * atPos, the main method in this trait, will add positions to a tree,
- * and will ensure the following properties:
- *
- * 1. All nodes between the root of the tree and nodes that already have positions
- * will be assigned positions.
- * 2. No node which already has a position will be assigned a different range; however
- * a RangePosition might become a TransparentPosition.
- * 3. The position of each assigned node includes the positions of each of its children.
- * 4. The positions of all solid descendants of children of an assigned node
- * are mutually non-overlapping.
- *
- * Here, the solid descendant of a node are:
- *
- * If the node has a TransparentPosition, the solid descendants of all its children
- * Otherwise, the singleton consisting of the node itself.
- */
-trait Positions extends Trees {
+trait Positions {
self: nsc.Global =>
- case class Range(pos: Position, tree: Tree) {
- def isFree = tree == EmptyTree
- }
+ def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
+ new OffsetPosition(source, point)
- class TransparentPosition(source0: SourceFile, start: Int, point: Int, end: Int) extends RangePosition(source0, start, point, end) {
- override def show = "<"+super.show+">"
- }
-
- def isTransparent(pos: Position) = pos.isInstanceOf[TransparentPosition]
-
- def isRange(pos: Position) = pos.isInstanceOf[RangePosition]
-
- protected var splitAllowed = false
-
- // -------------- ensuring no overlaps -------------------------------
-
- def solidDescendants(tree: Tree): List[Tree] =
- if (isTransparent(tree.pos)) tree.children flatMap solidDescendants
- else List(tree)
-
- /** A free range from `lo` to `hi` */
- private def free(lo: Int, hi: Int): Range =
- Range(new RangePosition(null, lo, lo, hi), EmptyTree)
-
- /** The maximal free range */
- private val maxFree: Range = free(0, Math.MAX_INT)
-
- /** A singleton list of a non-empty range from `lo` to `hi`, or else the empty List */
- private def maybeFree(lo: Int, hi: Int) =
- if (lo < hi) List(free(lo, hi))
- else List()
-
- /** Insert `pos` into ranges `rs` if possible;
- * otherwise add conflicting trees to `conflicting`.
- */
- private def insert(rs: List[Range], t: Tree, conflicting: ListBuffer[Tree]): List[Range] = rs match {
- case List() =>
- assert(conflicting.nonEmpty)
- rs
- case r :: rs1 =>
- assert(!isTransparent(t.pos))
- if (r.isFree && (r.pos includes t.pos)) {
-// println("subdividing "+r+"/"+t.pos)
- maybeFree(t.pos.end, r.pos.end) ::: List(Range(t.pos, t)) ::: maybeFree(r.pos.start, t.pos.start) ::: rs1
- } else {
- if (!r.isFree && (r.pos overlaps t.pos)) conflicting += r.tree
- r :: insert(rs1, t, conflicting)
- }
- }
-
- /** Replace elem `t` of `ts` by `replacement` list. */
- private def replace(ts: List[Tree], t: Tree, replacement: List[Tree]): List[Tree] =
- if (ts.head == t) replacement ::: ts.tail
- else ts.head :: replace(ts.tail, t, replacement)
-
- /** Ensure that given list of trees has mutually non-overlapping positions,
- * by assinging TransparentPositions to some of them, if necessary
+ /** A position that wraps the non-empty set of trees.
+ * The point of the wrapping position is the point of the first trees' position.
+ * If all some the trees are non-synthetic, returns a range position enclosing the non-synthetic trees
+ * Otherwise returns a synthetic offset position to point.
*/
- def ensureNonOverlapping(cts: List[Tree]): Unit = {
-
- def isSplittable(node: Tree) = node match {
- case Function(_, _) | CaseDef(_, _, _) | Match(_, _) => true
- case _ => false
- }
+ def wrappingPos(trees: List[Tree]): Position = trees.head.pos
- /** Do a pass over all child trees `cts`, where `ranges` reflects positions previously
- * encountered. If there are overlaps, break up one node by making its position a TransparentPosition
- * and do another pass of `ensureOverlapping`.
- * @param ranges The current list of non-overlapping ranges,
- * both occupied and free, sorted from later to earlier.
- * No TransparentPositions allowed here!
- * @param trees The list of trees to insert in ranges.
- */
- def iterate(ranges: List[Range], trees: List[Tree]): Unit = trees match {
- case List() =>
- ;
- case tree :: trees1 =>
- if (isTransparent(tree.pos))
- iterate(ranges, solidDescendants(tree) ::: trees1)
- else if (!tree.pos.isDefined || tree.pos.isSynthetic)
- iterate(ranges, trees1)
- else {
- val conflicting = new ListBuffer[Tree]
- val ranges1 = insert(ranges, tree, conflicting)
-// println("inserted "+tree+"; ranges = "+ranges1)
- if (conflicting.isEmpty) {
- iterate(ranges1, trees1)
- } else {
- val splitNode =
- if (conflicting.size == 1 && (conflicting.head.pos includes tree.pos)) {
- println("*** splitting \n"+conflicting.head+"\n--- because it conflicts with ---\n"+tree)
- println(tree.id)
- conflicting.head
- } else {
- println("*** splitting \n"+tree+"\n--- because it conflicts with trees in ---\n"+conflicting)
- println(tree.id)
- tree
- }
- //if (!splitAllowed && !isSplittable(splitNode)) throw new Error()//debug
+ def makeTransparent(pos: Position) = pos
-// println("splitting "+splitNode)
- splitNode setPos new TransparentPosition(splitNode.pos.source.get, splitNode.pos.start, splitNode.pos.point, splitNode.pos.end)
- ensureNonOverlapping(replace(cts, splitNode, solidDescendants(splitNode)))
- }
- }
- }
-// println("ensure non overlap "+cts)
- iterate(List(maxFree), cts)
- }
-
- /** Does given list of trees have mutually non-overlapping positions? */
- def findOverlapping(cts: List[Tree]): List[(Tree, Tree)] = {
- var ranges = List(maxFree)
- for (ct <- cts) {
- if (ct.pos.isDefined && !ct.pos.isSynthetic) {
- val conflicting = new ListBuffer[Tree]
- ranges = insert(ranges, ct, conflicting)
- if (conflicting.nonEmpty) return conflicting.toList map (t => (t, ct))
- }
- }
- List()
- }
-
- // -------------- setting positions -------------------------------
-
- /** Set position of all children of a node
- * @param pos A target position.
- * Uses the point of the position as the point of all positions it assigns.
- * Uses the start of this position as an Offset position for unpositioed trees
- * without children.
- * @param trees The children to position. All children must be positionable.
- */
- private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try {
- var remainingRange = pos
- for (tree <- trees) {
- if (!tree.isEmpty && tree.pos == NoPosition) {
- val children = tree.children filter (c => !c.isEmpty && !c.pos.isSynthetic)
- if (children.isEmpty) {
- tree setPos new OffsetPosition(pos.source.get, remainingRange.start)
- } else {
- setChildrenPos(remainingRange, children)
- tree setPos new RangePosition(
- pos.source.get, (children map (_.pos.start)).min, pos.point, (children map (_.pos.end)).max)
- }
- remainingRange = new RangePosition(pos.source.get, tree.pos.end, pos.point, pos.end)
- }
- }
- ensureNonOverlapping(trees)
- } catch {
- case ex: Exception =>
- println("error while set children pos "+pos+" of "+trees)
- throw ex
- }
-
- /** Position a tree.
- * This means: Set position of a node and position all its unpositioned children.
- */
- override def atPos[T <: Tree](pos: Position)(tree: T): T =
- if (isRange(pos)) {
- if (!tree.isEmpty && tree.pos == NoPosition) {
- tree.setPos(pos)
- val children = tree.children
- if (children.nonEmpty) {
- if (children.tail.isEmpty) atPos(pos)(children.head)
- else setChildrenPos(pos, children)
- }
- }
- tree
- } else {
- super.atPos(pos)(tree)
- }
-
- // ---------------- Validating positions ----------------------------------
-
- def validatePositions(tree: Tree) {
- def error(msg: String) {
- inform("**** bad positions:")
- inform(msg)
- inform("================= in =================")
- inform(tree.toString)
- throw new ValidateError
- }
- def validate(tree: Tree, encltree: Tree): Unit = try {
- if (!tree.isEmpty) {
- if (!tree.pos.isDefined)
- error("tree without position["+tree.id+"]:"+tree)
- if (!tree.pos.isSynthetic) {
- if (encltree.pos.isSynthetic)
- error("synthetic "+encltree+" contains nonsynthetic["+tree.id+"] " + tree)
- if (!(encltree.pos includes tree.pos))
- error(encltree+" does not include "+tree)
- findOverlapping(tree.children flatMap solidDescendants) match {
- case List() => ;
- case xs => error("overlapping trees: "+xs)
- }
- }
- for (ct <- tree.children flatMap solidDescendants) validate(ct, tree)
- }
- } catch {
- case ex: ValidateError =>
- println("error while validating "+tree)
- throw ex
- }
- validate(tree, tree)
- }
-
- class ValidateError extends Exception
-
- // ---------------- Locating trees ----------------------------------
-
- /** A locator for trees with given positions.
- * Given a position `pos`, locator.apply returns
- * the smallest tree that encloses `pos`.
- */
- class Locator(pos: Position) extends Traverser {
- var last: Tree = _
- def locateIn(root: Tree): Tree = {
- this.last = EmptyTree
- traverse(root)
- this.last
- }
- override def traverse(t: Tree) {
- if (!t.pos.isSynthetic && (t.pos includes pos)) {
- if (!isTransparent(t.pos)) last = t
- super.traverse(t)
- }
- }
- }
+ def validatePositions(tree: Tree) {}
}
diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
new file mode 100755
index 0000000000..727b3e8cb2
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala
@@ -0,0 +1,285 @@
+package scala.tools.nsc.interactive
+
+import ast.Trees
+import scala.tools.nsc.util.{SourceFile, Position, RangePosition, OffsetPosition, NoPosition, SyntheticOffsetPosition, WorkScheduler}
+import scala.collection.mutable.ListBuffer
+
+/** Handling range positions
+ * atPos, the main method in this trait, will add positions to a tree,
+ * and will ensure the following properties:
+ *
+ * 1. All nodes between the root of the tree and nodes that already have positions
+ * will be assigned positions.
+ * 2. No node which already has a position will be assigned a different range; however
+ * a RangePosition might become a TransparentPosition.
+ * 3. The position of each assigned node includes the positions of each of its children.
+ * 4. The positions of all solid descendants of children of an assigned node
+ * are mutually non-overlapping.
+ *
+ * Here, the solid descendant of a node are:
+ *
+ * If the node has a TransparentPosition, the solid descendants of all its children
+ * Otherwise, the singleton consisting of the node itself.
+ */
+trait RangePositions extends Trees with Positions {
+self: nsc.Global =>
+
+ case class Range(pos: Position, tree: Tree) {
+ def isFree = tree == EmptyTree
+ }
+
+ class TransparentPosition(source0: SourceFile, start: Int, point: Int, end: Int) extends RangePosition(source0, start, point, end) {
+ override def show = "<"+super.show+">"
+ }
+
+ def isTransparent(pos: Position) = pos.isInstanceOf[TransparentPosition]
+
+ def isRange(pos: Position) = pos.isInstanceOf[RangePosition] && !isTransparent(pos)
+
+ protected var splitAllowed = false
+
+ override def rangePos(source: SourceFile, start: Int, point: Int, end: Int) =
+ new RangePosition(source, start, point, end)
+
+ /** A position that wraps the non-empty set of trees.
+ * The point of the wrapping position is the point of the first trees' position.
+ * If all some the trees are non-synthetic, returns a range position enclosing the non-synthetic trees
+ * Otherwise returns a synthetic offset position to point.
+ */
+ override def wrappingPos(trees: List[Tree]): Position = {
+ val headpos = trees.head.pos
+ if (headpos.isDefined) {
+ val source = headpos.source.get
+ val point = headpos.point
+ val nonsynthetic = trees filter (t => t.pos.isDefined && !t.pos.isSynthetic)
+ if (nonsynthetic.isEmpty)
+ new SyntheticOffsetPosition(source, point)
+ else
+ new RangePosition(source, (nonsynthetic map (_.pos.start)).min, point, (nonsynthetic map (_.pos.end)).max)
+ } else {
+ headpos
+ }
+ }
+
+ override def makeTransparent(pos: Position) = pos match {
+ case rp: RangePosition if (!rp.isSynthetic) =>
+ new TransparentPosition(rp.source.get, rp.start, rp.point, rp.end)
+ case _ =>
+ pos
+ }
+
+ // -------------- ensuring no overlaps -------------------------------
+
+ def solidDescendants(tree: Tree): List[Tree] =
+ if (isTransparent(tree.pos)) tree.children flatMap solidDescendants
+ else List(tree)
+
+ /** A free range from `lo` to `hi` */
+ private def free(lo: Int, hi: Int): Range =
+ Range(new RangePosition(null, lo, lo, hi), EmptyTree)
+
+ /** The maximal free range */
+ private lazy val maxFree: Range = free(0, Math.MAX_INT)
+
+ /** A singleton list of a non-empty range from `lo` to `hi`, or else the empty List */
+ private def maybeFree(lo: Int, hi: Int) =
+ if (lo < hi) List(free(lo, hi))
+ else List()
+
+ /** Insert `pos` into ranges `rs` if possible;
+ * otherwise add conflicting trees to `conflicting`.
+ */
+ private def insert(rs: List[Range], t: Tree, conflicting: ListBuffer[Tree]): List[Range] = rs match {
+ case List() =>
+ assert(conflicting.nonEmpty)
+ rs
+ case r :: rs1 =>
+ assert(!isTransparent(t.pos))
+ if (r.isFree && (r.pos includes t.pos)) {
+// println("subdividing "+r+"/"+t.pos)
+ maybeFree(t.pos.end, r.pos.end) ::: List(Range(t.pos, t)) ::: maybeFree(r.pos.start, t.pos.start) ::: rs1
+ } else {
+ if (!r.isFree && (r.pos overlaps t.pos)) conflicting += r.tree
+ r :: insert(rs1, t, conflicting)
+ }
+ }
+
+ /** Replace elem `t` of `ts` by `replacement` list. */
+ private def replace(ts: List[Tree], t: Tree, replacement: List[Tree]): List[Tree] =
+ if (ts.head == t) replacement ::: ts.tail
+ else ts.head :: replace(ts.tail, t, replacement)
+
+ /** Ensure that given list of trees has mutually non-overlapping positions,
+ * by assinging TransparentPositions to some of them, if necessary
+ */
+ def ensureNonOverlapping(cts: List[Tree]): Unit = {
+
+ def isSplittable(node: Tree) = node match {
+ case Function(_, _) | CaseDef(_, _, _) | Match(_, _) => true
+ case _ => false
+ }
+
+ /** Do a pass over all child trees `cts`, where `ranges` reflects positions previously
+ * encountered. If there are overlaps, break up one node by making its position a TransparentPosition
+ * and do another pass of `ensureOverlapping`.
+ * @param ranges The current list of non-overlapping ranges,
+ * both occupied and free, sorted from later to earlier.
+ * No TransparentPositions allowed here!
+ * @param trees The list of trees to insert in ranges.
+ */
+ def iterate(ranges: List[Range], trees: List[Tree]): Unit = trees match {
+ case List() =>
+ ;
+ case tree :: trees1 =>
+ if (isTransparent(tree.pos))
+ iterate(ranges, solidDescendants(tree) ::: trees1)
+ else if (!tree.pos.isDefined || tree.pos.isSynthetic)
+ iterate(ranges, trees1)
+ else {
+ val conflicting = new ListBuffer[Tree]
+ val ranges1 = insert(ranges, tree, conflicting)
+// println("inserted "+tree+"; ranges = "+ranges1)
+ if (conflicting.isEmpty) {
+ iterate(ranges1, trees1)
+ } else {
+ val splitNode =
+ if (conflicting.size == 1 && (conflicting.head.pos includes tree.pos)) {
+ println("*** splitting \n"+conflicting.head+"\n--- because it conflicts with ---\n"+tree)
+ println(tree.id)
+ conflicting.head
+ } else {
+ println("*** splitting \n"+tree+"\n--- because it conflicts with trees in ---\n"+conflicting)
+ println(tree.id)
+ tree
+ }
+ throw new Error()//debug
+
+// println("splitting "+splitNode)
+ splitNode setPos new TransparentPosition(splitNode.pos.source.get, splitNode.pos.start, splitNode.pos.point, splitNode.pos.end)
+ ensureNonOverlapping(replace(cts, splitNode, solidDescendants(splitNode)))
+ }
+ }
+ }
+// println("ensure non overlap "+cts)
+ if (phase.id <= currentRun.typerPhase.id)
+ iterate(List(maxFree), cts)
+ }
+
+ /** Does given list of trees have mutually non-overlapping positions? */
+ def findOverlapping(cts: List[Tree]): List[(Tree, Tree)] = {
+ var ranges = List(maxFree)
+ for (ct <- cts) {
+ if (ct.pos.isDefined && !ct.pos.isSynthetic) {
+ val conflicting = new ListBuffer[Tree]
+ ranges = insert(ranges, ct, conflicting)
+ if (conflicting.nonEmpty) return conflicting.toList map (t => (t, ct))
+ }
+ }
+ List()
+ }
+
+ // -------------- setting positions -------------------------------
+
+ /** Set position of all children of a node
+ * @param pos A target position.
+ * Uses the point of the position as the point of all positions it assigns.
+ * Uses the start of this position as an Offset position for unpositioed trees
+ * without children.
+ * @param trees The children to position. All children must be positionable.
+ */
+ private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try {
+ var remainingRange = pos
+ for (tree <- trees) {
+ if (!tree.isEmpty && tree.pos == NoPosition) {
+ val children = tree.children filter (c => !c.isEmpty && !c.pos.isSynthetic)
+ if (children.isEmpty) {
+ tree setPos new OffsetPosition(pos.source.get, remainingRange.start)
+ } else {
+ setChildrenPos(remainingRange, children)
+ tree setPos wrappingPos(children)
+ }
+ remainingRange = new RangePosition(pos.source.get, tree.pos.end, pos.point, pos.end)
+ }
+ }
+ ensureNonOverlapping(trees)
+ } catch {
+ case ex: Exception =>
+ println("error while set children pos "+pos+" of "+trees)
+ throw ex
+ }
+
+ /** Position a tree.
+ * This means: Set position of a node and position all its unpositioned children.
+ */
+ override def atPos[T <: Tree](pos: Position)(tree: T): T =
+ if (isRange(pos)) {
+ if (!tree.isEmpty && tree.pos == NoPosition) {
+ tree.setPos(pos)
+ val children = tree.children
+ if (children.nonEmpty) {
+ if (children.tail.isEmpty) atPos(pos)(children.head)
+ else setChildrenPos(pos, children)
+ }
+ }
+ tree
+ } else {
+ super.atPos(pos)(tree)
+ }
+
+ // ---------------- Validating positions ----------------------------------
+
+ override def validatePositions(tree: Tree) {
+ def error(msg: String) {
+ inform("**** bad positions:")
+ inform(msg)
+ inform("================= in =================")
+ inform(tree.toString)
+ throw new ValidateError
+ }
+ def validate(tree: Tree, encltree: Tree): Unit = try {
+ if (!tree.isEmpty) {
+ if (!tree.pos.isDefined)
+ error("tree without position["+tree.id+"]:"+tree)
+ if (!tree.pos.isSynthetic) {
+ if (encltree.pos.isSynthetic)
+ error("synthetic "+encltree+" contains nonsynthetic["+tree.id+"] " + tree)
+ if (!(encltree.pos includes tree.pos))
+ error(encltree+" does not include "+tree)
+ findOverlapping(tree.children flatMap solidDescendants) match {
+ case List() => ;
+ case xs => error("overlapping trees: "+xs)
+ }
+ }
+ for (ct <- tree.children flatMap solidDescendants) validate(ct, tree)
+ }
+ } catch {
+ case ex: ValidateError =>
+ println("error while validating "+tree)
+ throw ex
+ }
+ validate(tree, tree)
+ }
+
+ class ValidateError extends Exception
+
+ // ---------------- Locating trees ----------------------------------
+
+ /** A locator for trees with given positions.
+ * Given a position `pos`, locator.apply returns
+ * the smallest tree that encloses `pos`.
+ */
+ class Locator(pos: Position) extends Traverser {
+ var last: Tree = _
+ def locateIn(root: Tree): Tree = {
+ this.last = EmptyTree
+ traverse(root)
+ this.last
+ }
+ override def traverse(t: Tree) {
+ if (!t.pos.isSynthetic && (t.pos includes pos)) {
+ if (!isTransparent(t.pos)) last = t
+ super.traverse(t)
+ }
+ }
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
index deae3f114f..5f74567f2b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
@@ -76,9 +76,9 @@ trait EtaExpansion { self: Analyzer =>
else {
val vname: Name = freshName(tree.pos, 0)
defs += atPos(tree.pos)(ValDef(Modifiers(SYNTHETIC), vname, TypeTree(), tree))
- Ident(vname) setPos tree.pos
+ Ident(vname) setPos tree.pos.toSynthetic
}
- tree match {
+ val tree1 = tree match {
// a partial application using named arguments has the following form:
// { val qual$1 = qual
// val x$1 = arg1
@@ -98,6 +98,8 @@ trait EtaExpansion { self: Analyzer =>
case Ident(name) =>
tree
}
+ if (tree1 ne tree) tree1 setPos makeTransparent(tree1.pos)
+ tree1
}
/** Eta-expand lifted tree.
@@ -110,15 +112,11 @@ trait EtaExpansion { self: Analyzer =>
case mt: ImplicitMethodType =>
tree
case MethodType(paramSyms, restpe) =>
- var cnt0 = 0
- def cnt = {
- cnt0 += 1
- cnt0 - 1
- }
val params = paramSyms map (sym =>
ValDef(Modifiers(SYNTHETIC | PARAM), sym.name, TypeTree(sym.tpe), EmptyTree))
- atPos(tree.pos)(Function(params, expand(Apply(tree, params map gen.paramToArg), restpe)))
- //atPos(tree.pos)(Function(params, expand(Apply(tree, args), restpe)))
+ atPos(makeTransparent(tree.pos)) {
+ Function(params, expand(Apply(tree, params map gen.paramToArg), restpe))
+ }
case _ =>
tree
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 202c9bc7ca..b48aed76ab 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -66,7 +66,7 @@ trait SyntheticMethods extends ast.TreeDSL {
newSyntheticMethod(name, flags | OVERRIDE, tpeCons)
def newSyntheticMethod(name: Name, flags: Int, tpeCons: Symbol => Type) = {
- val method = clazz.newMethod(clazz.pos, name) setFlag (flags | SYNTHETICMETH)
+ val method = clazz.newMethod(clazz.pos.toSynthetic, name) setFlag (flags | SYNTHETICMETH)
method setInfo tpeCons(method)
clazz.info.decls.enter(method).asInstanceOf[TermSymbol]
}
@@ -159,7 +159,7 @@ trait SyntheticMethods extends ast.TreeDSL {
// returns (Apply, Bind)
def makeTrees(acc: Symbol, cpt: Type): (Tree, Bind) = {
- val varName = context.unit.fresh.newName(clazz.pos, acc.name + "$")
+ val varName = context.unit.fresh.newName(clazz.pos.toSynthetic, acc.name + "$")
val (eqMethod, binding) =
if (cpt.isVarargs) (nme.sameElements, Star(WILD()))
else (nme.EQ , WILD() )
@@ -199,7 +199,7 @@ trait SyntheticMethods extends ast.TreeDSL {
def newAccessorMethod(tree: Tree): Tree = tree match {
case DefDef(_, _, _, _, _, rhs) =>
var newAcc = tree.symbol.cloneSymbol
- newAcc.name = context.unit.fresh.newName(tree.symbol.pos, tree.symbol.name + "$")
+ newAcc.name = context.unit.fresh.newName(tree.symbol.pos.toSynthetic, tree.symbol.name + "$")
newAcc setFlag SYNTHETIC resetFlag (ACCESSOR | PARAMACCESSOR | PRIVATE)
newAcc = newAcc.owner.info.decls enter newAcc
val result = typer typed { DEF(newAcc) === rhs.duplicate }
diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala
index 9225dffd72..2acf8d1f7a 100644
--- a/src/compiler/scala/tools/nsc/util/Position.scala
+++ b/src/compiler/scala/tools/nsc/util/Position.scala
@@ -195,6 +195,11 @@ class SyntheticOffsetPosition(source0: SourceFile, offset0: Int) extends OffsetP
override def toSynthetic = this
override def withPoint(off: Int) = new SyntheticOffsetPosition(source0, off)
override def show = "<["+point+"]>"
+/*
+ override def union(pos: Position) =
+ if (pos.isDefined && !pos.isSynthetic) pos
+ else this
+*/
}
/** new for position ranges */
@@ -206,15 +211,15 @@ extends OffsetPosition(source0, point) {
override def withStart(off: Int) = new RangePosition(source0, off, point, end)
override def withEnd(off: Int) = new RangePosition(source0, start, point, off)
override def withPoint(off: Int) = new RangePosition(source0, start, off, end)
- override def union(pos: Position) =
- if (pos.isDefined && !pos.isSynthetic) new RangePosition(source0, start min pos.start, point, end max pos.end)
- else this
override def endOrElse(d: Int) = end
override def focusStart = OffsetPosition(source0, start)
override def focusPoint = OffsetPosition(source0, point)
override def focusEnd = OffsetPosition(source0, end)
override def toString = "RangePosition("+source0+", "+start+", "+point+", "+end+")"
override def show = "["+start+":"+end+"]"
+ override def union(pos: Position) =
+ if (pos.isDefined && !pos.isSynthetic) new RangePosition(source0, start min pos.start, point, end max pos.end)
+ else this
}