diff options
author | Paul Phillips <paulp@improving.org> | 2010-05-14 19:25:31 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-05-14 19:25:31 +0000 |
commit | d97b3a8066dfe588e080c6b3c87bda2c9f27f80e (patch) | |
tree | 587dcb985358d3381bc4fa9648ba12a725ea42dc | |
parent | 7b822f28663e547e438f7aeb4e6520af32be7c07 (diff) | |
download | scala-d97b3a8066dfe588e080c6b3c87bda2c9f27f80e.tar.gz scala-d97b3a8066dfe588e080c6b3c87bda2c9f27f80e.tar.bz2 scala-d97b3a8066dfe588e080c6b3c87bda2c9f27f80e.zip |
Starting to look like the pattern matcher and I...
Starting to look like the pattern matcher and I can meet in the middle.
More distributing my acquired bottom-up knowledge among the current
code. No review.
3 files changed, 43 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 7fbc57c325..73ecbdee70 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -171,9 +171,7 @@ trait ParallelMatching extends ast.TreeDSL def tail = ps.tail def size = ps.length - def caseAccessors = head.necessaryType.typeSymbol.caseFieldAccessors - def currentArity = if (head.isCaseClass) caseAccessors.length else 0 - def dummies = emptyPatterns(currentArity) + def dummies = head.dummies def apply(i: Int): Pattern = ps(i) def pzip() = ps.zipWithIndex @@ -190,17 +188,11 @@ trait ParallelMatching extends ast.TreeDSL } } - object TypedUnapply { - def unapply(x: Tree): Option[Boolean] = condOpt(x) { - case Typed(UnapplyParamType(tpe), tpt) => !(tpt.tpe <:< tpe) - } - } - def mkRule(rest: Rep): RuleApplication = { tracing("Rule", head match { case x if isEquals(x.tree.tpe) => new MixEquals(this, rest) case x: SequencePattern => new MixSequence(this, rest, x) - case AnyUnapply(false) => new MixUnapply(this, rest, false) + case AnyUnapply(false) => new MixUnapply(this, rest) case _ => isPatternSwitch(scrut, ps) match { case Some(x) => new MixLiteralInts(x, rest) @@ -356,7 +348,7 @@ trait ParallelMatching extends ast.TreeDSL /** mixture rule for unapply pattern */ - class MixUnapply(val pmatch: PatternMatch, val rest: Rep, typeTest: Boolean) extends RuleApplication { + class MixUnapply(val pmatch: PatternMatch, val rest: Rep) extends RuleApplication { val uapattern = head match { case x: UnapplyPattern => x ; case _ => abort("XXX") } val ua @ UnApply(app, args) = head.tree @@ -569,16 +561,16 @@ trait ParallelMatching extends ast.TreeDSL val failRows = new ListBuffer[(Int, Pattern)] for ((pattern, j) <- pmatch.pzip()) { - def isMoreSpecific = matches(pattern.tpe, head.necessaryType) - def isLessSpecific = matches(head.necessaryType, pattern.tpe) - def isEquivalent = head.necessaryType =:= pattern.tpe - def isObjectTest = pattern.isObject && (head.necessaryType =:= pattern.necessaryType) + def isMoreSpecific = matches(pattern.tpe, head.tpe) + def isLessSpecific = matches(head.tpe, pattern.tpe) + def isEquivalent = head.tpe =:= pattern.tpe + def isObjectTest = pattern.isObject && (head.tpe =:= pattern.tpe) def ifElsePattern(yes: Pattern) = if (isEquivalent) yes else pattern def succDummy = succRows += ((j, NoPattern :: pmatch.dummies)) def succTyped(pp: Pattern) = succRows += ((j, ifElsePattern(pp) :: pmatch.dummies)) - def succSubs = succRows += ((j, ifElsePattern(NoPattern) :: (pattern subpatterns pmatch))) + def succSubs = succRows += ((j, ifElsePattern(NoPattern) :: (pattern expandToArity head.arity))) def failOnly = failRows += ((j, pattern)) pattern match { @@ -605,7 +597,7 @@ trait ParallelMatching extends ast.TreeDSL } } - lazy val casted = scrut castedTo head.necessaryType + lazy val casted = scrut castedTo head.tpe lazy val cond = condition(checkErroneous(casted), scrut, head.boundVariables.nonEmpty) lazy val success = { diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index 83fd3a9608..82bddb2013 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -104,10 +104,7 @@ trait PatternBindings extends ast.TreeDSL // Like rebindToEqualsCheck, but subtly different. Not trying to be // mysterious -- I haven't sorted it all out yet. - def rebindToObjectCheck(): Pattern = { - val sType = sufficientType - rebindToType(mkEqualsRef(sType), sType) - } + def rebindToObjectCheck(): Pattern = rebindToType(mkEqualsRef(atomicTpe), atomicTpe) /** Helpers **/ private def wrapBindings(vs: List[Symbol], pat: Tree): Tree = vs match { diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index a135655b9d..b1bcf44c38 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -89,7 +89,7 @@ trait Patterns extends ast.TreeDSL { // require (!isVarPattern(fn) && args.isEmpty) val ident @ Ident(name) = fn - override def sufficientType = Pattern(ident).equalsCheck + override def atomicTpe = Pattern(ident).equalsCheck override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = "Id(%s)".format(name) } @@ -98,7 +98,7 @@ trait Patterns extends ast.TreeDSL { require (args.isEmpty) val Apply(select: Select, _) = tree - override def sufficientType = mkSingletonFromQualifier + override def atomicTpe = mkSingletonFromQualifier override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = backticked match { case Some(s) => "this." + s @@ -117,7 +117,7 @@ trait Patterns extends ast.TreeDSL { case class ObjectPattern(tree: Apply) extends ApplyPattern { // NamePattern? require(!fn.isType && isModule) - override def sufficientType = tpe.narrow + override def atomicTpe = tpe.narrow override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = "Obj(%s)".format(fn) } @@ -139,9 +139,10 @@ trait Patterns extends ast.TreeDSL { private def isColonColon = cleanName == "::" - override def subpatterns(pm: MatchMatrix#PatternMatch) = - if (pm.head.isCaseClass) toPats(args) - else super.subpatterns(pm) + override def expandToArity(newArity: Int): List[Pattern] = { + assert(newArity == args.length) + toPats(args) + } override def simplify(pv: PatternVar) = if (args.isEmpty) this rebindToEmpty tree.tpe @@ -168,13 +169,14 @@ trait Patterns extends ast.TreeDSL { private val MethodType(List(arg, _*), _) = fn.tpe private def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe - override def necessaryType = arg.tpe + // to match an extractor, the arg type must be matched. + override def tpe = arg.tpe override def simplify(pv: PatternVar) = if (pv.sym.tpe <:< arg.tpe) this else this rebindTo uaTyped - override def description = "UnApp(%s => %s)".format(necessaryType, resTypesString) + override def description = "UnApp(%s => %s)".format(tpe, resTypesString) } // 8.1.8 (unapplySeq calls) @@ -384,7 +386,7 @@ trait Patterns extends ast.TreeDSL { protected def mkSingletonFromQualifier = { def pType = qualifier match { case _: Apply => PseudoType(tree) - case _ => singleType(Pattern(qualifier).necessaryType, sym) + case _ => singleType(Pattern(qualifier).tpe, sym) } qualifier.tpe match { case t: ThisType => singleType(t, sym) // this.X @@ -395,7 +397,7 @@ trait Patterns extends ast.TreeDSL { sealed trait NamePattern extends Pattern { def name: Name - override def sufficientType = tpe.narrow + override def atomicTpe = tpe.narrow override def simplify(pv: PatternVar) = this.rebindToEqualsCheck() override def description = name.toString() } @@ -422,22 +424,31 @@ trait Patterns extends ast.TreeDSL { protected lazy val Apply(fn, args) = tree override def subpatternsForVars: List[Pattern] = toPats(args) - override def dummies = - if (!this.isCaseClass) Nil - else emptyPatterns(sufficientType.typeSymbol.caseFieldAccessors.size) - def isConstructorPattern = fn.isType } sealed abstract class Pattern extends PatternBindingLogic { val tree: Tree + // The type of a pattern says: in order for something to match this + // pattern, it must conform to this type. It does NOT say that if + // something does conform to this type, it definitely matches the pattern: + // see atomic type for that. + def tpe = tree.tpe + + // The atomic type of a pattern says: if something matches this, it + // definitely matches the pattern (but this is independent of nullness + // and guards, which are checked independently.) + def atomicTpe = tpe + // returns either a simplification of this pattern or identity. def simplify(pv: PatternVar): Pattern = this - def simplify(): Pattern = this simplify null + + // the arity of this pattern + def arity = if (isCaseClass) caseAccessors.length else 0 // the right number of dummies for this pattern - def dummies: List[Pattern] = Nil + def dummies: List[Pattern] = emptyPatterns(arity) // 8.1.13 // A pattern p is irrefutable for type T if any of the following applies: @@ -448,33 +459,26 @@ trait Patterns extends ast.TreeDSL { // pi is irrefutable for Ti. def irrefutableFor(tpe: Type) = false - // does this pattern completely cover that pattern (i.e. latter cannot be matched) - def completelyCovers(second: Pattern) = false - // Is this a default pattern (untyped "_" or an EmptyTree inserted by the matcher) def isDefault = false - // what type must a scrutinee have to have any chance of matching this pattern? - def necessaryType = tpe - - // what type could a scrutinee have which would automatically indicate a match? - // (nullness and guards will still be checked.) - def sufficientType = tpe - // XXX have to determine if this can be made useful beyond an extractor barrier. // Default sufficient type might be NothingClass.tpe, tpe.narrow, ... // the subpatterns for this pattern (at the moment, that means constructor arguments) - def subpatterns(pm: MatchMatrix#PatternMatch): List[Pattern] = pm.dummies + def expandToArity(newArity: Int): List[Pattern] = + if (isDefault) emptyPatterns(newArity) + else if (newArity == 0) Nil + else Predef.error("expandToArity(" + newArity + ") in " + this) 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 isCaseClass = tpe.typeSymbol hasFlag Flags.CASE + def caseAccessors = tpe.typeSymbol.caseFieldAccessors def isObject = isSymValid && prefix.isStable // XXX not entire logic def unadorn(t: Tree): Tree = Pattern unadorn t @@ -516,7 +520,7 @@ trait Patterns extends ast.TreeDSL { if (boundVariables.isEmpty) description else "%s%s".format(bindingsDescription, description) } - def toTypeString() = "%s <: x <: %s".format(necessaryType, sufficientType) + def toTypeString() = "%s <: x <: %s".format(tpe, atomicTpe) } /*** Extractors ***/ |