summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-06-18 15:22:12 +0000
committerMartin Odersky <odersky@gmail.com>2009-06-18 15:22:12 +0000
commite6c140fecd361fdec9ad1d3c1579b8bbd3e9f007 (patch)
tree4ce37c932a6e5dff0237f4d2cbc1b2b0258bb41e
parent5d11bc473378d30483488889de7b8c381c1d66c7 (diff)
downloadscala-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
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala13
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala31
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/Parsers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala22
-rw-r--r--src/compiler/scala/tools/nsc/interactive/CompilerControl.scala60
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Global.scala79
-rwxr-xr-xsrc/compiler/scala/tools/nsc/interactive/Positions.scala73
-rw-r--r--src/compiler/scala/tools/nsc/interactive/REPL.scala7
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala32
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala4
-rw-r--r--src/compiler/scala/tools/nsc/util/Position.scala60
-rw-r--r--src/library/scala/Tuple2.scala20
-rw-r--r--src/library/scala/collection/generic/TraversableClass.scala41
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
+ }
}