summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-09-30 16:38:06 +0000
committerPaul Phillips <paulp@improving.org>2009-09-30 16:38:06 +0000
commit4f62a386bbea074d39cf03967a76c1538a7c343d (patch)
tree337f6289d654eac9360dcf5cb7c7ec85bca6daf4
parent5aa7e892bb693ba80cd372e46bdc6e9719d1bb82 (diff)
downloadscala-4f62a386bbea074d39cf03967a76c1538a7c343d.tar.gz
scala-4f62a386bbea074d39cf03967a76c1538a7c343d.tar.bz2
scala-4f62a386bbea074d39cf03967a76c1538a7c343d.zip
Yet further encapsulation in the pattern matcher.
Added -Ypmat-debug setting.
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala11
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala93
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala15
-rw-r--r--src/compiler/scala/tools/nsc/matching/TransMatcher.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
6 files changed, 69 insertions, 57 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index a7be8ae13e..45bd7ed770 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -829,6 +829,7 @@ trait ScalacSettings {
val Yrangepos = BooleanSetting ("-Yrangepos", "Use range positions for syntax trees.")
val Yidedebug = BooleanSetting ("-Yide-debug", "Generate, validate and output trees using the interactive compiler.")
val Ytyperdebug = BooleanSetting ("-Ytyper-debug", "Trace all type assignements")
+ val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
/**
* -P "Plugin" settings
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 7b56a31e97..c932b7cfb3 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -26,9 +26,8 @@ trait TreeDSL {
type BooleanTreeFunction2 = (Tree, Tree) => Boolean
// Add a null check to a Tree => Tree function
- // (this assumes your result Tree is representing a Boolean expression)
- def nullSafe[T](f: TreeFunction1): TreeFunction1 =
- tree => (tree OBJ_!= NULL) AND f(tree)
+ def nullSafe[T](f: TreeFunction1, ifNull: Tree): TreeFunction1 =
+ tree => IF (tree MEMBER_== NULL) THEN ifNull ELSE f(tree)
// XXX these two are in scala.PartialFunction now, just have to
// settle on the final names.
@@ -62,8 +61,8 @@ trait TreeDSL {
// So it's inconsistent until I devise a better way.
val TRUE = LIT(true)
val FALSE = LIT(false)
- val NULL = LIT(null)
val ZERO = LIT(0)
+ def NULL = LIT(null)
def UNIT = LIT(())
object WILD {
@@ -142,6 +141,8 @@ trait TreeDSL {
def IS(tpe: Type) = gen.mkIsInstanceOf(target, tpe, true)
def IS_OBJ(tpe: Type) = gen.mkIsInstanceOf(target, tpe, false)
+ // XXX having some difficulty expressing nullSafe in a way that doesn't freak out value types
+ // def TOSTRING() = nullSafe(fn(_: Tree, nme.toString_), LIT("null"))(target)
def TOSTRING() = fn(target, nme.toString_)
def GETCLASS() = fn(target, Object_getClass)
}
@@ -198,7 +199,7 @@ trait TreeDSL {
/** Top level accessible. */
def THROW(sym: Symbol, msg: Tree = null) = {
- val arg = if (msg == null) Nil else List(msg.TOSTRING)
+ val arg: List[Tree] = if (msg == null) Nil else List(msg.TOSTRING())
Throw(New(TypeTree(sym.tpe), List(arg)))
}
def NEW(tpe: Tree, args: Tree*) = New(tpe, List(args.toList))
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 0f72778bc3..ba96e8f872 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -13,6 +13,7 @@ import collection._
import mutable.BitSet
import immutable.IntMap
import MatchUtil._
+import annotation.elidable
/** Translation of match expressions.
*
@@ -38,9 +39,6 @@ import MatchUtil._
trait ParallelMatching extends ast.TreeDSL {
self: transform.ExplicitOuter with PatternNodes =>
- // debugging var, set to true to see how sausages are made
- private var trace = false
-
import global.{ typer => _, _ }
import definitions.{ AnyRefClass, EqualsPatternClass, IntClass, getProductArgs, productProj }
import symtab.Flags
@@ -51,10 +49,15 @@ trait ParallelMatching extends ast.TreeDSL {
// XXX temp
def toPats(xs: List[Tree]): List[Pattern] = xs map (x => Pattern(x))
+ // debugging val, set to true with -Ypmat-debug
+ private final def trace = settings.Ypmatdebug.value
+
def ifDebug(body: => Unit): Unit = { if (settings.debug.value) body }
def DBG(msg: => String): Unit = { ifDebug(println(msg)) }
+ @elidable(elidable.FINE)
def TRACE(f: String, xs: Any*): Unit = { if (trace) println(if (xs.isEmpty) f else f.format(xs : _*)) }
+
def logAndReturn[T](s: String, x: T): T = { log(s + x.toString) ; x }
def traceAndReturn[T](s: String, x: T): T = { TRACE(s + x.toString) ; x }
@@ -62,8 +65,6 @@ trait ParallelMatching extends ast.TreeDSL {
def isDefaultPattern(t: Tree) = cond(unbind(t)) { case EmptyTree | WILD() => true }
def isStar(t: Tree) = cond(unbind(t)) { case Star(q) => isDefaultPattern(q) }
def isRightIgnoring(t: Tree) = cond(unbind(t)) { case ArrayValue(_, xs) if !xs.isEmpty => isStar(xs.last) }
- def isLabellable(t: Tree) = !cond(t) { case _: Throw | _: Literal => true }
- def isModule(t: Tree) = t.symbol.isModule || t.tpe.termSymbol.isModule
// If the given pattern contains alternatives, return it as a list of patterns.
// Makes typed copies of any bindings found so all alternatives point to final state.
@@ -219,46 +220,17 @@ trait ParallelMatching extends ast.TreeDSL {
* the function takes care of binding
*/
final def requestBody(bx: Int, subst: Bindings): Tree = {
- val target = targets(bx)
- lazy val FinalState(bindings, body, freeVars) = target
+ implicit val ctx = context
+ lazy val target @ FinalState(bindings, body, freeVars) = targets(bx)
+ lazy val substInfo = subst infoFor freeVars
+ import substInfo._
// shortcut
- def labelJump: Tree = Apply(ID(shortCuts(-bx-1)), Nil)
-
- // first time this bx is requested
- def firstTime: Tree = {
- // might be bound elsewhere
- val (vsyms, vdefs) : (List[Symbol], List[Tree]) = List.unzip(
- for (v <- freeVars ; substv <- subst(v)) yield
- (v, typedValDef(v, substv))
- )
-
- // @bug: typer is not able to digest a body of type Nothing being assigned result type Unit
- val tpe = if (body.tpe.isNothing) body.tpe else resultType
- target.setLabel(owner.newLabel(body.pos, "body%"+bx) setInfo MethodType(vsyms, tpe))
-
- squeezedBlock(vdefs, (
- if (isLabellable(body)) LabelDef(target.label, vsyms, body setType tpe)
- else body.duplicate setType tpe
- ))
- }
-
- def successiveTimes: Tree = {
- val args = freeVars map subst flatten
- val fmls = target.label.tpe.paramTypes
- def vds = for (v <- freeVars ; substv <- subst(v)) yield typedValDef(v, substv)
-
- if (isLabellable(body)) ID(target.label) APPLY (args)
- else squeezedBlock(vds, body.duplicate setType resultType)
- }
-
- if (bx < 0) labelJump
- else {
- target.incrementReached
-
- if (target.isReachedOnce) firstTime
- else successiveTimes
- }
+ if (bx < 0) Apply(ID(shortCuts(-bx-1)), Nil)
+ // first time this bx is requested - might be bound elsewhere
+ else if (target.isNotReached) target.createLabelBody("body%"+bx, vsyms, vdefs)
+ // call label "method" if possible
+ else target.getLabelBody(idents, vdefs)
}
/** the injection here handles alternatives and unapply type tests */
@@ -285,18 +257,17 @@ trait ParallelMatching extends ast.TreeDSL {
if (tvars(j).tpe <:< arg.tpe) ua
else Typed(ua, TypeTree(arg.tpe)) setType arg.tpe
)
-
- // TRACE("doUnapplyApply: %s <:< %s == %s", tvars(j).tpe, argtpe, (tvars(j).tpe <:< argtpe))
- logAndReturn("doUnapplyApply: ", rebind(npat) setType arg.tpe)
+ rebind(npat) setType arg.tpe
}
def doValMatch(x: Tree, fn: Tree) = {
+ def isModule = x.symbol.isModule || x.tpe.termSymbol.isModule
def examinePrefix(path: Tree) = (path, path.tpe) match {
case (_, t: ThisType) => singleType(t, x.symbol) // cases 2/3 are e.g. `case Some(p._2)' in s.c.jcl.Map
case (_: Apply, _) => PseudoType(x) // outer-matching: test/files/pos/t154.scala
case _ => singleType(Pattern(path).mkSingleton, x.symbol) // old
}
val singletonType =
- if (isModule(x)) Pattern(x).mkSingleton else fn match {
+ if (isModule) Pattern(x).mkSingleton else fn match {
case Select(path, _) => examinePrefix(path)
case x: Ident => equalsCheck(x)
}
@@ -805,7 +776,7 @@ trait ParallelMatching extends ast.TreeDSL {
def compareOp = head.tpe member nme.lengthCompare // symbol for "lengthCompare" method
def cmpFunction(t1: Tree) = op((t1.duplicate DOT compareOp)(LIT(len)), ZERO)
// first ascertain lhs is not null: bug #2241
- typer typed nullSafe(cmpFunction _)(tree)
+ typer typed nullSafe(cmpFunction _, FALSE)(tree)
}
// precondition for matching: sequence is exactly length of arg
@@ -1073,11 +1044,35 @@ trait ParallelMatching extends ast.TreeDSL {
case class FinalState(bindings: Bindings, body: Tree, freeVars: List[Symbol]) extends State {
private var referenceCount = 0
private var _label: Symbol = null
- def incrementReached: Unit = { referenceCount += 1 }
def setLabel(s: Symbol): Unit = { _label = s }
def label = _label
+ // arguments to pass to this body%xx
+ def labelParamTypes = label.tpe.paramTypes
+
+ def createLabelBody(name: String, args: List[Symbol], vdefs: List[Tree]) = {
+ require(_label == null)
+ _label = owner.newLabel(body.pos, name) setInfo MethodType(args, tpe)
+ referenceCount += 1
+
+ squeezedBlock(vdefs,
+ if (isLabellable) LabelDef(label, args, body setType tpe)
+ else duplicate
+ )
+ }
+
+ def getLabelBody(idents: List[Tree], vdefs: List[Tree]): Tree = {
+ referenceCount += 1
+ if (isLabellable) ID(label) APPLY (idents)
+ else squeezedBlock(vdefs, duplicate)
+ }
+
+ // @bug: typer is not able to digest a body of type Nothing being assigned result type Unit
+ def tpe = if (body.tpe.isNothing) body.tpe else matchResultType
+ def duplicate = body.duplicate setType tpe
+
def isFinal = true
+ def isLabellable = !cond(body) { case _: Throw | _: Literal => true }
def isNotReached = referenceCount == 0
def isReachedOnce = referenceCount == 1
def isReachedTwice = referenceCount > 1
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index add3f44076..50bf8db756 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -247,11 +247,26 @@ trait PatternNodes extends ast.TreeDSL
override def toString() = "%s: %s @ %s: %s".format(pvar.name, pvar.tpe, tvar.name, tvar.tpe)
}
+ case class BindingsInfo(xs: List[BindingInfo]) {
+ def idents = xs map (_.ident)
+ def vsyms = xs map (_.vsym)
+
+ def vdefs(implicit context: MatchMatrixContext) =
+ xs map (x => context.typedValDef(x.vsym, x.ident))
+ }
+ case class BindingInfo(vsym: Symbol, ident: Ident)
+
case class Bindings(bindings: Binding*) extends Function1[Symbol, Option[Ident]] {
private def castIfNeeded(pvar: Symbol, tvar: Symbol) =
if (tvar.tpe <:< pvar.tpe) ID(tvar)
else ID(tvar) AS_ANY pvar.tpe
+ // filters the given list down to those defined in these bindings
+ def infoFor(vs: List[Symbol]): BindingsInfo = BindingsInfo(
+ for (v <- vs ; substv <- apply(v)) yield
+ BindingInfo(v, substv)
+ )
+
def add(vs: Iterable[Symbol], tvar: Symbol): Bindings = {
def newBinding(v: Symbol) = {
// see bug #1843 for the consequences of not setting info.
diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
index 78896846a4..02124c2041 100644
--- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
+++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
@@ -14,7 +14,7 @@
* Types which must be decomposed into conditionals and simple types:
*
* 2 Typed x: Int
- * 4 Stable Identifier Bob
+ * 4 Stable Identifier Bob or `x`
* 5 Constructor Symbol("abc")
* 6 Tuple (5, 5)
* 7 Extractor List(1, 2)
@@ -60,7 +60,7 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter {
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
+ matchResultType: Type) // the expected result type of the whole match
{
def newVar(
pos: Position,
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 8636866c52..c30f6fc5fb 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -396,7 +396,7 @@ abstract class ExplicitOuter extends InfoTransform
unit.error(tree.pos, "could not emit switch for @switch annotated match")
}
- localTyper.typed(t_untyped, context.resultType)
+ localTyper.typed(t_untyped, context.matchResultType)
}
if (nguard.isEmpty) t