summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-10-02 16:16:57 +0000
committerPaul Phillips <paulp@improving.org>2009-10-02 16:16:57 +0000
commit154cad734b72b8577c3dbea6a5ef05cd5ba8a550 (patch)
tree9f70d6a4e4d3c5e5c9787312e55ed2702cea434c
parent321338da04a6ca9bcc9b77ae663ed27f26a67d85 (diff)
downloadscala-154cad734b72b8577c3dbea6a5ef05cd5ba8a550.tar.gz
scala-154cad734b72b8577c3dbea6a5ef05cd5ba8a550.tar.bz2
scala-154cad734b72b8577c3dbea6a5ef05cd5ba8a550.zip
Bit by bit, the ad hoc tests and transformation...
Bit by bit, the ad hoc tests and transformations on Trees will make their way into a Pattern subclass specifically designed for the intended semantics.
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala45
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternBindings.scala12
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala3
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala51
-rw-r--r--src/compiler/scala/tools/nsc/matching/TransMatcher.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala1
6 files changed, 75 insertions, 41 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index d06bfcf575..9fc2ecb379 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -78,9 +78,9 @@ trait ParallelMatching extends ast.TreeDSL
class MatchMatrix(val context: MatrixContext, data: MatrixInit) extends MatchMatrixOptimizer {
import context._
- val MatrixInit(roots, cases, failTree) = data
- val ExpandedMatrix(rows, targets) = expand(roots, cases)
- val expansion: Rep = make(roots, rows)
+ val MatrixInit(roots, cases, failTree) = data
+ val ExpandedMatrix(rows, targets) = expand(roots, cases)
+ val expansion: Rep = make(roots, rows)
val shortCuts = new ListBuffer[Symbol]()
@@ -108,51 +108,44 @@ trait ParallelMatching extends ast.TreeDSL
/** the injection here handles alternatives and unapply type tests */
final def make(tvars: List[Symbol], row1: List[Row]): Rep = {
- def equalsCheck(x: Tree) =
- if (x.symbol.isValue) singleType(NoPrefix, x.symbol)
- else Pattern(x).mkSingleton
-
def classifyPat(opat: Pattern, j: Int): Pattern = {
- def vars = opat.boundVariables
- def rebind(t: Pattern) = Pattern(makeBind(vars, t.boundTree))
- def rebindEmpty(tpe: Type) = Pattern(mkEmptyTreeBind(vars, tpe))
- def rebindTyped() = Pattern(mkTypedBind(vars, equalsCheck(opat.tree)))
-
// @pre for doUnapplySeq: is not right-ignoring (no star pattern) ; no exhaustivity check
def doUnapplySeq(tptArg: Tree, xs: List[Tree]) = {
tvars(j) setFlag Flags.TRANS_FLAG
- rebind(Pattern(normalizedListPattern(xs, tptArg.tpe)))
+
+ opat rebindTo normalizedListPattern(xs, tptArg.tpe)
}
def doUnapplyApply(ua: UnApply, fn: Tree) = {
val MethodType(List(arg, _*), _) = fn.tpe
- val npat = Pattern(
+ val npat =
if (tvars(j).tpe <:< arg.tpe) ua
else Typed(ua, TypeTree(arg.tpe)) setType arg.tpe
- )
- rebind(npat) setType arg.tpe
+
+ opat rebindTo npat
}
def doValMatch(x: Tree, fn: Tree) = {
- def isModule = x.symbol.isModule || x.tpe.termSymbol.isModule
+ val p = Pattern(x)
+
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) Pattern(x).mkSingleton else fn match {
+ if (p.isModule) p.mkSingleton else fn match {
case Select(path, _) => examinePrefix(path)
- case x: Ident => equalsCheck(x)
+ case x: Ident => Pattern(fn).equalsCheck
}
- val typeToTest = mkEqualsRef(List(singletonType))
+ val typeToTest = mkEqualsRef(singletonType)
- rebind(Pattern(Typed(WILD(typeToTest), TypeTree(singletonType)) setType typeToTest))
+ val t = Typed(WILD(typeToTest), TypeTree(singletonType)) setType typeToTest
+ opat rebindTo t
}
def doReturnOriginal(t: Tree) = cond(t) {
case EmptyTree | WILD() | _: Literal | _: Typed | _: ArrayValue => true
}
- def doRebindTyped(t: Tree) = cond(t) { case _: Ident | _: Select => true }
// NOTE - this seemingly pointless representation has a point. Until extractors
// can be trusted, I only feel safe using them by using one to a match, because it is
@@ -160,15 +153,15 @@ trait ParallelMatching extends ast.TreeDSL
// pattern match before the final curtain falls.
val f = List[PartialFunction[Tree, Pattern]](
{ case _: Alternative => opat } ,
- { case Typed(p @ Stripped(_: UnApply), tpt) => if (tvars(j).tpe <:< tpt.tpe) rebind(Pattern(p)) else opat } ,
+ { case Typed(p @ Stripped(_: UnApply), tpt) => if (tvars(j).tpe <:< tpt.tpe) opat rebindTo p else opat } ,
{ case x if doReturnOriginal(x) => opat } ,
- { case x if doRebindTyped(x) => rebindTyped() } , // Ident(_) != nme.WILDCARD
+ { case _: Ident | _: Select => opat.rebindToEqualsCheck() } ,
{ case _: This => opat } ,
{ case UnapplySeq(tptArg, xs) => doUnapplySeq(tptArg, xs) } ,
{ case ua @ UnApply(Apply(fn, _), _) => doUnapplyApply(ua, fn) } ,
{ case x @ Apply_Function(fn) => doValMatch(x, fn) } ,
- { case Apply_Value(pre, sym) => rebindEmpty(mkEqualsRef(List(singleType(pre, sym)))) } ,
- { case Apply_CaseClass(tpe, args) => if (args.isEmpty) rebindEmpty(tpe) else opat } ,
+ { case Apply_Value(pre, sym) => opat rebindToEmpty mkEqualsRef(singleType(pre, sym)) } ,
+ { case Apply_CaseClass(tpe, args) => if (args.isEmpty) opat rebindToEmpty tpe else opat } ,
{ case x => abort("Unexpected pattern: " + x.getClass + " => " + x) }
) reduceLeft (_ orElse _)
diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
index 2f55ab3c2e..eeb8938b6a 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
@@ -16,6 +16,11 @@ trait PatternBindings extends ast.TreeDSL
import definitions.{ EqualsPatternClass }
import CODE._
+ /** EqualsPattern **/
+ def isEquals(tpe: Type) = cond(tpe) { case TypeRef(_, EqualsPatternClass, _) => true }
+ def mkEqualsRef(tpe: Type) = typeRef(NoPrefix, EqualsPatternClass, List(tpe))
+ def decodedEqualsType(tpe: Type) = condOpt(tpe) { case TypeRef(_, EqualsPatternClass, List(arg)) => arg } getOrElse (tpe)
+
// 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.
def extractBindings(p: Tree, prevBindings: Tree => Tree = identity[Tree] _): List[Tree] = {
@@ -32,13 +37,6 @@ trait PatternBindings extends ast.TreeDSL
case x :: xs => Bind(x, makeBind(xs, pat)) setType pat.tpe
}
- private def mkBind(vs: List[Symbol], tpe: Type, arg: Tree) =
- makeBind(vs, Typed(arg, TypeTree(tpe)) setType tpe)
-
- def mkTypedBind(vs: List[Symbol], tpe: Type) = mkBind(vs, tpe, WILD(tpe))
- def mkEmptyTreeBind(vs: List[Symbol], tpe: Type) = mkBind(vs, tpe, EmptyTree)
- def mkEqualsRef(xs: List[Type]) = typeRef(NoPrefix, EqualsPatternClass, xs)
-
case class Binding(pvar: Symbol, tvar: Symbol) {
override def toString() = "%s: %s @ %s: %s".format(pvar.name, pvar.tpe, tvar.name, tvar.tpe)
}
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index 7b866125a1..19baaab00a 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -26,7 +26,6 @@ trait PatternNodes extends ast.TreeDSL
type TypeComparison = (Type, Type) => Boolean
// Tests on Types
- def isEquals(t: Type) = cond(t) { case TypeRef(_, EqualsPatternClass, _) => true }
def isAnyRef(t: Type) = t <:< AnyRefClass.tpe
def isCaseClass(t: Type) = t.typeSymbol hasFlag Flags.CASE
@@ -41,8 +40,6 @@ trait PatternNodes extends ast.TreeDSL
// def isSubType: TypeComparison = (t1, t2) => isSubClass(t1, t2) && (t1 <:< t2)
// def isPatMatch: TypeComparison = (t1, t2) => isSubType(t1, t2)
- def decodedEqualsType(tpe: Type) =
- condOpt(tpe) { case TypeRef(_, EqualsPatternClass, List(arg)) => arg } getOrElse (tpe)
// If we write isSubtypeOf like:
//
diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala
index f6f84bd380..caa6dbf696 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -64,6 +64,8 @@ trait Patterns extends ast.TreeDSL {
// 8.1.4
case class StableIdPattern(tree: Ident) extends Pattern { }
+ // 8.1.4 (b)
+
// 8.1.5
case class ConstructorPattern(tree: Apply) extends ApplyPattern {
// XXX todo
@@ -77,19 +79,30 @@ trait Patterns extends ast.TreeDSL {
}
// 8.1.7
- case class ExtractorPattern(tree: UnApply) extends Pattern { }
+ case class ExtractorPattern(tree: UnApply) extends Pattern {
+ private val UnApply(Apply(fn, _), args) = tree
+ private val MethodType(List(arg, _*), _) = fn.tpe
+
+ def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe
+ }
// 8.1.8
case class SequencePattern(tree: ArrayValue) extends Pattern { }
// 8.1.8 (b)
- case class SequenceStarPattern(tree: ArrayValue) extends Pattern { }
+ case class SequenceStarPattern(tree: ArrayValue) extends Pattern {
+ // def removeStar(xs: List[Pattern]): List[Pattern] =
+ // xs.init ::: List(Pattern(makeBind(xs.last.boundVariables, WILD(scrut.seqType))))
+ }
// 8.1.9
// InfixPattern ... subsumed by Constructor/Extractor Patterns
// 8.1.10
- case class AlternativePattern(tree: Alternative, subpatterns: Seq[Pattern]) extends Pattern { }
+ case class AlternativePattern(tree: Alternative) extends Pattern {
+ private val Alternative(subtrees) = tree
+ lazy val subpatterns = subtrees map Pattern.apply
+ }
// 8.1.11
// XMLPattern ... for now, subsumed by SequencePattern, but if we want
@@ -110,7 +123,7 @@ trait Patterns extends ast.TreeDSL {
def apply(tree: Tree): Pattern = tree match {
case x: Bind => apply(unbind(tree)) withBoundTree x
case EmptyTree | WILD() => WildcardPattern()
- case x @ Alternative(ps) => AlternativePattern(x, ps map apply)
+ case x @ Alternative(ps) => AlternativePattern(x)
case x: Apply => ApplyPattern(x)
case x: Typed => TypedPattern(x)
case x: Literal => LiteralPattern(x)
@@ -137,6 +150,7 @@ trait Patterns extends ast.TreeDSL {
//
// val newpat = Typed(EmptyTree, TypeTree(tpe)) setType tpe)
//
+ // This is also how Select(qual, name) is handled.
object ApplyPattern {
def apply(x: Apply): Pattern = {
val Apply(fn, args) = x
@@ -181,18 +195,47 @@ trait Patterns extends ast.TreeDSL {
}
lazy val boundVariables = strip(boundTree)
+ private def wrapBindings(vs: List[Symbol], pat: Tree): Tree = vs match {
+ case Nil => pat
+ case x :: xs => Bind(x, wrapBindings(xs, pat)) setType pat.tpe
+ }
+
+ // If a tree has bindings, boundTree looks something like
+ // Bind(v3, Bind(v2, Bind(v1, tree)))
+ // This takes the given tree and creates a new pattern
+ // using the same bindings.
+ def rebindTo(t: Tree): Pattern =
+ Pattern(wrapBindings(boundVariables, t))
+
+ // Wrap this pattern's bindings around (_: Type)
+ def rebindToType(tpe: Type): Pattern =
+ rebindTo(Typed(WILD(tpe), TypeTree(tpe)) setType tpe)
+
+ // Wrap them around _
+ def rebindToEmpty(tpe: Type): Pattern =
+ rebindTo(Typed(EmptyTree, TypeTree(tpe)) setType tpe)
+
+ // Wrap them around a singleton type for an EqualsPattern check.
+ def rebindToEqualsCheck(): Pattern =
+ rebindToType(equalsCheck)
+
def sym = tree.symbol
def tpe = tree.tpe
def prefix = tpe.prefix
def isEmpty = tree.isEmpty
def isSymValid = (sym != null) && (sym != NoSymbol)
+ def isModule = sym.isModule || tpe.termSymbol.isModule
def setType(tpe: Type): this.type = {
tree setType tpe
this
}
+ def equalsCheck =
+ if (sym.isValue) singleType(NoPrefix, sym)
+ else mkSingleton
+
def mkSingleton = tpe match {
case st: SingleType => st
case _ => singleType(prefix, sym)
diff --git a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
index 30e0a62efd..c6a61984bf 100644
--- a/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
+++ b/src/compiler/scala/tools/nsc/matching/TransMatcher.scala
@@ -27,7 +27,9 @@ trait TransMatcher extends ast.TreeDSL with CompactTreePrinter {
import symtab.Flags
import CODE._
- var cunit: CompilationUnit = _ // memory leak?
+ // cunit is set to the current unit in ExplicitOuter's transformUnit,
+ // and nulled out afterward to avoid leaking.
+ var cunit: CompilationUnit = _
def newName(pos: Position, s: String) = cunit.fresh.newName(pos, s)
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 905d41e9f9..9419bba23e 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -491,6 +491,7 @@ abstract class ExplicitOuter extends InfoTransform
override def transformUnit(unit: CompilationUnit) {
cunit = unit
atPhase(phase.next) { super.transformUnit(unit) }
+ cunit = null
}
}