summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-07-06 15:00:33 +0000
committerPaul Phillips <paulp@improving.org>2009-07-06 15:00:33 +0000
commit5c33f943d48c16bfd9dce77b9af4156fd7f33d35 (patch)
treebc74a05f0a04963d4aa95f08ef3cc600cfe59dc8
parent26bca73b09d29a7978acdda36d2f85478343f9f4 (diff)
downloadscala-5c33f943d48c16bfd9dce77b9af4156fd7f33d35.tar.gz
scala-5c33f943d48c16bfd9dce77b9af4156fd7f33d35.tar.bz2
scala-5c33f943d48c16bfd9dce77b9af4156fd7f33d35.zip
More naming and commenting, some moving to more...
More naming and commenting, some moving to more sensible locations, and removing unnecessary mutability.
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala30
-rw-r--r--src/compiler/scala/tools/nsc/matching/TransMatcher.scala95
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala132
3 files changed, 130 insertions, 127 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 1905cc31b5..6691dad894 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -167,13 +167,8 @@ trait ParallelMatching extends ast.TreeDSL {
case t =>
super.transform(t match {
+ // note - it is too early for any other true/false related optimizations
case If(cond, IsTrue(), IsFalse()) => cond
- // These definitely cause failure after locker!
- // case If(IsTrue(), thenp, _) => thenp
- // case If(IsFalse(), _, elsep) => elsep
- // We could do more here...
- // case If(cond, thenp, IsFalse()) =>
- // gen.mkAnd(cond, thenp)
case If(cond1, If(cond2, thenp, elsep1), elsep2) if (elsep1 equalsStructure elsep2) =>
IF (cond1 AND cond2) THEN thenp ELSE elsep1
@@ -183,8 +178,20 @@ trait ParallelMatching extends ast.TreeDSL {
})
}
}
+ object resetTraverser extends Traverser {
+ import Flags._
+ def reset(vd: ValDef) =
+ if (vd.symbol hasFlag SYNTHETIC) vd.symbol resetFlag (TRANS_FLAG|MUTABLE)
+
+ override def traverse(x: Tree): Unit = x match {
+ case vd: ValDef => reset(vd)
+ case _ => super.traverse(x)
+ }
+ }
+
val res = lxtt transform tree
cleanup()
+ resetTraverser traverse res
res
}
@@ -273,11 +280,6 @@ trait ParallelMatching extends ast.TreeDSL {
/** the injection here handles alternatives and unapply type tests */
final def make(temp: List[Symbol], row1: List[Row]): Rep = {
- // equals check: call singleType(NoPrefix, o.symbol) `stpe'. Then we could also return
- // `typeRef(definitions.ScalaPackageClass.tpe, definitions.EqualsPatternClass, List(stpe))'
- // and force an equality check. However, exhaustivity checking would not work anymore.
- // so first, extend exhaustivity check to equalspattern
-
// Martin: I am not really sure what stype is doing, but it caused aliases.scala to fail
// The problem is if a val has a singleType of some other module. Then isModule is true and
// sType is called. But it ends up mixing the prefix of the other module with the val symbol
@@ -1138,8 +1140,8 @@ trait ParallelMatching extends ast.TreeDSL {
private def pad(s: String): String = "%%%ds" format (NPAD - 1) format s
}
- /** Executes the match algorithm. */
- final def execute(roots: List[Symbol], cases: List[Tree]) = {
+ /** Expands the patterns recursively. */
+ final def expand(roots: List[Symbol], cases: List[Tree]) = {
val (rows, targets, vss): (List[Option[Row]], List[Tree], List[List[Symbol]]) = unzip3(
for ((CaseDef(pat, g, b), bx) <- cases.zipWithIndex) yield { // stash away pvars and bodies for later
@@ -1190,7 +1192,7 @@ trait ParallelMatching extends ast.TreeDSL {
}
/** adds a test comparing the dynamic outer to the static outer */
- final def addOuterCondition(cond: Tree, tpe2test: Type, scrut: Tree, handleOuter: Tree=>Tree) = {
+ final def addOuterCondition(cond: Tree, tpe2test: Type, scrut: Tree, handleOuter: TreeFunction1) = {
val theRef = handleOuter(tpe2test match {
case TypeRef(NoPrefix, _, _) => abort("assertion failed: NoPrefix")
case TypeRef(ThisType(clazz), _, _) => THIS(clazz)
diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
index c4c5cbf047..9c7878a229 100644
--- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
+++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
@@ -47,7 +47,6 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter {
import CODE._
var cunit: CompilationUnit = _ // memory leak?
- var resultType: Type = _
def newName(pos: Position, s: String) = cunit.fresh.newName(pos, s)
@@ -57,9 +56,10 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter {
* requires but which aren't essential to the algorithm itself.
*/
case class MatchMatrixContext(
- handleOuter: TreeFunction1,
- typer: Typer,
- owner: Symbol)
+ handleOuter: TreeFunction1, // Tree => Tree function
+ typer: Typer, // a local typer
+ owner: Symbol, // the current owner
+ resultType: Type) // the expected result type of the whole match
{
def newVar(
pos: Position,
@@ -143,67 +143,73 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter {
}
}
- /** handles all translation of pattern matching
+ case class MatchMatrixInput(
+ roots: List[Symbol],
+ vars: List[Tree],
+ default: Tree
+ )
+
+ /** Handles all translation of pattern matching.
*/
def handlePattern(
- selector: Tree,
- cases: List[CaseDef],
- doCheckExhaustive: Boolean,
- owner: Symbol,
- handleOuter: TreeFunction1,
- localTyper: Typer): Tree =
+ selector: Tree, // tree being matched upon (called scrutinee after this)
+ cases: List[CaseDef], // list of cases in the match
+ isChecked: Boolean, // whether exhaustiveness checking is enabled (disabled with @unchecked)
+ context: MatchMatrixContext): Tree =
{
- val flags = if (doCheckExhaustive) Nil else List(Flags.TRANS_FLAG)
- val context = MatchMatrixContext(handleOuter, localTyper, owner)
-
import context._
- def matchError(obj: Tree) = atPos(selector.pos)(THROW(MatchErrorClass, obj))
- def caseIsOk(c: CaseDef) = cond(c.pat) { case _: Apply | Ident(nme.WILDCARD) => true }
+ val flags = List(Flags.TRANS_FLAG) filterNot (_ => isChecked)
+ def matchError(obj: Tree) = atPos(selector.pos)(THROW(MatchErrorClass, obj))
+ def caseIsOk(c: CaseDef) = cond(c.pat) { case _: Apply | Ident(nme.WILDCARD) => true }
+ // this appears to be an attempt at optimizing when all case defs are constructor
+ // patterns, but I don't think it's correct.
def doApply(fn: Tree): Boolean =
(fn.symbol eq (selector.tpe.decls lookup nme.CONSTRUCTOR)) &&
(cases forall caseIsOk)
- def processTuple(app: Apply): (List[Symbol], List[Tree], Tree) = {
+ // For x match { ... we start with a single root
+ def singleMatch() = {
+ val root: Symbol = newVar(selector.pos, selector.tpe, flags)
+ val varDef: Tree = typedValDef(root, selector)
+
+ MatchMatrixInput(List(root), List(varDef), matchError(ID(root)))
+ }
+
+ // For (x, y, z) match { ... we start with multiple roots, called tpXX.
+ def tupleMatch(app: Apply) = {
val Apply(fn, args) = app
- val (tmps, vds) = List.unzip(
+ val (roots, vars) = List.unzip(
for ((arg, typeArg) <- args zip selector.tpe.typeArgs) yield {
val v = newVar(arg.pos, typeArg, flags, newName(arg.pos, "tp"))
(v, typedValDef(v, arg))
}
)
- (tmps, vds, matchError(treeCopy.Apply(app, fn, tmps map ID)))
+ MatchMatrixInput(roots, vars, matchError(treeCopy.Apply(app, fn, roots map ID)))
}
- // sets temporaries, variable declarations, and the fail tree
- val (tmps, vds, theFailTree) = selector match {
- case app @ Apply(fn, _) if isTupleType(selector.tpe) && doApply(fn) =>
- processTuple(app)
- case _ =>
- val root: Symbol = newVar(selector.pos, selector.tpe, flags)
- val vdef: Tree = typer typed (VAL(root) === selector)
- val failTree: Tree = matchError(ID(root))
- (List(root), List(vdef), failTree)
+ // sets up input for the matching algorithm
+ val MatchMatrixInput(roots, vars, default) = selector match {
+ case app @ Apply(fn, _) if isTupleType(selector.tpe) && doApply(fn) => tupleMatch(app)
+ case _ => singleMatch()
}
- val matrix = new MatchMatrix(context, theFailTree)
- val rep = matrix.execute(tmps, cases)
- val mch = typer typed rep.toTree
- var dfatree = typer typed Block(vds, mch)
+ val matrix = new MatchMatrix(context, default)
+ val rep = matrix.expand(roots, cases) // expands casedefs and assigns name
+ val mch = typer typed rep.toTree // executes algorithm, converts tree to DFA
+ val dfatree = typer typed Block(vars, mch) // packages into a code block
- // TRACE("handlePattern(\n tmps = %s\n cases = %s\n rep = %s\n initRep = %s\n)",
- // tmps, cases.mkString("(\n ", "\n ", "\n)"), rep, irep)
+ // TRACE("handlePattern(\n roots = %s\n cases = %s\n rep = %s\n initRep = %s\n)",
+ // roots, cases.mkString("(\n ", "\n ", "\n)"), rep, irep)
// TRACE("dfatree(1) = " + toCompactString(dfatree))
- // cannot use squeezedBlock because of side-effects, see t275
+ // redundancy check
for ((cs, bx) <- cases.zipWithIndex)
if (!matrix.isReached(bx)) cunit.error(cs.body.pos, "unreachable code")
- dfatree = matrix cleanup dfatree
- resetTraverser traverse dfatree
- // TRACE("dfatree(2) = " + toCompactString(dfatree))
- dfatree
+ // cleanup performs squeezing and resets any remaining TRANS_FLAGs
+ matrix cleanup dfatree
}
private def toCompactString(t: Tree): String = {
@@ -213,17 +219,6 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter {
printer.flush()
buffer.toString
}
-
- private object resetTraverser extends Traverser {
- override def traverse(x: Tree): Unit = x match {
- case vd: ValDef =>
- if (vd.symbol hasFlag Flags.SYNTHETIC) {
- vd.symbol resetFlag (Flags.TRANS_FLAG | Flags.MUTABLE)
- }
- case _ =>
- super.traverse(x)
- }
- }
}
/** A tree printer which is stingier about vertical whitespace and unnecessary
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index bd5e71d23c..f838de7fe5 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -338,6 +338,72 @@ abstract class ExplicitOuter extends InfoTransform
sym setFlag notFlag
}
+ def matchTranslation(tree: Match) = {
+ val Match(selector, cases) = tree
+ var nselector = transform(selector)
+
+ def makeGuardDef(vs: List[Symbol], guard: Tree) = {
+ val gdname = newName(guard.pos, "gd")
+ val method = currentOwner.newMethod(tree.pos, gdname) setFlag SYNTHETIC
+ val fmls = vs map (_.tpe)
+ val tpe = new MethodType(method newSyntheticValueParams fmls, BooleanClass.tpe)
+ method setInfo tpe
+
+ localTyper typed (DEF(method) === {
+ new ChangeOwnerTraverser(currentOwner, method) traverse guard
+ new TreeSymSubstituter(vs, method.paramss.head) traverse guard
+ guard
+ })
+ }
+
+ val nguard = new ListBuffer[Tree]
+ val ncases =
+ for (CaseDef(p, guard, b) <- cases) yield {
+ val gdcall =
+ if (guard == EmptyTree) EmptyTree
+ else {
+ val vs = definedVars(p)
+ val guardDef = makeGuardDef(vs, guard)
+ nguard += transform(guardDef) // building up list of guards
+
+ localTyper typed (Ident(guardDef.symbol) APPLY (vs map Ident))
+ }
+
+ (CASE(transform(p)) IF gdcall) ==> transform(b)
+ }
+
+ def isUncheckedAnnotation(tpe: Type) = tpe hasAnnotation UncheckedClass
+ def isSwitchAnnotation(tpe: Type) = tpe hasAnnotation SwitchClass
+
+ val (checkExhaustive, requireSwitch) = nselector match {
+ case Typed(nselector1, tpt) =>
+ val unchecked = isUncheckedAnnotation(tpt.tpe)
+ if (unchecked)
+ nselector = nselector1
+
+ (!unchecked, isSwitchAnnotation(tpt.tpe))
+ case _ =>
+ (true, false)
+ }
+
+ val t = atPos(tree.pos) {
+ val context = MatchMatrixContext(transform, localTyper, currentOwner, tree.tpe)
+ val t_untyped = handlePattern(nselector, ncases, checkExhaustive, context)
+
+ /* if @switch annotation is present, verify the resulting tree is a Match */
+ if (requireSwitch) t_untyped match {
+ case Block(_, Match(_, _)) => // ok
+ case _ =>
+ unit.error(tree.pos, "could not emit switch for @switch annotated match")
+ }
+
+ localTyper.typed(t_untyped, context.resultType)
+ }
+
+ if (nguard.isEmpty) t
+ else Block(nguard.toList, t) setType t.tpe
+ }
+
/** The main transformation method */
override def transform(tree: Tree): Tree = {
val sym = tree.symbol
@@ -409,69 +475,9 @@ abstract class ExplicitOuter extends InfoTransform
}
super.transform(treeCopy.Apply(tree, sel, outerVal :: args))
- case mch @ Match(selector, cases) => // <----- transmatch hook
- var nselector = transform(selector)
-
- def makeGuardDef(vs: List[Symbol], guard: Tree) = {
- val gdname = newName(guard.pos, "gd")
- val method = currentOwner.newMethod(mch.pos, gdname) setFlag SYNTHETIC
- val fmls = vs map (_.tpe)
- val tpe = new MethodType(method newSyntheticValueParams fmls, BooleanClass.tpe)
- method setInfo tpe
-
- localTyper typed (DEF(method) === {
- new ChangeOwnerTraverser(currentOwner, method) traverse guard
- new TreeSymSubstituter(vs, method.paramss.head) traverse guard
- guard
- })
- }
-
- val nguard = new ListBuffer[Tree]
- val ncases =
- for (CaseDef(p, guard, b) <- cases) yield {
- val gdcall =
- if (guard == EmptyTree) EmptyTree
- else {
- val vs = definedVars(p)
- val guardDef = makeGuardDef(vs, guard)
- nguard += transform(guardDef) // building up list of guards
-
- localTyper typed (Ident(guardDef.symbol) APPLY (vs map Ident))
- }
-
- (CASE(transform(p)) IF gdcall) ==> transform(b)
- }
-
- def isUncheckedAnnotation(tpe: Type) = tpe hasAnnotation UncheckedClass
- def isSwitchAnnotation(tpe: Type) = tpe hasAnnotation SwitchClass
-
- val (checkExhaustive, requireSwitch) = nselector match {
- case Typed(nselector1, tpt) =>
- val unchecked = isUncheckedAnnotation(tpt.tpe)
- if (unchecked)
- nselector = nselector1
-
- (!unchecked, isSwitchAnnotation(tpt.tpe))
- case _ =>
- (true, false)
- }
-
- ExplicitOuter.this.resultType = tree.tpe
-
- val t = atPos(tree.pos) {
- val t_untyped = handlePattern(nselector, ncases, checkExhaustive, currentOwner, transform, localTyper)
- /* if @switch annotation is present, verify the resulting tree is a Match */
- if (requireSwitch) t_untyped match {
- case Block(_, Match(_, _)) => // ok
- case _ =>
- unit.error(tree.pos, "could not emit switch for @switch annotated match")
- }
-
- localTyper.typed(t_untyped, resultType)
- }
-
- if (nguard.isEmpty) t
- else Block(nguard.toList, t) setType t.tpe
+ // TransMatch hook
+ case mch: Match =>
+ matchTranslation(mch)
case _ =>
val x = super.transform(tree)