summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-10-03 22:38:39 +0000
committerPaul Phillips <paulp@improving.org>2009-10-03 22:38:39 +0000
commit7fd3db89c8850ea332ba99cf311b5b60cd86c550 (patch)
treedc420edc53632a0023cba714660aec2aedc136f6
parent43dcd522f188429fe2cffb63525922ae56a51d4b (diff)
downloadscala-7fd3db89c8850ea332ba99cf311b5b60cd86c550.tar.gz
scala-7fd3db89c8850ea332ba99cf311b5b60cd86c550.tar.bz2
scala-7fd3db89c8850ea332ba99cf311b5b60cd86c550.zip
Reaping the spoils of patternization.
or obsolete code now that I'm gaining some confidence about what exists for a reason and what exists only because it once existed.
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala105
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternBindings.scala12
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternNodes.scala174
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala22
4 files changed, 109 insertions, 204 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 6d7e4e56a9..adeaf452fa 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -141,10 +141,10 @@ trait ParallelMatching extends ast.TreeDSL
lazy val headType = head.tree match {
case p @ (_:Ident | _:Select) => head.mkSingleton // should be singleton object
- case __UnApply(_,argtpe,_) => argtpe // ?? why argtpe?
+ case UnapplyParamType(x) => x
case _ => head.tpe
}
- def isCaseHead = isCaseClass(headType)
+ def isCaseHead = head.isCaseClass
def dummies = if (isCaseHead) getDummies(headType.typeSymbol.caseFieldAccessors.length) else Nil
def dummyPatterns = dummies map (x => Pattern(x))
@@ -153,11 +153,7 @@ trait ParallelMatching extends ast.TreeDSL
def zip[T](others: List[T]) = trees zip others
def pzip[T](others: List[T]) = ps zip others
- /** returns true if pattern tests an object */
- def isObjectTest(pat: Pattern) =
- pat.isSymValid && pat.prefix.isStable && (headType =:= pat.mkSingleton)
-
- def extractSimpleSwitch(): Option[(List[Tree], Option[Tree])] = {
+ def extractSimpleSwitch(): Option[(List[Tree], Option[Pattern])] = {
def isSwitchableTag(tag: Int) = cond(tag) { case ByteTag | ShortTag | IntTag | CharTag => true }
def isSwitchableConst(t: Tree) = cond(unbind(t)) { case Literal(x: Constant) => isSwitchableTag(x.tag) }
def isSwitchableDefault(x: Tree) = isSwitchableConst(x) || isDefaultPattern(x)
@@ -166,7 +162,7 @@ trait ParallelMatching extends ast.TreeDSL
others match {
case Nil => Some((lits, None))
// TODO: This needs to also allow the case that the last is a compatible type pattern.
- case List(x) if isSwitchableDefault(x) => Some((lits, Some(x)))
+ case List(x) if isSwitchableDefault(x) => Some((lits, Some(Pattern(x))))
case _ => None
}
}
@@ -174,7 +170,7 @@ trait ParallelMatching extends ast.TreeDSL
// Any unapply - returns Some(true) if a type test is needed before the unapply can
// be called (e.g. def unapply(x: Foo) = { ... } but our scrutinee is type Any.)
object AnyUnapply {
- def unapply(x: Tree): Option[Boolean] = condOpt(x) { case __UnApply(_,tpe,_) => !(scrut.tpe <:< tpe) }
+ def unapply(x: Tree): Option[Boolean] = condOpt(x) { case UnapplyParamType(tpe) => !(scrut.tpe <:< tpe) }
}
object SimpleSwitch {
@@ -276,7 +272,7 @@ trait ParallelMatching extends ast.TreeDSL
val pats: Patterns,
val rest: Rep,
literals: List[Tree],
- defaultPattern: Option[Tree])
+ defaultPattern: Option[Pattern])
extends RuleApplication
{
private object NUM {
@@ -284,8 +280,8 @@ trait ParallelMatching extends ast.TreeDSL
}
// bound vars and rows for default pattern (only one row, but a list is easier to use later)
val (defaultVars, defaultRows) = defaultPattern match {
- case None => (Nil, Nil)
- case Some(Strip(vs, p)) => (vs, List((rest rows literals.size).rebind2(vs, scrut.sym)))
+ case None => (Nil, Nil)
+ case Some(Pattern(_, vs)) => (vs, List((rest rows literals.size).rebind2(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.
@@ -357,7 +353,10 @@ trait ParallelMatching extends ast.TreeDSL
object sameUnapplyCall {
private def sameFunction(fn1: Tree) = fxn.symbol == fn1.symbol && (fxn equalsStructure fn1)
- def unapply(t: Tree) = condOpt(t) { case UnApply(Apply(fn1, _), args) if sameFunction(fn1) => args }
+
+ def unapply(p: Pattern) = condOpt(p) {
+ case Pattern(UnApply(Apply(fn1, _), args), _) if sameFunction(fn1) => args
+ }
}
def newVarCapture(pos: Position, tpe: Type) =
@@ -367,10 +366,10 @@ trait ParallelMatching extends ast.TreeDSL
final def getTransition(): Branch[UnapplyCall] = {
val unapplyRes = newVarCapture(ua.pos, app.tpe)
val rhs = Apply(fxn, scrut.id :: trailingArgs) setType unapplyRes.tpe
- val zipped = pats zip rest.rows
+ val zipped = pats pzip rest.rows
val nrowsOther = zipped.tail flatMap {
- case (Stripped(sameUnapplyCall(_)), _) => Nil
- case (pat, r) => List(r insert Pattern(pat))
+ case (sameUnapplyCall(_), _) => Nil
+ case (pat, r) => List(r insert pat)
}
def mkTransition(vdefs: List[Tree], ntemps: List[Symbol], nrows: List[Row]) =
@@ -382,9 +381,9 @@ trait ParallelMatching extends ast.TreeDSL
// Second argument is number of dummies to prepend in the default case
def mkNewRows(sameFilter: (List[Tree]) => List[Tree], dum: Int) =
- for ((pat @ Strip(vs, p), r) <- zipped) yield p match {
- case sameUnapplyCall(args) => r.insert2(toPats(sameFilter(args)) ::: List(NoPattern), vs, scrut.sym)
- case _ => r insert (emptyPatterns(dum) ::: List(Pattern(pat)))
+ for ((pat, r) <- zipped) yield pat match {
+ case sameUnapplyCall(args) => r.insert2(toPats(sameFilter(args)) ::: List(NoPattern), pat.boundVariables, scrut.sym)
+ case _ => r insert (emptyPatterns(dum) ::: List(pat))
}
def mkGet(s: Symbol) = typedValDef(s, fn(ID(unapplyRes), nme.get))
def mkVar(tpe: Type) = newVarCapture(ua.pos, tpe)
@@ -600,6 +599,7 @@ trait ParallelMatching extends ast.TreeDSL
private def matches(arg1: Type, arg2: Type) = {
val List(t1, t2) = List(arg1, arg2) map decodedEqualsType
def eqSymbols = t1.typeSymbol eq t2.typeSymbol
+ // note: writing this as "t1.baseTypeSeq exists (_ =:= t2)" does not lead to 1434 passing.
def isSubtype = t1.baseTypeSeq exists (_.typeSymbol eq t2.typeSymbol)
(t1 <:< t2) || ((t1, t2) match {
@@ -619,14 +619,14 @@ trait ParallelMatching extends ast.TreeDSL
def eqHead(tpe: Type) = pats.headType =:= tpe
def alts(yes: Tree, no: Tree) = if (eqHead(pat.tpe)) yes else no
+ def isObjectTest = pattern.isObject && eqHead(pattern.mkSingleton)
- def isDef = pattern.isDefault
lazy val dummy = (j, pats.dummies)
- lazy val pass = (j, pat)
- lazy val subs = (j, pattern.subpatterns(pats) map (_.boundTree))
+ lazy val pass = (j, pattern.boundTree)
+ lazy val subs = (j, (pattern subpatterns pats) map (_.boundTree))
- // scrutinee, pattern
- val (s, p) = (spat.tpe, pats.headType)
+ // scrutinee, head of pattern group
+ val (s, p) = (pattern.tpe, pats.headType)
def sMatchesP = matches(s, p)
def pMatchesS = matches(p, s)
@@ -634,16 +634,24 @@ trait ParallelMatching extends ast.TreeDSL
// each pattern will yield a triple of options corresponding to the three lists,
// which will be flattened down to the values
implicit def mkOpt[T](x: T): Option[T] = Some(x) // limits noise from Some(value)
- (spat match {
- case LIT(null) if !eqHead(spat.tpe) => (None, None, pass) // special case for constant null
- case _ if pats.isObjectTest(pattern) => (EmptyTree, dummy, None) // matching an object
- case Typed(pp @ Stripped(_: UnApply), _) if sMatchesP => (pp, dummy, None) // <:< is never <equals>
- case q @ Typed(pp, _) if sMatchesP => (alts(pp, q), dummy, None) // never =:= for <equals>
- case z: UnApply => (EmptyTree, dummy, pass)
- case _ =>
- if (sMatchesP && !pattern.isDefault) (alts(EmptyTree, pat), subs, None)
- else if (pMatchesS || pattern.isDefault) (EmptyTree, dummy, pass)
- else (None, None, pass)
+
+ // Note - at the moment these comments are mostly trivial or nonsensical, but
+ // they persist from a much earlier time and I still try to read the tea leaves
+ //
+ // (1) special case for constant null
+ // (2) matching an object
+ // (3) <:< is never <equals>
+ // (4) never =:= for <equals>
+
+ (pattern match {
+ case Pattern(LIT(null), _) if !eqHead(pattern.tpe) => (None, None, pass) // (1)
+ case x if isObjectTest => (EmptyTree, dummy, None) // (2)
+ case Pattern(Typed(pp @ Pattern(_: UnApply, _), _), _) if sMatchesP => (pp, dummy, None) // (3)
+ case Pattern(Typed(pp, _), _) if sMatchesP => (alts(pp, pattern.tree), dummy, None) // (4)
+ case Pattern(_: UnApply, _) => (EmptyTree, dummy, pass)
+ case x if !x.isDefault && sMatchesP => (alts(EmptyTree, pat), subs, None)
+ case x if x.isDefault || pMatchesS => (EmptyTree, dummy, pass)
+ case _ => (None, None, pass)
// The below (once fixed) bugs 425 and 816 with only the small downside
// of causing 60 other tests to fail.
@@ -726,7 +734,7 @@ trait ParallelMatching extends ast.TreeDSL
case class Row(pat: List[Pattern], subst: Bindings, guard: Guard, bx: Int) {
def insert(h: Pattern) = copy(pat = h :: pat)
- def insert(hs: List[Pattern]) = copy(pat = hs ::: pat) // prepends supplied tree
+ def insert(hs: List[Pattern]) = copy(pat = hs ::: pat) // prepends supplied pattern
def replace(hs: List[Pattern]) = copy(pat = hs) // substitutes for patterns
def rebind(b: Bindings) = copy(subst = b) // substitutes for bindings
@@ -816,9 +824,26 @@ trait ParallelMatching extends ast.TreeDSL
case class Combo(index: Int, sym: Symbol) {
// is this combination covered by the given pattern?
- def isCovered(p: Pattern) = cond(p.tree) {
- case _: UnApply | _: ArrayValue => true
- case x => isDefaultPattern(x) || (p.tpe coversSym sym)
+ def isCovered(p: Pattern) = {
+ def cmpSymbols(t1: Type, t2: Type) = t1.typeSymbol eq t2.typeSymbol
+ def coversSym = {
+ val tpe = decodedEqualsType(p.tpe)
+ lazy val lmoc = sym.linkedModuleOfClass
+ val symtpe =
+ if ((sym hasFlag Flags.MODULE) && (lmoc ne NoSymbol))
+ singleType(sym.tpe.prefix, lmoc) // e.g. None, Nil
+ else sym.tpe
+
+ (tpe.typeSymbol == sym) ||
+ (symtpe <:< tpe) ||
+ (symtpe.parents exists (x => cmpSymbols(x, tpe))) || // e.g. Some[Int] <: Option[&b]
+ ((tpe.prefix memberType sym) <:< tpe) // outer, see combinator.lexical.Scanner
+ }
+
+ cond(p.tree) {
+ case _: UnApply | _: ArrayValue => true
+ case x => isDefaultPattern(x) || coversSym
+ }
}
}
case class SetCombo(index: Int, syms: Set[Symbol]) {}
@@ -985,11 +1010,11 @@ trait ParallelMatching extends ast.TreeDSL
typer typed (tpe match {
case ct: ConstantType => ct.value match {
- case v @ Constant(null) if isAnyRef(scrutTree.tpe) => scrutTree ANY_EQ NULL
+ case v @ Constant(null) if scrutTree.tpe.isAnyRef => scrutTree ANY_EQ NULL
case v => scrutTree MEMBER_== Literal(v)
}
case _: SingletonType if useEqTest => REF(tpe.termSymbol) MEMBER_== scrutTree
- case _ if scrutTree.tpe <:< tpe && isAnyRef(tpe) => scrutTree OBJ_!= NULL
+ case _ if scrutTree.tpe <:< tpe && tpe.isAnyRef => scrutTree OBJ_!= NULL
case _ => scrutTree IS tpe
})
}
diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
index 575050821a..0fd3043281 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
@@ -27,6 +27,18 @@ trait PatternBindings extends ast.TreeDSL
override def safeToString: String = "PseudoType("+o+")"
}
+ final def definedVars(x: Tree): List[Symbol] = {
+ def vars(x: Tree): List[Symbol] = x match {
+ case Apply(_, args) => args flatMap vars
+ case b @ Bind(_, p) => b.symbol :: vars(p)
+ case Typed(p, _) => vars(p) // otherwise x @ (_:T)
+ case UnApply(_, args) => args flatMap vars
+ case ArrayValue(_, xs) => xs flatMap vars
+ case x => Nil
+ }
+ vars(x) reverse
+ }
+
// 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] = {
diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
index dd9022cd2d..59fe3ed0d7 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala
@@ -7,7 +7,7 @@
package scala.tools.nsc
package matching
-import scala.tools.nsc.util.{Position, NoPosition}
+import scala.tools.nsc.util.NoPosition
/**
* @author Burak Emir
@@ -17,76 +17,16 @@ trait PatternNodes extends ast.TreeDSL
self: transform.ExplicitOuter =>
import global.{ typer => _, _ }
- import analyzer.Typer
- import symtab.Flags
- import Types._
import CODE._
- import definitions.{ ConsClass, ListClass, AnyRefClass, EqualsPatternClass, ListModule }
-
- type TypeComparison = (Type, Type) => Boolean
-
- // Tests on Types
- def isAnyRef(t: Type) = t <:< AnyRefClass.tpe
- def isCaseClass(t: Type) = t.typeSymbol hasFlag Flags.CASE
-
- // Comparisons on types
- // def sameSymbols: TypeComparison = _.typeSymbol eq _.typeSymbol
- // def samePrefix: TypeComparison = _.prefix =:= _.prefix
- // def isSubErased: TypeComparison = (t1, t2) => cond((t1, t2)) {
- // case (_: TypeRef, _: TypeRef) => !t1.isArray && samePrefix(t1,t2) && (sameSymbols(t1,t2) || isSubClass(t1, t2))
- // }
-
- // def isSubClass: TypeComparison = (t1, t2) => t1.baseClasses exists (_ eq t2.typeSymbol)
- // def isSubType: TypeComparison = (t1, t2) => isSubClass(t1, t2) && (t1 <:< t2)
- // def isPatMatch: TypeComparison = (t1, t2) => isSubType(t1, t2)
-
-
- // If we write isSubtypeOf like:
- //
- // = t1.baseTypeSeq exists (_ =:= t2)
- //
- // ..then all tests pass except for test/files/run/bug1434.scala, which involves:
- // class A[T], B extends A[Any], C extends B ; ... match { case _: A[_] => .. ; case _: C => .. ; case _: B => .. }
- // and a match error is thrown, which is interesting because either of C or B should match.
- def isSubtypeOf(t1: Type, t2: Type) = t1.baseTypeSeq exists (p => cmpSymbols(p, t2))
- def cmpSymbols(t1: Type, t2: Type) = t1.typeSymbol eq t2.typeSymbol
-
- case class TypeComp(x: Type, y: Type) {
- def xIsaY = x <:< y
- def yIsaX = y <:< x
- def eqSymbol = cmpSymbols(x, y)
- def eqPrefix = x.prefix =:= y.prefix
-
- object erased {
- import Types._
- /** an approximation of _tp1 <:< tp2 that ignores _ types. this code is wrong,
- * ideally there is a better way to do it, and ideally defined in Types.scala
- */
- private def cmpErased(t1: Type, t2: Type) = (t1, t2) match {
- case (_: TypeRef, _: TypeRef) => !t1.isArray && eqPrefix && (eqSymbol || isSubtypeOf(t1, t2))
- case _ => false
- }
-
- def xIsaY = cmpErased(x, y)
- def yIsaX = cmpErased(y, x)
- }
- }
+ import definitions.{ ListClass, ConsClass }
object Types {
import definitions._
- implicit def enrichType(_tpe: Type): RichType = new RichType(_tpe)
+ implicit def enrichType(x: Type): RichType = new RichType(x)
- class RichType(_tpe: Type) {
- /* equality checks for named constant patterns like "Foo()" are encoded as "_:<equals>[Foo().type]"
- * and later compiled to "if(Foo() == scrutinee) ...". This method extracts type information from
- * such an encoded type, which is used in optimization. If the argument is not an encoded equals
- * test, it is returned as is.
- */
- private def tpeWRTEquality(t: Type) = t match {
- case TypeRef(_, EqualsPatternClass, List(arg)) => arg
- case _ => t
- }
- lazy val tpe = tpeWRTEquality(_tpe)
+ class RichType(undecodedTpe: Type) {
+ def tpe = decodedEqualsType(undecodedTpe)
+ def isAnyRef = tpe <:< AnyRefClass.tpe
// These tests for final classes can inspect the typeSymbol
private def is(s: Symbol) = tpe.typeSymbol eq s
@@ -97,23 +37,7 @@ trait PatternNodes extends ast.TreeDSL
def isBoolean = is(BooleanClass)
def isNothing = is(NothingClass)
def isArray = is(ArrayClass)
-
- def cmp(other: Type): TypeComp = TypeComp(tpe, tpeWRTEquality(other))
-
- def coversSym(sym: Symbol) = {
- lazy val lmoc = sym.linkedModuleOfClass
- val symtpe =
- if ((sym hasFlag Flags.MODULE) && (lmoc ne NoSymbol))
- singleType(sym.tpe.prefix, lmoc) // e.g. None, Nil
- else sym.tpe
-
- (tpe.typeSymbol == sym) ||
- (symtpe <:< tpe) ||
- (symtpe.parents exists (x => cmpSymbols(x, tpe))) || // e.g. Some[Int] <: Option[&b]
- ((tpe.prefix memberType sym) <:< tpe) // outer, see combinator.lexical.Scanner
- }
}
-
}
/** For folding a list into a well-typed x :: y :: etc :: tree. */
@@ -122,9 +46,9 @@ trait PatternNodes extends ast.TreeDSL
val consRef = typeRef(pre, sym, List(tpe))
val listRef = typeRef(pre, ListClass, List(tpe))
- def fold(x: Tree, xs: Tree) = x match {
- case sp @ Strip(_, _: Star) => makeBind(definedVars(sp), WILD(sp.tpe))
- case _ =>
+ def fold(x: Tree, xs: Tree) = unbind(x) match {
+ case _: Star => makeBind(definedVars(x), WILD(x.tpe))
+ case _ =>
val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy")
val consType = MethodType(dummyMethod newSyntheticValueParams List(tpe, listRef), consRef)
@@ -137,83 +61,11 @@ trait PatternNodes extends ast.TreeDSL
def normalizedListPattern(pats: List[Tree], tptArg: Type): Tree =
pats.foldRight(gen.mkNil)(listFolder(tptArg))
- // An Apply that's a constructor pattern (case class)
- // foo match { case C() => true }
- object Apply_CaseClass {
- def unapply(x: Any) = condOpt(x) {
- case x @ Apply(fn, args) if fn.isType => (x.tpe, args)
- }
- }
-
- // No-args Apply where fn is not a type - looks like, case object with prefix?
- //
- // class Pip {
- // object opcodes { case object EmptyInstr }
- // def bop(x: Any) = x match { case opcodes.EmptyInstr => true }
- // }
- object Apply_Value {
- def unapply(x: Any) = condOpt(x) {
- case x @ Apply(fn, Nil) if !fn.isType => (x.tpe.prefix, x.symbol)
- }
- }
-
- // No-args Apply for all the other cases
- // val Bop = Nil
- // def foo(x: Any) = x match { case Bop => true }
- object Apply_Function {
- def isApplyFunction(t: Apply) = cond(t) {
- case Apply_Value(_, _) => true
- case x if !isCaseClass(x.tpe) => true
- }
- def unapply(x: Any) = condOpt(x) {
- case x @ Apply(fn, Nil) if isApplyFunction(x) => fn
- }
- }
-
- // unapplySeq extractor
- // val List(x,y) = List(1,2)
- object UnapplySeq {
- private object TypeApp {
- def unapply(x: Any) = condOpt(x) {
- case TypeApply(sel @ Select(stor, nme.unapplySeq), List(tpe)) if stor.symbol eq ListModule => tpe
+ object UnapplyParamType {
+ def unapply(x: Tree): Option[Type] = condOpt(unbind(x)) {
+ case UnApply(Apply(fn, _), _) => fn.tpe match {
+ case m: MethodType => m.paramTypes.head
}
}
- def unapply(x: UnApply) = condOpt(x) {
- case UnApply(Apply(TypeApp(tptArg), _), List(ArrayValue(_, xs))) => (tptArg, xs)
- }
- }
-
- // unapply extractor
- // val Pair(_,x) = Pair(1,2)
- object __UnApply {
- private def paramType(fn: Tree) = fn.tpe match { case m: MethodType => m.paramTypes.head }
- def unapply(x: Tree) = condOpt(x) {
- case Strip(vs, UnApply(Apply(fn, _), args)) => (vs, paramType(fn), args)
- }
- }
-
- // break a pattern down into bound variables and underlying tree.
- object Strip {
- private def strip(t: Tree, syms: List[Symbol] = Nil): (Tree, List[Symbol]) = t match {
- case b @ Bind(_, pat) => strip(pat, b.symbol :: syms)
- case _ => (t, syms)
- }
- def unapply(x: Tree): Option[(List[Symbol], Tree)] = Some(strip(x).swap)
- }
-
- object Stripped {
- def unapply(x: Tree): Option[Tree] = Some(unbind(x))
- }
-
- final def definedVars(x: Tree): List[Symbol] = {
- def vars(x: Tree): List[Symbol] = x match {
- case Apply(_, args) => args flatMap vars
- case b @ Bind(_, p) => b.symbol :: vars(p)
- case Typed(p, _) => vars(p) // otherwise x @ (_:T)
- case UnApply(_, args) => args flatMap vars
- case ArrayValue(_, xs) => xs flatMap vars
- case x => Nil
- }
- vars(x) reverse
}
}
diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala
index 078c0862e7..3c4ea68b1c 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -83,7 +83,7 @@ trait Patterns extends ast.TreeDSL {
// 8.1.5
case class ConstructorPattern(tree: Apply) extends ApplyPattern {
- require(fn.isType && isCaseClass(tpe))
+ require(fn.isType && this.isCaseClass)
override def subpatterns(pats: MatchMatrix#Patterns) =
if (pats.isCaseHead) args map Pattern.apply
@@ -197,10 +197,25 @@ trait Patterns extends ast.TreeDSL {
case x: Star => MiscPattern(x) // XXX
case _ => abort("Unknown Tree reached pattern matcher: %s/%s".format(tree, tree.getClass))
}
- def unapply(other: Pattern): Option[Tree] = Some(other.tree)
+ def unapply(other: Any): Option[(Tree, List[Symbol])] = other match {
+ case x: Tree => unapply(Pattern(x))
+ case x: Pattern => Some((x.tree, x.boundVariables))
+ case _ => None
+ }
}
object UnapplyPattern {
+ private object UnapplySeq {
+ private object TypeApp {
+ def unapply(x: Any) = condOpt(x) {
+ case TypeApply(sel @ Select(stor, nme.unapplySeq), List(tpe)) if stor.symbol eq ListModule => tpe
+ }
+ }
+ def unapply(x: UnApply) = condOpt(x) {
+ case UnApply(Apply(TypeApp(tptArg), _), List(ArrayValue(_, xs))) => (tptArg, xs)
+ }
+ }
+
def apply(x: UnApply): Pattern = {
x match {
case UnapplySeq(_, _) => SequenceExtractorPattern(x)
@@ -238,7 +253,6 @@ trait Patterns extends ast.TreeDSL {
sealed abstract class ApplyPattern extends Pattern {
protected lazy val Apply(fn, args) = tree
- private def isCaseClass = tree.tpe.typeSymbol hasFlag Flags.CASE
def isConstructorPattern = fn.isType
}
// trait SimplePattern extends Pattern {
@@ -302,6 +316,8 @@ trait Patterns extends ast.TreeDSL {
def isSymValid = (sym != null) && (sym != NoSymbol)
def isModule = sym.isModule || tpe.termSymbol.isModule
+ def isCaseClass = tpe.typeSymbol hasFlag Flags.CASE
+ def isObject = isSymValid && prefix.isStable
def setType(tpe: Type): this.type = {
tree setType tpe