diff options
author | Martin Odersky <odersky@gmail.com> | 2009-06-18 15:22:12 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-06-18 15:22:12 +0000 |
commit | e6c140fecd361fdec9ad1d3c1579b8bbd3e9f007 (patch) | |
tree | 4ce37c932a6e5dff0237f4d2cbc1b2b0258bb41e | |
parent | 5d11bc473378d30483488889de7b8c381c1d66c7 (diff) | |
download | scala-e6c140fecd361fdec9ad1d3c1579b8bbd3e9f007.tar.gz scala-e6c140fecd361fdec9ad1d3c1579b8bbd3e9f007.tar.bz2 scala-e6c140fecd361fdec9ad1d3c1579b8bbd3e9f007.zip |
(1) some changes to interactive compiler interf...
(1) some changes to interactive compiler interface. 2) added
(symbol.hasTypeAt 3) Added flatten/transpose/unzip to TraversableClass
15 files changed, 334 insertions, 143 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index 14573b39d7..dec92d7832 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -115,12 +115,13 @@ abstract class TreePrinters { } def printAnnotations(tree: Tree) { - val annots = tree.symbol.annotations - if (!annots.isEmpty) { - annots foreach { annot => print("@"+annot+" ") } - println - } - else { + if (tree.symbol.rawInfo.isComplete) { + val annots = tree.symbol.annotations + if (!annots.isEmpty) { + annots foreach { annot => print("@"+annot+" ") } + println + } + } else { val annots = tree.asInstanceOf[MemberDef].mods.annotations if (!annots.isEmpty) { annots foreach { annot => print("@"+annot+" ") } diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 3c3e29de32..d175bfa398 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -103,6 +103,10 @@ trait Trees { if (Statistics.enabled) nodeCount += 1 } + val id = nodeCount +// assert(id != 151) + nodeCount += 1 + private var rawpos: Position = NoPosition def pos = rawpos @@ -121,8 +125,9 @@ trait Trees { this } - def setOriginal(tree: Tree): this.type = { - setPos(SyntheticAliasPosition(tree)) + def setOriginal(tree: Tree): this.type = tree.pos match { + case SyntheticAliasPosition(orig) => setOriginal(orig) + case _ => setPos(if (tree.pos.isDefined) SyntheticAliasPosition(tree) else tree.pos) } def setType(tp: Type): this.type = { @@ -252,6 +257,9 @@ trait Trees { def shallowDuplicate: this.type = ((new ShallowDuplicator(this)) transform this).asInstanceOf[this.type] + def syntheticDuplicate: this.type = + (syntheticDuplicator transform this).asInstanceOf[this.type] + def copyAttrs(tree: Tree): this.type = { rawpos = tree.rawpos tpe = tree.tpe @@ -286,6 +294,15 @@ trait Trees { override val treeCopy = new StrictTreeCopier } + private lazy val syntheticDuplicator = new Transformer { + override val treeCopy = new StrictTreeCopier + override def transform(t: Tree) = { + val t1 = super.transform(t) + if (t1 ne t) t1.setOriginal(t) + t1 + } + } + private class ShallowDuplicator(orig: Tree) extends Transformer { override val treeCopy = new StrictTreeCopier override def transform(tree: Tree) = @@ -576,15 +593,15 @@ trait Trees { atPos(vd) { ValDef( Modifiers(vd.mods.flags & (IMPLICIT | DEFAULTPARAM) | PARAM) withAnnotations vd.mods.annotations, - vd.name, atPos(vd.tpt) { vd.tpt.duplicate }, vd.rhs.duplicate) + vd.name, atPos(vd.tpt) { vd.tpt.syntheticDuplicate }, vd.rhs.syntheticDuplicate) }}) val (edefs, rest) = body span treeInfo.isEarlyDef val (evdefs, etdefs) = edefs partition treeInfo.isEarlyValDef val (lvdefs, gvdefs) = List.unzip { evdefs map { case vdef @ ValDef(mods, name, tpt, rhs) => - val fld = atPos(vdef.pos) { treeCopy.ValDef(vdef, mods, name, TypeTree(), EmptyTree) } - val local = atPos(fld) { treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) } + val fld = treeCopy.ValDef(vdef.syntheticDuplicate, mods, name, TypeTree() setOriginal tpt, EmptyTree) + val local = treeCopy.ValDef(vdef, Modifiers(PRESUPER), name, tpt, rhs) (local, fld) } } @@ -1645,7 +1662,7 @@ trait Trees { if (tree.tpe ne null) tree.tpe = typeSubst(tree.tpe) super.traverse(tree) } - override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate) + override def apply[T <: Tree](tree: T): T = super.apply(tree.syntheticDuplicate) override def toString() = "TreeTypeSubstituter("+from+","+to+")" } @@ -1663,7 +1680,7 @@ trait Trees { if (tree.hasSymbol) subst(from, to) super.traverse(tree) } - override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate) + override def apply[T <: Tree](tree: T): T = super.apply(tree.syntheticDuplicate) override def toString() = "TreeSymSubstituter("+from+","+to+")" } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 229c7aeb5a..c78886b823 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1029,7 +1029,7 @@ self => if (isWildcard(t)) (placeholderParams: @unchecked) match { case (vd @ ValDef(mods, name, _, _)) :: rest => - placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest + placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.syntheticDuplicate, EmptyTree) :: rest } // this does not correspond to syntax, but is necessary to // accept closures. We might restrict closures to be between {...} only. @@ -1949,7 +1949,7 @@ self => val trees = makePatDef(newmods, if (tp.isEmpty) p else Typed(p, tp), rhs) map atPos(p.pos.start, p.pos.point) - rhs = rhs.duplicate + rhs = rhs.syntheticDuplicate if (newmods hasFlag Flags.DEFERRED) { trees match { case List(ValDef(_, _, _, EmptyTree)) => @@ -1998,7 +1998,7 @@ self => val start = in.skipToken() if (in.token == THIS) { atPos(start, in.skipToken()) { - val vparamss = paramClauses(nme.CONSTRUCTOR, implicitClassViews map (_.duplicate), false) + val vparamss = paramClauses(nme.CONSTRUCTOR, implicitClassViews map (_.syntheticDuplicate), false) newLineOptWhenFollowedBy(LBRACE) val rhs = if (in.token == LBRACE) constrBlock(vparamss) else { accept(EQUALS); constrExpr(vparamss) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 687e5f8e21..96b052013a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -208,7 +208,7 @@ abstract class TreeBuilder { List( makeVisitor( List( - CaseDef(pat1.duplicate, EmptyTree, Literal(true)), + CaseDef(pat1.syntheticDuplicate, EmptyTree, Literal(true)), CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false))), false, nme.CHECK_IF_REFUTABLE_STRING @@ -301,16 +301,16 @@ abstract class TreeBuilder { enums match { case ValFrom(pos, pat, rhs) :: Nil => - atPos(pos) { + atPos(pos union body.pos) { makeCombination(mapName, rhs, pat, body) } case ValFrom(pos, pat, rhs) :: (rest @ (ValFrom(_, _, _) :: _)) => - atPos(pos) { + 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.duplicate, test)) :: rest, + 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]); @@ -318,9 +318,9 @@ abstract class TreeBuilder { 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.duplicate)) + val defpats = pats map (x => makeBind(x.syntheticDuplicate)) val pdefs = List.flatten(List.map2(defpats, rhss)(makePatDef)) - val patX1 = makeBind(pat.duplicate); + val patX1 = makeBind(pat.syntheticDuplicate); val ids = (patX1 :: defpats) map makeValue val rhs1 = makeForYield( List(ValFrom(pos, patX1, rhs)), @@ -373,8 +373,9 @@ abstract class TreeBuilder { def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean): Tree = makeVisitor(cases, checkExhaustive, "x$") - private def makeUnchecked(expr: Tree): Tree = + private def makeUnchecked(expr: Tree): Tree = atPos(expr.pos) { Annotated(New(scalaDot(definitions.UncheckedClass.name), List(List())), expr) + } /** Create visitor <x => x match cases> */ def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean, prefix: String): Tree = { @@ -410,7 +411,12 @@ abstract class TreeBuilder { val matchExpr = atPos(rhs.pos){ Match( makeUnchecked(rhs), - List(makeSynthetic(CaseDef(pat1, EmptyTree, makeTupleTerm(vars map (_._1) map Ident, true))))) + List( + makeSynthetic( + atPos(rhs.pos) { + CaseDef(pat1, EmptyTree, makeTupleTerm(vars map (_._1) map Ident, true)) + }))) + } vars match { case List((vname, tpt, pos)) => diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index 9db09c7f88..d7b5c3eedb 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -10,18 +10,29 @@ import scala.tools.nsc.ast._ */ trait CompilerControl { self: Global => + /** Response wrapper to client + */ + type Response[T] = SyncVar[Either[T, Throwable]] + + abstract class WorkItem extends (() => Unit) + + /** The status of a member that's returned by completion. + */ object MemberStatus extends Enumeration { val Accessible, Inherited, Implicit = Value } - type Response[T] = SyncVar[Either[T, Throwable]] - + /** Info given for every member found by completion + */ type Member = (Symbol, Type, MemberStatus.ValueSet) - /* Must be initialized before starting compilerRunner */ + /** The scheduler by which client and compiler communicate + * Must be initialized before starting compilerRunner + */ protected val scheduler = new WorkScheduler - /** The compilation unit corresponding to a source file */ + /** The compilation unit corresponding to a source file + */ def unitOf(s: SourceFile): RichCompilationUnit = unitOfFile get s.file match { case Some(unit) => unit @@ -31,34 +42,53 @@ trait CompilerControl { self: Global => unit } - /** Remove the corresponding CompilationUnit from consideration for recompilation */ - def removeUnitOf(s: SourceFile) = unitOfFile remove s.file - /** The compilation unit corresponding to a position */ def unitOf(pos: Position): RichCompilationUnit = unitOf(pos.source.get) - /** Locate smallest tree that encloses position */ + /** Remove the CompilationUnit corresponding to the given SourceFile + * from consideration for recompilation. + */ + def removeUnitOf(s: SourceFile) = unitOfFile remove s.file + + /** Locate smallest tree that encloses position + */ def locateTree(pos: Position): Tree = new Locator(pos) locateIn unitOf(pos).body - /** Locate smallest context that encloses position */ + /** Locate smallest context that encloses position + */ def locateContext(pos: Position): Option[Context] = locateContext(unitOf(pos).contexts, pos) - /** Make sure a set of compilation units is loaded and parsed */ + /** Make sure a set of compilation units is loaded and parsed. + * Return () to syncvar `result` on completion. + */ def askReload(sources: List[SourceFile], result: Response[Unit]) = - scheduler.postWorkItem(() => reload(sources, result)) + scheduler postWorkItem new WorkItem { + def apply() = reload(sources, result) + override def toString = "reload "+sources + } - /** Set sync var `result` to a fully attributed tree located at position `pos` */ + /** Set sync var `result` to a fully attributed tree located at position `pos` + */ def askTypeAt(pos: Position, result: Response[Tree]) = - scheduler.postWorkItem(() => self.getTypedTreeAt(pos, result)) + scheduler postWorkItem new WorkItem { + def apply() = self.getTypedTreeAt(pos, result) + override def toString = "typeat "+pos.source+" "+pos.show + } def askCompletion(pos: Position, result: Response[List[Member]]) = - scheduler.postWorkItem(() => self.completion(pos, result)) + scheduler postWorkItem new WorkItem { + def apply() = self.completion(pos, result) + override def toString = "completion "+pos.source+" "+pos.show + } /** Ask to do unit first on present and subsequent type checking passes */ def askToDoFirst(f: SourceFile) = { - scheduler.postWorkItem { () => moveToFront(List(f)) } + scheduler postWorkItem new WorkItem { + def apply() = moveToFront(List(f)) + override def toString = "dofirst "+f + } } /** Cancel currently pending high-priority jobs */ diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 325718f865..43c5fecaf6 100755 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -17,13 +17,15 @@ class Global(settings: Settings, reporter: Reporter) with RichCompilationUnits { self => + override def onlyPresentation = true + /** A list indicating in which order some units should be typechecked. * All units in firsts are typechecked before any unit not in this list * Modified by askToDoFirst, reload, typeAtTree. */ var firsts: List[SourceFile] = List() - /** A map of all loaded files units to the rich compilation units that corresponds to them. + /** A map of all loaded files to the rich compilation units that correspond to them. */ val unitOfFile = new LinkedHashMap[AbstractFile, RichCompilationUnit] with SynchronizedMap[AbstractFile, RichCompilationUnit] @@ -34,7 +36,7 @@ self => /** Is a background compiler run needed? */ private var outOfDate = false - /** Is a reload/ background compiler currently running? */ + /** Is a reload/background compiler currently running? */ private var acting = false /** The status value of a unit that has not yet been loaded */ @@ -43,13 +45,19 @@ self => /** The status value of a unit that has not yet been typechecked */ final val JustParsed = 0 + private var resultTree = EmptyTree + // ----------- Overriding hooks in nsc.Global ----------------------- /** Create a RangePosition */ override def rangePos(source: SourceFile, start: Int, point: Int, end: Int) = new RangePosition(source, start, point, end) - /** Called from typechecker: signal that a node has been completely typechecked + + + /** 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. * @param context The context that typechecked the node * @param old The original node * @param result The transformed node @@ -58,7 +66,7 @@ self => def integrateNew() { context.unit.body = new TreeReplacer(old, result) transform context.unit.body } - if ((context.unit != null) && (context.unit.targetPos includes result.pos)) { + if ((context.unit != null) && !result.pos.isSynthetic && (result.pos includes context.unit.targetPos)) { integrateNew() throw new TyperResult(result) } @@ -70,8 +78,8 @@ self => } } - /** Called every time a context is created - * Register the context in a context tree + /** Called from typechecker every time a context is created. + * Registers the context in a context tree */ override def registerContext(c: Context) = c.unit match { case u: RichCompilationUnit => addContext(u.contexts, c) @@ -95,10 +103,14 @@ self => case Some(action) => try { acting = true + println("picked up work item: "+action) action() + println("done with work item: "+action) } catch { case ex: CancelActionReq => + println("cancelled work item: "+action) } finally { + println("quitting work item: "+action) acting = false } case None => @@ -121,10 +133,9 @@ self => while (outOfDate) { try { backgroundCompile() + outOfDate = false } catch { case ex: FreshRunReq => - } finally { - outOfDate = false } } } @@ -148,7 +159,7 @@ self => firsts = firsts filter (s => unitOfFile contains (s.file)) val prefix = firsts map unitOf val units = prefix ::: (unitOfFile.values.toList diff prefix) - units foreach recompile + recompile(units) inform("Everything is now up to date") } @@ -172,15 +183,19 @@ self => unit.status = JustParsed } - /** Make sure symbol and type attributes are reset and recompile unit. + /** Make sure symbol and type attributes are reset and recompile units. */ - def recompile(unit: RichCompilationUnit) { - reset(unit) - inform("parsing: "+unit) - parse(unit) - inform("type checking: "+unit) - currentTyperRun.typeCheck(unit) - unit.status = currentRunId + def recompile(units: List[RichCompilationUnit]) { + for (unit <- units) { + reset(unit) + inform("parsing: "+unit) + parse(unit) + } + for (unit <- units) { + inform("type checking: "+unit) + currentTyperRun.typeCheck(unit) + unit.status = currentRunId + } } /** Move list of files to front of firsts */ @@ -209,7 +224,6 @@ self => if (settings.Xprintpos.value) treePrinter.print(unit) } moveToFront(sources) - () } if (outOfDate) throw new FreshRunReq else outOfDate = true @@ -248,8 +262,8 @@ self => pre.memberType(sym), if (context.isAccessible(sym, pre, superAccess)) vs + Accessible else vs ) - val decls = tree.tpe.decls.toList map (sym => withStatus(sym, ValueSet())) - val inherited = tree.tpe.members.toList diff decls map (sym => withStatus(sym, ValueSet(Inherited))) + val decls = tree.tpe.decls.toList map (withStatus(_, ValueSet())) + val inherited = tree.tpe.members.toList diff decls map (withStatus(_, ValueSet(Inherited))) val implicits = List() // not yet done decls ::: inherited ::: implicits case None => @@ -263,15 +277,13 @@ self => /** A transformer that replaces tree `from` with tree `to` in a given tree */ class TreeReplacer(from: Tree, to: Tree) extends Transformer { override def transform(t: Tree): Tree = { - if (t.pos includes from.pos) - if (t == from) to - else super.transform(t) - else - t + if (t == from) to + else if ((t.pos includes from.pos) || isTransparent(t.pos)) super.transform(t) + else t } } - /** A traverser that resets all type and symbol attributes in a tree */ + /** A traverser that resets all type and symbol attributes in a tree object ResetAttrs extends Transformer { override def transform(t: Tree): Tree = { if (t.hasSymbol) t.symbol = NoSymbol @@ -287,6 +299,7 @@ self => } } } + */ /** The typer run */ class TyperRun extends Run { @@ -302,18 +315,24 @@ self => * (i.e. largest tree that's contained by position) */ def typedTreeAt(pos: Position): Tree = { + println("starting typedTreeAt") val tree = locateTree(pos) -// println("at pos "+pos+" was found: "+tree) - if (tree.tpe ne null) tree - else { + println("at pos "+pos+" was found: "+tree) + if (tree.tpe ne null) { + println("already attributed") + tree + } else { val unit = unitOf(pos) assert(unit.status >= JustParsed) unit.targetPos = pos try { + println("starting type targetted check") typeCheck(unit) throw new FatalError("tree not found") } catch { - case ex: TyperResult => ex.tree + case ex: TyperResult => + println("result found") + ex.tree } } } diff --git a/src/compiler/scala/tools/nsc/interactive/Positions.scala b/src/compiler/scala/tools/nsc/interactive/Positions.scala index e253f2f3d8..213ea44d42 100755 --- a/src/compiler/scala/tools/nsc/interactive/Positions.scala +++ b/src/compiler/scala/tools/nsc/interactive/Positions.scala @@ -19,7 +19,7 @@ import scala.collection.mutable.ListBuffer * Here, the solid descendant of a node are: * * If the node has a TransparentPosition, the solid descendants of all its children - * Otherwise, then singleton consisting of the node itself. + * Otherwise, the singleton consisting of the node itself. */ trait Positions extends Trees { self: Global => @@ -33,7 +33,9 @@ self: Global => } def isTransparent(pos: Position) = pos.isInstanceOf[TransparentPosition] + def isRange(pos: Position) = pos.isInstanceOf[RangePosition] + def isPositionable(tree: Tree) = tree match { case EmptyTree => false case `emptyValDef` => false @@ -44,7 +46,8 @@ self: Global => // -------------- ensuring no overlaps ------------------------------- def solidDescendants(tree: Tree): List[Tree] = - if (isTransparent(tree.pos)) tree.children flatMap solidDescendants else 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 = @@ -54,7 +57,9 @@ self: Global => 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() + 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`. @@ -95,22 +100,22 @@ self: Global => def iterate(ranges: List[Range], trees: List[Tree]): Unit = trees match { case List() => ; - case ct :: trees1 => - if (isTransparent(ct.pos)) - iterate(ranges, solidDescendants(ct) ::: trees1) - else if (!ct.pos.isDefined || ct.pos.isSynthetic) + 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, ct, conflicting) -// println("inserted "+ct+"; ranges = "+ranges1) + 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 ct.pos)) conflicting.head - else ct - println("splitting "+splitNode) + if (conflicting.size == 1 && (conflicting.head.pos includes tree.pos)) conflicting.head + else tree +// 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))) } @@ -135,8 +140,6 @@ self: Global => // -------------- setting positions ------------------------------- - /** The sorted list of descendant nodes, a long 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. @@ -145,18 +148,18 @@ self: Global => * @param trees The children to position. All children must be positionable. */ private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try { - var currentPos = pos + var remainingRange = pos for (tree <- trees) { if (tree.pos == NoPosition) { val children = tree.children filter isPositionable - if (children.isEmpty) - tree setPos OffsetPosition(pos.source.get, currentPos.start) - else { - setChildrenPos(currentPos, children) + if (children.isEmpty) { + tree setPos 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) } - currentPos = new RangePosition(pos.source.get, tree.pos.end, pos.point, pos.end) + remainingRange = new RangePosition(pos.source.get, tree.pos.end, pos.point, pos.end) } } ensureNonOverlapping(trees) @@ -176,13 +179,7 @@ self: Global => val children = tree.children if (children.nonEmpty) { if (children.tail.isEmpty) atPos(pos)(children.head) - else if (tree.isInstanceOf[Template]) { - println("setting children "+children) - setChildrenPos(pos, children filter isPositionable) - println("set children "+children) - } else { - setChildrenPos(pos, children filter isPositionable) - } + else setChildrenPos(pos, children filter isPositionable) } } tree @@ -198,19 +195,23 @@ self: Global => inform(msg) inform("================= in =================") inform(tree.toString) + throw new ValidateError } def validate(tree: Tree, encltree: Tree): Unit = try { if (isPositionable(tree)) { - if (!tree.pos.isDefined) { - error("tree without position: "+tree) - throw new ValidateError + if (!tree.pos.isDefined) + error("tree without position["+tree.id+"]:"+tree) + if (encltree.pos.isSynthetic) { + if (!tree.pos.isSynthetic) + error("synthetic "+encltree+" contains nonsynthetic["+tree.id+"] " + tree) + } else { + if (!(encltree.pos includes tree.pos)) + error(encltree+" does not include["+tree.id+"] "+tree) + findOverlapping(tree.children flatMap solidDescendants) match { + case List() => ; + case xs => error("overlapping trees: "+xs) + } } - if (encltree.pos.isSynthetic && !tree.pos.isDefined && tree.pos.isSynthetic) - error("synthetic "+encltree+" contains nonsynthetic" + tree) - if (tree.pos.isDefined && !(encltree.pos includes tree.pos)) - error(encltree+" does not include "+tree) - for ((t1, t2) <- findOverlapping(tree.children flatMap solidDescendants)) - error("overlapping trees: "+t1+" === and === "+t2) for (ct <- tree.children flatMap solidDescendants) validate(ct, tree) } } catch { diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index 86e680a599..2d158e1ee3 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -33,7 +33,7 @@ object REPL { else { try { object compiler extends Global(command.settings, reporter) { - printTypings = true +// printTypings = true } if (reporter.hasErrors) { reporter.flush() @@ -75,8 +75,8 @@ object REPL { /** Commands: * * reload file1 ... fileN - * typeat file line off1 off2? - * complete file line off1 off2? + * typeat file off1 off2? + * complete file off1 off2? */ def run(comp: Global) { val reloadResult = new comp.Response[Unit] @@ -122,5 +122,6 @@ object REPL { case Left(result) => println("==> "+result) case Right(exc/*: Throwable ??*/) => exc.printStackTrace; println("ERROR: "+exc) } + svar.unset() } } diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index 44b70a602c..227768acb0 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -302,6 +302,8 @@ trait Symbols { case None => true })) } + protected var activeLocks = 0 + // Lock a symbol, using the handler if the recursion depth becomes too great. def lock(handler: => Unit) = { if ((rawflags & LOCKED) != 0) { @@ -317,14 +319,20 @@ trait Symbols { recursionTable += (this -> 1) } } else { handler } - } else { rawflags |= LOCKED } + } else { + rawflags |= LOCKED + activeLocks += 1 + } } // Unlock a symbol def unlock() = { - rawflags = rawflags & ~LOCKED - if (settings.Yrecursion.value != 0) - recursionTable -= this + if ((rawflags & LOCKED) != 0) { + activeLocks -= 1 + rawflags = rawflags & ~LOCKED + if (settings.Yrecursion.value != 0) + recursionTable -= this + } } // Tests ---------------------------------------------------------------------- @@ -812,6 +820,13 @@ trait Symbols { infos ne null } + /** Was symbol's type updated during given phase? */ + final def hasTypeAt(pid: Phase#Id): Boolean = { + var infos = this.infos + while ((infos ne null) && phaseId(infos.validFrom) > pid) infos = infos.prev + infos ne null + } + /** The type constructor of a symbol is: * For a type symbol, the type corresponding to the symbol itself, * excluding parameters. diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 20061515c8..9c41249426 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -470,9 +470,9 @@ trait Namers { self: Analyzer => val getterName = if (hasBoolBP) "is" + beanName else "get" + beanName val getterMods = Modifiers(flags, mods.privateWithin, - mods.annotations map (_.duplicate)) + mods.annotations map (_.syntheticDuplicate)) val beanGetterDef = atPos(vd.pos) { - DefDef(getterMods, getterName, Nil, List(Nil), tpt.duplicate, + DefDef(getterMods, getterName, Nil, List(Nil), tpt.syntheticDuplicate, if (mods hasFlag DEFERRED) EmptyTree else Select(This(getter.owner.name), name)) } enterSyntheticSym(beanGetterDef) @@ -936,7 +936,7 @@ trait Namers { self: Analyzer => var deftParams = tparams map copyUntyped[TypeDef] val defvParamss = previous map (_.map(p => { // in the default getter, remove the default parameter - val p1 = atPos(p.pos) { ValDef(p.mods &~ DEFAULTPARAM, p.name, p.tpt.duplicate, EmptyTree) } + val p1 = atPos(p.pos) { ValDef(p.mods &~ DEFAULTPARAM, p.name, p.tpt.syntheticDuplicate, EmptyTree) } UnTyper.traverse(p1) p1 })) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 1a2495f00c..159062dca0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1029,7 +1029,7 @@ trait Typers { self: Analyzer => // A method to replace a super reference by a New in a supercall def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match { case Apply(fn, args) => - treeCopy.Apply(scall, transformSuperCall(fn), args map (_.duplicate)) + treeCopy.Apply(scall, transformSuperCall(fn), args map (_.syntheticDuplicate)) case Select(Super(_, _), nme.CONSTRUCTOR) => treeCopy.Select( scall, @@ -1040,15 +1040,15 @@ trait Typers { self: Analyzer => treeInfo.firstConstructor(templ.body) match { case constr @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => // Convert constructor body to block in environment and typecheck it - val cstats1: List[Tree] = cstats map (_.duplicate) + val cstats1: List[Tree] = cstats map (_.syntheticDuplicate) val scall = if (cstats.isEmpty) EmptyTree else cstats.last val cbody1 = scall match { case Apply(_, _) => treeCopy.Block(cbody, cstats1.init, - if (supertparams.isEmpty) cunit.duplicate + if (supertparams.isEmpty) cunit.syntheticDuplicate else transformSuperCall(scall)) case _ => - treeCopy.Block(cbody, cstats1, cunit.duplicate) + treeCopy.Block(cbody, cstats1, cunit.syntheticDuplicate) } val outercontext = context.outer @@ -1056,7 +1056,7 @@ trait Typers { self: Analyzer => val cscope = outercontext.makeNewScope(constr, outercontext.owner)(ParentTypesScopeKind(clazz)) val cbody2 = newTyper(cscope) // called both during completion AND typing. .typePrimaryConstrBody(clazz, - cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate))) + cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.syntheticDuplicate))) scall match { case Apply(_, _) => @@ -1570,13 +1570,17 @@ trait Typers { self: Analyzer => * @return ... */ def typedBlock(block: Block, mode: Int, pt: Type): Block = { - if (context.retyping) { - for (stat <- block.stats) { - if (stat.isDef) context.scope.enter(stat.symbol) + namer.enterSyms(block.stats) + for (stat <- block.stats) { + if (onlyPresentation && stat.isDef) { + if (stat.isDef) { + var e = context.scope.lookupEntry(stat.symbol.name) + while ((e ne null) && (e.sym ne stat.symbol)) e = e.tail + if (e eq null) context.scope.enter(stat.symbol) + } } + enterLabelDef(stat) } - namer.enterSyms(block.stats) - block.stats foreach enterLabelDef val stats1 = typedStats(block.stats, context.owner) val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt) val block1 = treeCopy.Block(block, stats1, expr1) @@ -2380,7 +2384,7 @@ trait Typers { self: Analyzer => // and then stripping the "self =>" and substituting // in the supplied selfsym. val funcparm = ValDef(NoMods, nme.self, TypeTree(selfsym.info), EmptyTree) - val func = Function(List(funcparm), ann.duplicate) + val func = Function(List(funcparm), ann.syntheticDuplicate) // The .duplicate of annot.constr // deals with problems that // accur if this annotation is @@ -3077,7 +3081,7 @@ trait Typers { self: Analyzer => def mkAssign(vble: Tree): Tree = Assign( vble, - Apply(Select(vble.duplicate, prefix) setPos fun.pos, args) setPos tree.pos + Apply(Select(vble.syntheticDuplicate, prefix) setPos fun.pos, args) setPos tree.pos ) setPos tree.pos val tree1 = qual match { case Select(qualqual, vname) => @@ -3368,7 +3372,7 @@ trait Typers { self: Analyzer => imports1 = imports1.tail } defSym = impSym - qual = atPos(tree.pos.focusStart)(resetPos(imports.head.qual.duplicate)) + qual = atPos(tree.pos.focusStart)(resetPos(imports.head.qual.syntheticDuplicate)) pre = qual.tpe } else { if (settings.debug.value) { @@ -3742,7 +3746,7 @@ trait Typers { self: Analyzer => val result = if (tree1.isEmpty) tree1 else adapt(tree1, mode, pt) if (printTypings) println("adapted "+tree1+":"+tree1.tpe+" to "+pt+", "+context.undetparams); //DEBUG // if ((mode & TYPEmode) != 0) println("type: "+tree1+" has type "+tree1.tpe) - if (phase.id == currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result) + if (phase.id <= currentRun.typerPhase.id) signalDone(context.asInstanceOf[analyzer.Context], tree, result) result } catch { case ex: CompilerControl#FreshRunReq => throw ex diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 0bb1f87ed4..2b8837c084 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -95,14 +95,14 @@ trait Unapplies { self: Analyzer => } def copyUntyped[T <: Tree](tree: T): T = { - val tree1 = tree.duplicate + val tree1 = tree.syntheticDuplicate UnTyper.traverse(tree1) tree1 } def copyUntypedInvariant(td: TypeDef): TypeDef = { val tree1 = treeCopy.TypeDef(td, td.mods &~ (COVARIANT | CONTRAVARIANT), - td.name, td.tparams map (_.duplicate), td.rhs.duplicate) + td.name, td.tparams map (_.syntheticDuplicate), td.rhs.syntheticDuplicate) UnTyper.traverse(tree1) tree1 } diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index 07b0a785d5..0f427420b8 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -13,14 +13,35 @@ object Position { trait Position { import Position.tabInc + + /** An optional value containing the point of this position as an offset in a source file, + * or None if not defined + */ def offset: Option[Int] = None + + /** An optional value containing the source file referred to by this position, or + * None if not defined. + */ def source: Option[SourceFile] = None + + /** Is this position neither a NoPosition nor a FakePosition? + * If isDefined is true, offset and source are both defined. + */ def isDefined: Boolean = false + + /** Is this position a synthetic position? */ def isSynthetic: Boolean = false + + /** if possible, make this position a synthetic one */ def toSynthetic: Position = this + /** The start of the position's range */ def start: Int = point + + /** The point (where the ^ is) of the position */ def point: Int = offset.get + + /** The end of the position's range */ def end: Int = point def startOrElse(d: Int) = offset.getOrElse(d) @@ -36,6 +57,9 @@ trait Position { */ def union(pos: Position) = this + /** The underlying position; for a SyntheticAliasPosition this is the underlying position + * of the aliased tree. + */ def underlying = this /** If this is a range position, the offset position of its start. @@ -53,24 +77,42 @@ trait Position { */ def focusEnd = this + /** Does this position include the given position `pos`. + * This holds if both positions are defined, and the range [start..end] of this position + * is the same or covers the range of the given position. + */ def includes(pos: Position) = isDefined && pos.isDefined && start <= pos.start && pos.end <= end + /** Does this position properly include the given position `pos` ("properly" meaning their + * ranges are not the same)? + */ def properlyIncludes(pos: Position) = includes(pos) && (start < pos.start || pos.end < end) /** Does this position precede that position? + * This holds if both positions are defined and the end point of this position + * is not larger than the start point of the given position. */ def precedes(pos: Position) = isDefined && pos.isDefined && end <= pos.start + /** Does this position properly precede the given position `pos` ("properly" meaning their ranges + * do not share a common point). + */ def properlyPrecedes(pos: Position) = precedes(pos) && start < pos.end + /** Does this position overlap with that position? + * This holds if both positions are defined and there is an interval of + * non-zero length that is shared by both position ranges. + */ def overlaps(pos: Position) = isDefined && pos.isDefined && (pos.start <= start && start < pos.end) || (start <= pos.start && pos.start < end) + /** Does this position cover the same range as that position? + */ def sameRange(pos: Position) = isDefined && pos.isDefined && start == pos.start && end == pos.end @@ -161,9 +203,11 @@ extends OffsetPosition(source0, point) { override def startOrElse(d: Int) = start override def pointOrElse(d: Int) = point override def withStart(off: Int) = new RangePosition(source0, off, point, end) - override def withEnd(off: Int) = new RangePosition(source0, start, off, end) - override def withPoint(off: Int) = new RangePosition(source0, start, point, off) - override def union(pos: Position) = new RangePosition(source0, start min pos.start, point, end max pos.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) 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) @@ -175,17 +219,21 @@ extends OffsetPosition(source0, point) { /** A position to be used for synthetic trees that do not correspond to some original tree * @note Trees with synthetic positions may not contain trees with real positions inside them! + * todo: needed? */ class SyntheticRangePosition(source0: SourceFile, start: Int, point: Int, end: Int) extends RangePosition(source0, start, point, end) { override def isSynthetic = true override def toSynthetic = this override def withStart(off: Int) = new SyntheticRangePosition(source0, off, point, end) - override def withEnd(off: Int) = new SyntheticRangePosition(source0, start, off, end) - override def withPoint(off: Int) = new SyntheticRangePosition(source0, start, point, off) - override def union(pos: Position) = new SyntheticRangePosition(source0, start min pos.start, point, end max pos.end) + override def withEnd(off: Int) = new SyntheticRangePosition(source0, start, point, off) + override def withPoint(off: Int) = new SyntheticRangePosition(source0, start, off, end) + override def union(pos: Position) = + if (pos.isDefined) new SyntheticRangePosition(source0, start min pos.start, point, end max pos.end) + else this override def focusStart = new SyntheticOffsetPosition(source0, start) override def focusPoint = new SyntheticOffsetPosition(source0, point) override def focusEnd = new SyntheticOffsetPosition(source0, end) + override def show = "<["+start+":"+end+"]>" } diff --git a/src/library/scala/Tuple2.scala b/src/library/scala/Tuple2.scala index bcf30e58aa..7edea7db15 100644 --- a/src/library/scala/Tuple2.scala +++ b/src/library/scala/Tuple2.scala @@ -82,10 +82,22 @@ object Tuple2 { /** Tuple2 is the canonical representation of a @see Product2 * */ -case class Tuple2[+T1, +T2](_1:T1,_2:T2) - extends Product2[T1, T2] -{ - override def toString() = "(" + _1 + "," + _2 + ")" +case class Tuple2[+T1, +T2](_1:T1, _2:T2) extends Product2[T1, T2] { +/* + def map[CC[X] <: Traversable[X], A1, A2, B](implicit fst: T1 => CC[A1], snd: T2 => Traversable[A2]) = (f: (A1, A2) => B) => { + val b = fst(_1).genericBuilder[B] + val it1 = _1.iterator + val it2 = _2.iterator + while (it1.hasNext && it2.hasNext) + b += f(it1.next, it2.next) + b.result + } +*/ + override def toString() = { + val sb = new StringBuilder + sb.append('(').append(_1).append(',').append(_2).append(')') + sb.toString + } /** Swap the elements of the tuple */ def swap: Tuple2[T2,T1] = Tuple2(_2, _1) diff --git a/src/library/scala/collection/generic/TraversableClass.scala b/src/library/scala/collection/generic/TraversableClass.scala index c107bddd0d..04c61dc413 100644 --- a/src/library/scala/collection/generic/TraversableClass.scala +++ b/src/library/scala/collection/generic/TraversableClass.scala @@ -11,16 +11,53 @@ package scala.collection.generic +import annotation.unchecked.uncheckedVariance + trait TraversableClass[+A, +CC[X] <: Traversable[X]] { - /** The factory companion object that builds instances of class CC */ + def foreach[U](f: A => U): Unit + def head: A + def isEmpty: Boolean + /** The factory companion object that builds instances of class CC */ def companion: Companion[CC] - /** The builder that builds instances of CC[A] */ + /** The builder that builds instances of CC[A] */ protected[this] def newBuilder: Builder[A, CC[A]] = companion.newBuilder[A] /** The generic builder that builds instances of CC at arbitrary element types. */ def genericBuilder[B]: Builder[B, CC[B]] = companion.newBuilder[B] + + def unzip[A1, A2](implicit toPair: A => (A1, A2)): (CC[A1], CC[A2]) = { + val b1 = genericBuilder[A1] + val b2 = genericBuilder[A2] + for (xy <- this) { + val (x, y) = toPair(xy) + b1 += x + b2 += y + } + (b1.result, b2.result) + } + + def flatten[B](implicit toTraversable: A => Traversable[B]): CC[B] = { + val b = genericBuilder[B] + for (xs <- this) + b ++= toTraversable(xs) + b.result + } + + def transpose[B](implicit toTraversable: A => Traversable[B]): CC[CC[B] @uncheckedVariance] = { + val bs: Array[Builder[B, CC[B]]] = head.map(_ => genericBuilder[B]).toArray + for (xs <- this) { + var i = 0 + for (x <- toTraversable(xs)) { + bs(i) += x + i += 1 + } + } + val bb = genericBuilder[CC[B]] + for (b <- bs) bb += b.result + bb.result + } } |