diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/matching')
3 files changed, 110 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala index 029ccadfa8..d072590d70 100644 --- a/src/compiler/scala/tools/nsc/matching/CodeFactory.scala +++ b/src/compiler/scala/tools/nsc/matching/CodeFactory.scala @@ -73,7 +73,7 @@ trait CodeFactory { Apply(Select(sel, ntpe.member(nme.lengthCompare)), List(Literal(Constant(i)))), Literal(Constant(0)) ) - ) + )/*defs.Seq_length ?*/ /** for tree of sequence type sel, returns boolean tree testing that length >= i */ @@ -81,12 +81,25 @@ trait CodeFactory { GreaterThanOrEquals( typer.typed(Apply(Select(sel, tpe.member(nme.lengthCompare)), List(Literal(Constant(i))))), typer.typed(Literal(Constant(0)))) + //defs.Seq_length instead of tpe.member ? - final def Not(arg:Tree) = - Select(arg, definitions.Boolean_not) + final def Not(arg:Tree) = arg match { + case Literal(Constant(true)) => Literal(Constant(false)) + case Literal(Constant(false)) => Literal(Constant(true)) + case t => Select(arg, definitions.Boolean_not) + } - def And(left: Tree, right: Tree): Tree = - Apply(Select(left, definitions.Boolean_and), List(right)) + def And(left: Tree, right: Tree): Tree = left match { + case Literal(Constant(value: Boolean)) => + if (value) right else left + case _ => + right match { + case Literal(Constant(true)) => + left + case _ => + Apply(Select(left, definitions.Boolean_and), List(right)) + } + } final def Equals(left: Tree, right: Tree): Tree = Apply(Select(left, nme.EQ), List(right)) @@ -115,4 +128,86 @@ trait CodeFactory { final def Get(tree : Tree) = Apply(Select(tree, nme.get), List()) + // statistics + var nremoved = 0 + var nsubstituted = 0 + + final def squeezedBlock(vds: List[Tree], exp: Tree)(implicit theOwner: Symbol): Tree = + if (settings_squeeze) + squeezedBlock1(vds, exp) + else + Block(vds,exp) + + final def squeezedBlock1(vds: List[Tree], exp: Tree)(implicit theOwner: Symbol): Tree = { + val tpe = exp.tpe + + class RefTraverser(sym: Symbol) extends Traverser { + var nref = 0 + var 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) => + var args1 = args; while(args1 ne Nil) { + if(args1.head.symbol eq sym) { + nref += 2 // will abort traversal, cannot substitute this one + args1 = Nil // break + } else { + args1 = args1.tail + } + } + traverse(rhs) + case t if nref > 1 => + // abort, no story to tell + case t => + super.traverse(t) + } + } + + 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 t if stop => + t + case t => + super.transform(t) + } + } + vds match { + case Nil => + exp + case (vd:ValDef) :: rest => + // recurse + val exp1 = squeezedBlock(rest, exp) + + val sym = vd.symbol + val rt = new RefTraverser(sym) + rt.atOwner (theOwner) (rt.traverse(exp1)) + rt.nref match { + case 0 => + nremoved += 1 + exp1 + case 1 if rt.nsafeRef == 1 => + nsubstituted += 1 + new Subst(sym, vd.rhs).transform(exp1) + case _ => + exp1 match { + case Block(vds2, exp2) => Block(vd::vds2, exp2) + case exp2 => Block(vd::Nil, exp2) + } + } + case x::xs => + squeezedBlock(xs, exp) match { + case Block(vds2, exp2) => Block(x::vds2, exp2) + case exp2 => Block(x::Nil, exp2) + } + } + } } + diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 32309e08d9..baa849d928 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -132,7 +132,7 @@ trait ParallelMatching { val typedElse = repToTree(guardedRest) val typedIf = typer.typed { If(guard.duplicate, body, typedElse) } - typer.typed { Block(vdefs, typedIf) } + typer.typed { squeezedBlock(vdefs, typedIf) } } } @@ -309,7 +309,7 @@ trait ParallelMatching { typer.typed{ mkIdent(uacall.symbol) } else emptynessCheck(uacall.symbol) - typer.typed { Block(List(rep.handleOuter(uacall)), If(cond,Block(vdefs,succ),fail)) } + typer.typed { squeezedBlock(List(rep.handleOuter(uacall)), If(cond,squeezedBlock(vdefs,succ),fail)) } } } @@ -372,7 +372,7 @@ trait ParallelMatching { // fixed length val cond = getCond(treeAsSeq, xs.length) return ({thenp:Tree => {elsep:Tree => - If(cond, Block(bindings, thenp), elsep)}}, succRep, failRep) + If(cond, squeezedBlock(bindings, thenp), elsep)}}, succRep, failRep) } // lengthArg is exact length @@ -588,7 +588,7 @@ trait ParallelMatching { if (casted ne this.scrutinee) vdefs = ValDef(casted, gen.mkAsInstanceOf(mkIdent(this.scrutinee), casted.tpe)) :: vdefs - return typer.typed( If(cond, Block(vdefs, succ), fail) ) + return typer.typed( If(cond, squeezedBlock(vdefs, succ), fail) ) } } @@ -646,7 +646,7 @@ trait ParallelMatching { override def transform(tree:Tree): Tree = tree match { case blck @ Block(vdefs, ld @ LabelDef(name,params,body)) => val bx = labelIndex(ld.symbol) - if (bx >= 0 && !isReachedTwice(bx)) Block(vdefs,body) + if (bx >= 0 && !isReachedTwice(bx)) squeezedBlock(vdefs,body) else blck case If(cond, Literal(Constant(true)), Literal(Constant(false))) => @@ -698,8 +698,8 @@ trait ParallelMatching { labels(bx) = label return body match { - case _: Throw | _: Literal => Block(vdefs, body.duplicate setType tpe) - case _ => Block(vdefs.reverse, LabelDef(label, vsyms, body setType tpe)) + case _: Throw | _: Literal => squeezedBlock(vdefs, body.duplicate setType tpe) + case _ => squeezedBlock(vdefs.reverse, LabelDef(label, vsyms, body setType tpe)) } } @@ -724,7 +724,7 @@ trait ParallelMatching { body match { case _: Throw | _: Literal => // might be bound elsewhere (see `x @ unapply') val vdefs = for (v <- vss(bx) ; val substv = subst(v) ; if substv ne null) yield typedValDef(v, substv) - Block(vdefs, body.duplicate setType resultType) + squeezedBlock(vdefs, body.duplicate setType resultType) case _ => Apply(mkIdent(label),args) } diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala index e96de6a0d5..2772cb5edb 100644 --- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala +++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala @@ -23,6 +23,7 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with Parall // cache these final val settings_debug = settings.debug.value + final val settings_squeeze = settings.Xsqueeze.value == "on" // check special case Seq(p1,...,pk,_*) protected def isRightIgnoring(p: ArrayValue): Boolean = { @@ -81,6 +82,7 @@ trait TransMatcher { self: transform.ExplicitOuter with PatternNodes with Parall val mch = typer.typed(repToTree(irep)) var dfatree = typer.typed(Block(vds, mch)) + // cannot use squeezedBlock because of side-effects, see t275 for ((cs, bx) <- cases.zipWithIndex) if (!rep.isReached(bx)) cunit.error(cs.body.pos, "unreachable code") |