diff options
author | Paul Phillips <paulp@improving.org> | 2009-10-02 16:16:57 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-10-02 16:16:57 +0000 |
commit | 154cad734b72b8577c3dbea6a5ef05cd5ba8a550 (patch) | |
tree | 9f70d6a4e4d3c5e5c9787312e55ed2702cea434c | |
parent | 321338da04a6ca9bcc9b77ae663ed27f26a67d85 (diff) | |
download | scala-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.
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 } } |