diff options
Diffstat (limited to 'src')
19 files changed, 228 insertions, 223 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js index 0f25f024f4..925f07bcb1 100644 --- a/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js +++ b/src/compiler/scala/tools/nsc/doc/html/resource/lib/index.js @@ -438,10 +438,13 @@ function kindFilter(kind) { /* Applies the kind filter. */ function kindFilterSync() { - if (kindFilterState == "all" || focusFilterState != null) + if (kindFilterState == "all" || focusFilterState != null) { + $("#tpl a.packhide").text('hide'); $("#tpl ol.templates").show(); - else + } else { + $("#tpl a.packhide").text('show'); $("#tpl ol.templates").hide(); + } } function resizeFilterBlock() { diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index 64178b5eac..0c5d85d2a8 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -199,7 +199,7 @@ trait CompilerControl { self: Global => /** Cancels current compiler run and start a fresh one where everything will be re-typechecked * (but not re-loaded). */ - def askReset() = scheduler raise FreshRunReq + def askReset() = scheduler raise (new FreshRunReq) /** Tells the compile server to shutdown, and not to restart again */ def askShutdown() = scheduler raise ShutdownReq @@ -307,7 +307,7 @@ trait CompilerControl { self: Global => /** Signals a request for a fresh background compiler run. * Note: The object has to stay top-level so that the PresentationCompilerThread may access it. */ -object FreshRunReq extends ControlThrowable +class FreshRunReq extends ControlThrowable /** Signals a request for a shutdown of the presentation compiler. * Note: The object has to stay top-level so that the PresentationCompilerThread may access it. diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 9b50b82bb3..2b920c8c03 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -173,7 +173,7 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "") def isOutOfDate: Boolean = outOfDate def demandNewCompilerRun() = { - if (outOfDate) throw FreshRunReq // cancel background compile + if (outOfDate) throw new FreshRunReq // cancel background compile else outOfDate = true // proceed normally and enable new background compile } @@ -316,7 +316,7 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "") } logreplay("exception thrown", scheduler.pollThrowable()) match { - case Some(ex @ FreshRunReq) => + case Some(ex: FreshRunReq) => newTyperRun() minRunId = currentRunId demandNewCompilerRun() @@ -537,9 +537,10 @@ class Global(settings: Settings, reporter: Reporter, projectName: String = "") } catch { case CancelException => debugLog("cancelled") - case ex @ FreshRunReq => + case ex: FreshRunReq => if (debugIDE) { println("FreshRunReq thrown during response") + ex.printStackTrace() } response raise ex throw ex diff --git a/src/compiler/scala/tools/nsc/interactive/Picklers.scala b/src/compiler/scala/tools/nsc/interactive/Picklers.scala index 53ef20507f..561fa47e94 100644 --- a/src/compiler/scala/tools/nsc/interactive/Picklers.scala +++ b/src/compiler/scala/tools/nsc/interactive/Picklers.scala @@ -16,8 +16,13 @@ import mutable.ListBuffer trait Picklers { self: Global => - lazy val freshRunReq = singletonPickler(FreshRunReq) - lazy val shutdownReq = singletonPickler(ShutdownReq) + lazy val freshRunReq = + unitPickler + .wrapped { _ => new FreshRunReq } { x => () } + .labelled ("FreshRunReq") + .cond (_.isInstanceOf[FreshRunReq]) + + lazy val shutdownReq = singletonPickler(ShutdownReq) def defaultThrowable[T <: Throwable]: CondPickler[T] = javaInstancePickler[T] cond { _ => true } diff --git a/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala b/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala index 4ba0208c39..098884dab1 100644 --- a/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala +++ b/src/compiler/scala/tools/nsc/interactive/PresentationCompilerThread.scala @@ -24,7 +24,7 @@ final class PresentationCompilerThread(var compiler: Global, name: String = "") try { compiler.backgroundCompile() } catch { - case FreshRunReq => + case ex: FreshRunReq => compiler.debugLog("fresh run req caught, starting new pass") } compiler.log.flush() @@ -40,7 +40,7 @@ final class PresentationCompilerThread(var compiler: Global, name: String = "") compiler.log.flush() ex match { - case FreshRunReq => + case ex: FreshRunReq => compiler.debugLog("fresh run req caught outside presentation compiler loop; ignored") // This shouldn't be reported case _ : Global#ValidateException => // This will have been reported elsewhere compiler.debugLog("validate exception caught outside presentation compiler loop; ignored") diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index 2532801d83..5648f97f84 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -88,21 +88,17 @@ trait Matrix extends MatrixAdditions { context: MatrixContext): Tree = { import context._ - // log("handlePattern: selector.tpe = " + selector.tpe) - // sets up top level match val matrixInit: MatrixInit = { val v = copyVar(selector, isChecked, selector.tpe, "temp") MatrixInit(List(v), cases, atPos(selector.pos)(MATCHERROR(v.ident))) } - - val matrix = new MatchMatrix(context) { lazy val data = matrixInit } - val rep = matrix.expansion // expands casedefs and assigns name - val mch = typer typed rep.toTree // executes algorithm, converts tree to DFA - val dfatree = typer typed Block(matrixInit.valDefs, mch) // packages into a code block + val matrix = new MatchMatrix(context) { lazy val data = matrixInit } + val mch = typer typed matrix.expansion.toTree + val dfatree = typer typed Block(matrix.data.valDefs, mch) // redundancy check - matrix.targets filter (_.isNotReached) foreach (cs => cunit.error(cs.body.pos, "unreachable code")) + matrix.targets filter (_.unreached) foreach (cs => cunit.error(cs.body.pos, "unreachable code")) // optimize performs squeezing and resets any remaining NO_EXHAUSTIVE tracing("handlePattern")(matrix optimize dfatree) } @@ -168,9 +164,9 @@ trait Matrix extends MatrixAdditions { val emptyPatternVarGroup = PatternVarGroup() class PatternVarGroup(val pvs: List[PatternVar]) { - def syms = pvs map (_.sym) + def syms = pvs map (_.sym) def valDefs = pvs map (_.valDef) - def idents = pvs map (_.ident) + def idents = pvs map (_.ident) def extractIndex(index: Int): (PatternVar, PatternVarGroup) = { val (t, ts) = self.extractIndex(pvs, index) diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index 3b481dd03e..e59d8c7858 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -12,8 +12,7 @@ import PartialFunction._ /** Traits which are mixed into MatchMatrix, but separated out as * (somewhat) independent components to keep them on the sidelines. */ -trait MatrixAdditions extends ast.TreeDSL -{ +trait MatrixAdditions extends ast.TreeDSL { self: ExplicitOuter with ParallelMatching => import global.{ typer => _, _ } @@ -30,50 +29,52 @@ trait MatrixAdditions extends ast.TreeDSL private val settings_squeeze = !settings.Ynosqueeze.value - def squeezedBlockPVs(pvs: List[PatternVar], exp: Tree): Tree = - squeezedBlock(pvs map (_.valDef), exp) + class RefTraverser(vd: ValDef) extends Traverser { + private val targetSymbol = vd.symbol + private var safeRefs = 0 + private var isSafe = true - /** Compresses multiple Blocks. */ - def mkBlock(stats: List[Tree], expr: Tree): Tree = expr match { - case Block(stats1, expr1) if stats.isEmpty => mkBlock(stats1, expr1) - case _ => Block(stats, expr) - } + def canDrop = isSafe && safeRefs == 0 + def canInline = isSafe && safeRefs == 1 - def squeezedBlock(vds: List[Tree], exp: Tree): Tree = - if (settings_squeeze) mkBlock(Nil, squeezedBlock1(vds, exp)) - else mkBlock(vds, exp) + override def traverse(tree: Tree): Unit = tree match { + case t: Ident if t.symbol eq targetSymbol => + // target symbol's owner should match currentOwner + if (targetSymbol.owner == currentOwner) safeRefs += 1 + else isSafe = false - private def squeezedBlock1(vds: List[Tree], exp: Tree): Tree = { - class RefTraverser(sym: Symbol) extends Traverser { - var nref, nsafeRef = 0 - override def traverse(tree: Tree) = tree match { - case t: Ident if t.symbol eq sym => - nref += 1 - if (sym.owner == currentOwner) // oldOwner should match currentOwner - nsafeRef += 1 - - case LabelDef(_, args, rhs) => - (args dropWhile(_.symbol ne sym)) match { - case Nil => - case _ => nref += 2 // cannot substitute this one - } - traverse(rhs) - case t if nref > 1 => // abort, no story to tell - case t => - super.traverse(t) - } - } + case LabelDef(_, params, rhs) => + if (params exists (_.symbol eq targetSymbol)) // cannot substitute this one + isSafe = false - class Subst(sym: Symbol, rhs: Tree) extends Transformer { - var stop = false - override def transform(tree: Tree) = tree match { - case t: Ident if t.symbol == sym => - stop = true - rhs - case _ => if (stop) tree else super.transform(tree) - } + traverse(rhs) + case _ if safeRefs > 1 => () + case _ => + super.traverse(tree) + } + } + class Subst(vd: ValDef) extends Transformer { + private var stop = false + override def transform(tree: Tree): Tree = tree match { + case t: Ident if t.symbol == vd.symbol => + stop = true + vd.rhs + case _ => + if (stop) tree + else super.transform(tree) } + } + + /** Compresses multiple Blocks. */ + private def combineBlocks(stats: List[Tree], expr: Tree): Tree = expr match { + case Block(stats1, expr1) if stats.isEmpty => combineBlocks(stats1, expr1) + case _ => Block(stats, expr) + } + def squeezedBlock(vds: List[Tree], exp: Tree): Tree = + if (settings_squeeze) combineBlocks(Nil, squeezedBlock1(vds, exp)) + else combineBlocks(vds, exp) + private def squeezedBlock1(vds: List[Tree], exp: Tree): Tree = { lazy val squeezedTail = squeezedBlock(vds.tail, exp) def default = squeezedTail match { case Block(vds2, exp2) => Block(vds.head :: vds2, exp2) @@ -83,17 +84,13 @@ trait MatrixAdditions extends ast.TreeDSL if (vds.isEmpty) exp else vds.head match { case vd: ValDef => - val sym = vd.symbol - val rt = new RefTraverser(sym) - rt.atOwner (owner) (rt traverse squeezedTail) - - rt.nref match { - case 0 => squeezedTail - case 1 if rt.nsafeRef == 1 => new Subst(sym, vd.rhs) transform squeezedTail - case _ => default - } - case _ => - default + val rt = new RefTraverser(vd) + rt.atOwner(owner)(rt traverse squeezedTail) + + if (rt.canDrop) squeezedTail + else if (rt.canInline) new Subst(vd) transform squeezedTail + else default + case _ => default } } } @@ -109,9 +106,7 @@ trait MatrixAdditions extends ast.TreeDSL object lxtt extends Transformer { override def transform(tree: Tree): Tree = tree match { case blck @ Block(vdefs, ld @ LabelDef(name, params, body)) => - def shouldInline(t: FinalState) = t.isReachedOnce && (t.labelSym eq ld.symbol) - - if (targets exists shouldInline) squeezedBlock(vdefs, body) + if (targets exists (_ shouldInline ld.symbol)) squeezedBlock(vdefs, body) else blck case t => @@ -166,7 +161,7 @@ trait MatrixAdditions extends ast.TreeDSL private def requiresExhaustive(sym: Symbol) = { (sym.isMutable) && // indicates that have not yet checked exhaustivity - !(sym hasFlag NO_EXHAUSTIVE) && // indicates @unchecked + !(sym hasFlag NO_EXHAUSTIVE) && // indicates @unchecked (sym.tpe.typeSymbol.isSealed) && !isValueClass(sym.tpe.typeSymbol) // make sure it's not a primitive, else (5: Byte) match { case 5 => ... } sees no Byte } diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 89e849d038..1b0265ce5d 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -25,7 +25,7 @@ trait ParallelMatching extends ast.TreeDSL self: ExplicitOuter => import global.{ typer => _, _ } - import definitions.{ AnyRefClass, IntClass, BooleanClass, getProductArgs, productProj } + import definitions.{ AnyRefClass, NothingClass, IntClass, BooleanClass, getProductArgs, productProj } import CODE._ import Types._ import Debug._ @@ -55,16 +55,8 @@ trait ParallelMatching extends ast.TreeDSL */ final def requestBody(bx: Int, subst: Bindings): Tree = { // shortcut - if (bx < 0) - return Apply(ID(shortCuts(-bx-1)), Nil) - - val pvgroup = PatternVarGroup.fromBindings(subst.get(), targets(bx).freeVars) - val target = targets(bx) - - // first time this bx is requested - might be bound elsewhere - if (target.isNotReached) target.createLabelBody(bx, pvgroup) - // call label "method" if possible - else target.getLabelBody(pvgroup) + if (bx < 0) Apply(ID(shortCuts(-bx-1)), Nil) + else targets(bx) labelBody subst } /** the injection here handles alternatives and unapply type tests */ @@ -107,9 +99,9 @@ trait ParallelMatching extends ast.TreeDSL def allValDefs = extraValDefs ::: accessorPatternVars.valDefs // tests - def isDefined = sym ne NoSymbol - def isSimple = tpe.isByte || tpe.isShort || tpe.isChar || tpe.isInt - def isCaseClass = tpe.typeSymbol.isCase + def isDefined = sym ne NoSymbol + def isSubrangeType = Set(ByteClass, ShortClass, CharClass, IntClass) contains tpe.typeSymbol + def isCaseClass = tpe.typeSymbol.isCase // sequences def seqType = tpe.widen baseType SeqClass @@ -144,7 +136,7 @@ trait ParallelMatching extends ast.TreeDSL // ... should compile to a switch. It doesn't because the scrut isn't Int/Char, but // that could be handle in an if/else since every pattern requires an Int. // More immediately, Byte and Short scruts should also work. - if (!scrut.isSimple) None + if (!scrut.isSubrangeType) None else { val (_lits, others) = ps span isSwitchableConst val lits = _lits collect { case x: LiteralPattern => x } @@ -162,7 +154,7 @@ trait ParallelMatching extends ast.TreeDSL override val ps: List[LiteralPattern], val defaultPattern: Option[Pattern] ) extends PatternMatch(scrut, ps) { - require(scrut.isSimple && (ps forall (_.isSwitchable))) + require(scrut.isSubrangeType && (ps forall (_.isSwitchable))) } case class PatternMatch(scrut: Scrutinee, ps: List[Pattern]) { @@ -217,17 +209,6 @@ trait ParallelMatching extends ast.TreeDSL def MixtureRule(scrut: Scrutinee, column: List[Pattern], rest: Rep): RuleApplication = PatternMatch(scrut, column) mkRule rest - /** - * Class encapsulating a guard expression in a pattern match: - * case ... if(tree) => ... - */ - case class Guard(tree: Tree) { - def isEmpty = tree.isEmpty - def duplicate = Guard(tree.duplicate) - override def toString() = if (isEmpty) "" else " // if %s" format tree - } - val NoGuard = Guard(EmptyTree) - /***** Rule Applications *****/ sealed abstract class RuleApplication { @@ -263,14 +244,13 @@ trait ParallelMatching extends ast.TreeDSL /** {case ... if guard => bx} else {guardedRest} */ /** VariableRule: The top-most rows has only variable (non-constructor) patterns. */ - case class VariableRule(subst: Bindings, guard: Guard, guardedRest: Rep, bx: Int) extends RuleApplication { + case class VariableRule(subst: Bindings, guard: Tree, guardedRest: Rep, bx: Int) extends RuleApplication { def pmatch: PatternMatch = impossible def rest: Rep = guardedRest - lazy val cond = if (guard.isEmpty) TRUE else guard.duplicate.tree + lazy val cond = if (guard.isEmpty) TRUE else guard lazy val success = requestBody(bx, subst) lazy val failure = guardedRest.toTree - lazy val pvgroup = PatternVarGroup.fromBindings(subst.get()) final def tree(): Tree = @@ -278,11 +258,7 @@ trait ParallelMatching extends ast.TreeDSL else squeezedBlock(pvgroup.valDefs, codegen) } - /** Mixture rule for all literal ints (and chars) i.e. hopefully a switch - * will be emitted on the JVM. - */ - class MixLiteralInts(val pmatch: PatternSwitch, val rest: Rep) extends RuleApplication - { + class MixLiteralInts(val pmatch: PatternSwitch, val rest: Rep) extends RuleApplication { val literals = pmatch.ps val defaultPattern = pmatch.defaultPattern @@ -312,42 +288,41 @@ trait ParallelMatching extends ast.TreeDSL case None => (Nil, Nil) case Some(Pattern(_, vs)) => (vs, List(rebindAll(rest rows literals.size, vs, scrut.sym))) } + // literalMap is a map from each literal to a list of row indices. // varMap is a list from each literal to a list of the defined vars. - lazy val (literalMap, varMap) = { - val tags = literals map (_.intValue) - val varMap = tags zip (literals map (_.deepBoundVariables)) - val litMap = - tags.zipWithIndex.reverse.foldLeft(IntMap.empty[List[Int]]) { - // we reverse before the fold so the list can be built with :: - case (map, (tag, index)) => map.updated(tag, index :: map.getOrElse(tag, Nil)) - } - - (litMap, varMap) + lazy val (litPairs, varMap) = ( + literals.zipWithIndex map { + case (lit, index) => + val tag = lit.intValue + (tag -> index, tag -> lit.deepBoundVariables) + } unzip + ) + def literalMap = litPairs groupBy (_._1) map { + case (k, vs) => (k, vs map (_._2)) } lazy val cases = for ((tag, indices) <- literalMap.toList) yield { val newRows = indices map (i => addDefaultVars(i)(rest rows i)) - val r = remake(newRows ::: defaultRows, includeScrut = false) - val r2 = make(r.tvars, r.rows map (x => x rebind bindVars(tag, x.subst))) + val r = remake(newRows ++ defaultRows, includeScrut = false) + val r2 = make(r.tvars, r.rows map (x => x rebind bindVars(tag, x.subst))) CASE(Literal(tag)) ==> r2.toTree } - lazy val defaultTree = remake(defaultRows, includeScrut = false).toTree - def casesWithDefault = cases ::: List(CASE(WILD(IntClass.tpe)) ==> defaultTree) + lazy val defaultTree = remake(defaultRows, includeScrut = false).toTree + def defaultCase = CASE(WILD(IntClass.tpe)) ==> defaultTree // cond/success/failure only used if there is exactly one case. - lazy val (cond, success) = cases match { - case List(CaseDef(lit, _, body)) => (scrut.id MEMBER_== lit, body) - } + lazy val cond = scrut.id MEMBER_== cases.head.pat + lazy val success = cases.head.body lazy val failure = defaultTree // only one case becomes if/else, otherwise match def tree() = if (cases.size == 1) codegen - else casted MATCH (casesWithDefault: _*) + else casted MATCH (cases :+ defaultCase: _*) } /** mixture rule for unapply pattern @@ -426,7 +401,7 @@ trait ParallelMatching extends ast.TreeDSL val (squeezePVs, pvs, rows) = doSuccess val srep = remake(rows, pvs).toTree - squeezedBlockPVs(squeezePVs, srep) + squeezedBlock(squeezePVs map (_.valDef), srep) } final def tree() = @@ -521,7 +496,7 @@ trait ParallelMatching extends ast.TreeDSL // wrapping in a null check on the scrutinee nullSafe(compareFn, FALSE)(scrut.id) } - lazy val success = squeezedBlockPVs(pvs, remake(successRows, pvs, hasStar).toTree) + lazy val success = squeezedBlock(pvs map (_.valDef), remake(successRows, pvs, hasStar).toTree) lazy val failure = remake(failRows).toTree final def tree(): Tree = codegen @@ -535,7 +510,7 @@ trait ParallelMatching extends ast.TreeDSL private lazy val rhs = decodedEqualsType(head.tpe) match { case SingleType(pre, sym) => REF(pre, sym) - case PseudoType(o) => o.duplicate + case PseudoType(o) => o } lazy val label = @@ -546,7 +521,7 @@ trait ParallelMatching extends ast.TreeDSL lazy val success = remake(List( rest.rows.head.insert2(List(NoPattern), head.boundVariables, scrut.sym), - Row(emptyPatterns(1 + rest.tvars.size), NoBinding, NoGuard, shortCut(label)) + Row(emptyPatterns(1 + rest.tvars.size), NoBinding, EmptyTree, shortCut(label)) )).toTree lazy val failure = LabelDef(label, Nil, labelBody) @@ -637,7 +612,7 @@ trait ParallelMatching extends ast.TreeDSL /*** States, Rows, Etc. ***/ - case class Row(pats: List[Pattern], subst: Bindings, guard: Guard, bx: Int) { + case class Row(pats: List[Pattern], subst: Bindings, guard: Tree, bx: Int) { private def nobindings = subst.get().isEmpty private def bindstr = if (nobindings) "" else pp(subst) // if (pats exists (p => !p.isDefault)) @@ -693,8 +668,8 @@ trait ParallelMatching extends ast.TreeDSL def vprint(vs: List[Any]) = if (vs.isEmpty) "" else ": %s".format(pp(vs)) def rprint(r: Row) = pp(r) def tprint(t: FinalState) = - if (t.freeVars.isEmpty) " ==> %s".format(pp(t.body)) - else " ==>\n %s".format(pp(t.freeVars -> t.body)) + if (t.params.isEmpty) " ==> %s".format(pp(t.body)) + else " ==>\n %s".format(pp(t.params -> t.body)) val xs = rows zip targets map { case (r,t) => rprint(r) + tprint(t) } val ppstr = pp(xs, newlines = true) @@ -703,70 +678,38 @@ trait ParallelMatching extends ast.TreeDSL } } - abstract class State { - def body: Tree - def freeVars: List[Symbol] - def isFinal: Boolean - } - - case class FinalState(bx: Int, body: Tree, freeVars: List[Symbol]) extends State { + case class FinalState(bx: Int, body: Tree, params: List[Symbol]) { private var referenceCount = 0 - private var _label: LabelDef = null - private var _labelSym: Symbol = null - - def labelSym = _labelSym - def label = _label - - // @bug: typer is not able to digest a body of type Nothing being assigned result type Unit - def bodyTpe = if (body.tpe.isNothing) body.tpe else matchResultType - def duplicate = body.duplicate setType bodyTpe - - def isFinal = true - def isLabellable = !cond(body) { case _: Literal => true } - def isNotReached = referenceCount == 0 - def isReachedOnce = referenceCount == 1 - def isReachedTwice = referenceCount > 1 - - // arguments to pass to this body%xx - def labelParamTypes = label.tpe.paramTypes - - def createLabelBody(index: Int, pvgroup: PatternVarGroup) = { - val args = pvgroup.syms - val vdefs = pvgroup.valDefs - - val name = "body%" + index - require(_labelSym == null) - referenceCount += 1 - - if (isLabellable) { - val mtype = MethodType(freeVars, bodyTpe) - _labelSym = owner.newLabel(body.pos, name) setInfo mtype - _label = typer typedLabelDef LabelDef(_labelSym, freeVars, body setType bodyTpe) - // TRACE("Creating index %d: mtype = %s".format(bx, mtype)) - // TRACE("[New label] def %s%s: %s = %s".format(name, pp(freeVars), bodyTpe, body)) - } - - ifLabellable(vdefs, squeezedBlock(vdefs, label)) + // typer is not able to digest a body of type Nothing being assigned result type Unit + private def caseResultType = if (body.tpe.isNothing) body.tpe else matchResultType + private lazy val label: LabelDef = body match { + case Literal(_) => null + case _ => + val symbol = owner.newLabel(body.pos, "body%" + bx) setInfo MethodType(params, caseResultType) + // typer typedLabelDef + LabelDef(symbol, params, body setType caseResultType) } - def getLabelBody(pvgroup: PatternVarGroup): Tree = { - val idents = pvgroup map (_.rhs) - val vdefs = pvgroup.valDefs + def unreached = referenceCount == 0 + def shouldInline(sym: Symbol) = referenceCount == 1 && label != null && label.symbol == sym + + def labelBody(subst: Bindings): Tree = { referenceCount += 1 + val pvgroup = PatternVarGroup.fromBindings(subst.get(), params) - ifLabellable(vdefs, ID(labelSym) APPLY (idents)) + if (referenceCount > 1 && label != null) + ID(label.symbol) APPLY (pvgroup map (_.rhs)) + else squeezedBlock(pvgroup.valDefs, + if (label != null) label + else body.duplicate setType caseResultType + ) } - - private def ifLabellable(vdefs: List[Tree], t: => Tree) = - if (isLabellable) t - else squeezedBlock(vdefs, duplicate) - - override def toString() = pp("Final%d%s".format(bx, pp(freeVars)) -> body) + override def toString() = pp("Final%d%s".format(bx, pp(params)) -> body) } case class Rep(val tvars: PatternVarGroup, val rows: List[Row]) { lazy val Row(pats, subst, guard, index) = rows.head - lazy val guardedRest = if (guard.isEmpty) NoRep else make(tvars, rows.tail) + lazy val guardedRest = if (guard.isEmpty) Rep(Nil, Nil) else make(tvars, rows.tail) lazy val (defaults, others) = pats span (_.isDefault) /** Sealed classes. */ @@ -818,12 +761,11 @@ trait ParallelMatching extends ast.TreeDSL else "Rep(%dx%d)%s%s".format(tvars.size, rows.size, ppn(tvars), ppn(rows)) } - val NoRep = Rep(Nil, Nil) /** Expands the patterns recursively. */ final def expand(roots: List[PatternVar], cases: List[CaseDef]) = tracing("Expanded")(ExpandedMatrix( for ((CaseDef(pat, guard, body), index) <- cases.zipWithIndex) yield { - def mkRow(ps: List[Tree]) = Row(toPats(ps), NoBinding, Guard(guard), index) + def mkRow(ps: List[Tree]) = Row(toPats(ps), NoBinding, guard, index) val pattern = Pattern(pat) val row = mkRow(pat match { diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 40ff73e648..742ab32736 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -98,7 +98,15 @@ trait Patterns extends ast.TreeDSL { require (args.isEmpty) val Apply(select: Select, _) = tree - override def sufficientType = mkSingletonFromQualifier + override lazy val sufficientType = qualifier.tpe match { + case t: ThisType => singleType(t, sym) // this.X + case _ => + qualifier match { + case _: Apply => PseudoType(tree) + case _ => singleType(Pattern(qualifier).necessaryType, sym) + } + } + override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = backticked match { case Some(s) => "this." + s @@ -382,16 +390,6 @@ trait Patterns extends ast.TreeDSL { case Apply(f, Nil) => getPathSegments(f) case _ => Nil } - protected def mkSingletonFromQualifier = { - def pType = qualifier match { - case _: Apply => PseudoType(tree) - case _ => singleType(Pattern(qualifier).necessaryType, sym) - } - qualifier.tpe match { - case t: ThisType => singleType(t, sym) // this.X - case _ => pType - } - } } sealed trait NamePattern extends Pattern { diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 053a6d211a..fb18ce1d72 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -367,7 +367,7 @@ private[collection] trait GenTraversableOnce[+A] { def copyToArray[B >: A](xs: Array[B]): Unit /** Copies values of this $coll to an array. - * Fills the given array `xs` with values of this $coll, after skipping `start` values. + * Fills the given array `xs` with values of this $coll, beginning at index `start`. * Copying will stop once either the end of the current $coll is reached, * or the end of the array is reached. * diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala index 04d89299c8..b9a60ae1f1 100755 --- a/src/library/scala/collection/IndexedSeqOptimized.scala +++ b/src/library/scala/collection/IndexedSeqOptimized.scala @@ -103,11 +103,11 @@ trait IndexedSeqOptimized[+A, +Repr] extends IndexedSeqLike[A, Repr] { self => override /*IterableLike*/ def slice(from: Int, until: Int): Repr = { - val lo = from max 0 - val hi = until min length - val elems = hi - lo + val lo = math.max(from, 0) + val hi = math.min(until, length) + val elems = math.max(hi - lo, 0) val b = newBuilder - b.sizeHint(elems max 0) + b.sizeHint(elems) var i = lo while (i < hi) { @@ -185,11 +185,10 @@ trait IndexedSeqOptimized[+A, +Repr] extends IndexedSeqLike[A, Repr] { self => override /*SeqLike*/ def segmentLength(p: A => Boolean, from: Int): Int = { - val start = from val len = length - var i = start + var i = from while (i < len && p(this(i))) i += 1 - i - start + i - from } private def negLength(n: Int) = if (n >= length) -1 else n diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala index 458b26207e..b6713b65e4 100644 --- a/src/library/scala/collection/IterableLike.scala +++ b/src/library/scala/collection/IterableLike.scala @@ -90,9 +90,49 @@ self => iterator.next override /*TraversableLike*/ def slice(from: Int, until: Int): Repr = { - val lo = from max 0 - if (until <= lo) newBuilder.result - else newBuilder ++= (iterator drop lo take (until - lo)) result + val lo = math.max(from, 0) + val elems = until - lo + val b = newBuilder + if (elems <= 0) b.result + else { + b.sizeHintBounded(elems, this) + var i = 0 + val it = iterator drop lo + while (i < elems && it.hasNext) { + b += it.next + i += 1 + } + b.result + } + } + + override /*TraversableLike*/ def take(n: Int): Repr = { + val b = newBuilder + + if (n <= 0) b.result + else { + b.sizeHintBounded(n, this) + var i = 0 + val it = iterator + while (i < n && it.hasNext) { + b += it.next + i += 1 + } + b.result + } + } + + override /*TraversableLike*/ def drop(n: Int): Repr = { + val b = newBuilder + val lo = math.max(0, n) + b.sizeHint(this, -lo) + var i = 0 + val it = iterator + while (i < n && it.hasNext) { + it.next + i += 1 + } + b ++= it result } override /*TraversableLike*/ def takeWhile(p: A => Boolean): Repr = { diff --git a/src/library/scala/collection/IterableViewLike.scala b/src/library/scala/collection/IterableViewLike.scala index e0e1329844..e0f1ada2b8 100644 --- a/src/library/scala/collection/IterableViewLike.scala +++ b/src/library/scala/collection/IterableViewLike.scala @@ -63,6 +63,8 @@ trait IterableViewLike[+A, trait ZippedAll[A1 >: A, B] extends Transformed[(A1, B)] with super[GenIterableViewLike].ZippedAll[A1, B] + private[this] implicit def asThis(xs: Transformed[A]): This = xs.asInstanceOf[This] + /** Boilerplate method, to override in each subclass * This method could be eliminated if Scala had virtual classes */ @@ -81,6 +83,16 @@ trait IterableViewLike[+A, protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new { val pred = p } with DroppedWhile protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new { val pred = p } with TakenWhile + // After adding take and drop overrides to IterableLike, these overrides (which do nothing + // but duplicate the implementation in TraversableViewLike) had to be added to prevent the + // overrides in IterableLike from besting the overrides in TraversableViewLike when mixed + // together in e.g. SeqViewLike. This is a suboptimal situation. Examples of failing tests + // are run/bug2876 and run/viewtest. + protected override def newTaken(n: Int): Transformed[A] = newSliced(SliceInterval(0, n)) + protected override def newDropped(n: Int): Transformed[A] = newSliced(SliceInterval(n, Int.MaxValue)) + override def drop(n: Int): This = newDropped(n) + override def take(n: Int): This = newTaken(n) + override def zip[A1 >: A, B, That](that: GenIterable[B])(implicit bf: CanBuildFrom[This, (A1, B), That]): That = { newZipped(that).asInstanceOf[That] // was: val b = bf(repr) diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 7bd33cbb23..39c1d5b07f 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -975,8 +975,8 @@ trait Iterator[+A] extends TraversableOnce[A] { } /** Copies selected values produced by this iterator to an array. - * Fills the given array `xs` with at most `len` values produced by this - * iterator, after skipping `start` values. + * Fills the given array `xs` starting at index `start` with at most + * `len` values produced by this iterator. * Copying will stop once either the end of the current iterator is reached, * or the end of the array is reached, or `len` elements have been copied. * @@ -987,12 +987,11 @@ trait Iterator[+A] extends TraversableOnce[A] { * @param len the maximal number of elements to copy. * @tparam B the type of the elements of the array. * - * * @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit */ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = { var i = start - val end = start + len min xs.length + val end = start + math.min(len, xs.length) while (hasNext && i < end) { xs(i) = next() i += 1 diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala index 7c5cba0665..236a5bdaa3 100755 --- a/src/library/scala/collection/LinearSeqOptimized.scala +++ b/src/library/scala/collection/LinearSeqOptimized.scala @@ -168,7 +168,9 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea // since we are in collection.*, not immutable.*. // However making that change will pessimize all the // immutable linear seqs (like list) which surely expect - // drop to share. + // drop to share. (Or at least it would penalize List if + // it didn't override drop. It would be a lot better if + // the leaf collections didn't override so many methods.) // // Upshot: MutableList is broken and passes part of the // original list as the result of drop. diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index f79baa7c58..77dc15e695 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -93,6 +93,10 @@ trait SeqViewLike[+A, } with Patched[B] protected def newPrepended[B >: A](elem: B): Transformed[B] = new { protected[this] val fst = elem } with Prepended[B] + // see comment in IterableViewLike. + protected override def newTaken(n: Int): Transformed[A] = newSliced(SliceInterval(0, n)) + protected override def newDropped(n: Int): Transformed[A] = newSliced(SliceInterval(n, Int.MaxValue)) + override def reverse: This = newReversed.asInstanceOf[This] override def patch[B >: A, That](from: Int, patch: GenSeq[B], replaced: Int)(implicit bf: CanBuildFrom[This, B, That]): That = { diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index 2d3a4c229c..fe1d5d7d77 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -434,10 +434,14 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] def take(n: Int): Repr = slice(0, n) def drop(n: Int): Repr = - if (n <= 0) newBuilder ++= thisCollection result + if (n <= 0) { + val b = newBuilder + b.sizeHint(this) + b ++= thisCollection result + } else sliceWithKnownDelta(n, Int.MaxValue, -n) - def slice(from: Int, until: Int): Repr = sliceWithKnownBound(from max 0, until) + def slice(from: Int, until: Int): Repr = sliceWithKnownBound(math.max(from, 0), until) // Precondition: from >= 0, until > 0, builder already configured for building. private[this] def sliceInternal(from: Int, until: Int, b: Builder[A, Repr]): Repr = { diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index c14e24ab47..d8c8268a2e 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -171,6 +171,12 @@ sealed abstract class List[+A] extends LinearSeq[A] these } + override def slice(from: Int, until: Int): List[A] = { + val lo = math.max(from, 0) + if (until <= lo || isEmpty) Nil + else this drop lo take (until - lo) + } + override def takeRight(n: Int): List[A] = { @tailrec def loop(lead: List[A], lag: List[A]): List[A] = lead match { diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index dcba9a52a5..99929dd93c 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -43,8 +43,7 @@ abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] with CustomParalleliza repr.getClass.getComponentType.getComponentType.asInstanceOf[Predef.Class[U]])) override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) { - var l = len - if (repr.length < l) l = repr.length + var l = math.min(len, repr.length) if (xs.length - start < l) l = xs.length - start max 0 Array.copy(repr, 0, xs, start, l) } |