From 4a6c3da399756720b124eaa209ed34e36c394600 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 7 Oct 2009 00:02:05 +0000 Subject: Getting variable binding bits into appropriate ... Getting variable binding bits into appropriate places. Waved goodbye to PatternNodes. --- .../tools/nsc/matching/ParallelMatching.scala | 23 ++++- .../scala/tools/nsc/matching/PatternBindings.scala | 73 ++++++++++++-- .../scala/tools/nsc/matching/PatternNodes.scala | 63 ------------ .../scala/tools/nsc/matching/Patterns.scala | 109 +++++++-------------- .../scala/tools/nsc/transform/ExplicitOuter.scala | 3 +- 5 files changed, 124 insertions(+), 147 deletions(-) delete mode 100644 src/compiler/scala/tools/nsc/matching/PatternNodes.scala diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index a533863b0f..12a3ac99c2 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -23,16 +23,35 @@ trait ParallelMatching extends ast.TreeDSL with Patterns with PatternBindings with PatternOptimizer - with PatternNodes { self: ExplicitOuter => import global.{ typer => _, _ } import definitions.{ AnyRefClass, IntClass, getProductArgs, productProj } import treeInfo.{ isStar } - import Types._ import CODE._ + object Types { + import definitions._ + implicit def enrichType(x: Type): RichType = new RichType(x) + + 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 + def isByte = is(ByteClass) + def isShort = is(ShortClass) + def isInt = is(IntClass) + def isChar = is(CharClass) + def isBoolean = is(BooleanClass) + def isNothing = is(NothingClass) + def isArray = is(ArrayClass) + } + } + import Types._ + /** Debugging support: enable with -Ypmat-debug **/ private final def trace = settings.Ypmatdebug.value diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index f791236a10..6450962391 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -38,12 +38,72 @@ trait PatternBindings extends ast.TreeDSL case Alternative(ps) => ps map prevBindings } } - def makeBind(vs: List[Symbol], pat: Tree): Tree = vs match { case Nil => pat case x :: xs => Bind(x, makeBind(xs, pat)) setType pat.tpe } + trait PatternBindingLogic { + self: Pattern => + + // This is for traversing the pattern tree - pattern types which might have + // bound variables beneath them return a list of said patterns for flatMapping. + def subpatternsForVars: List[Pattern] = Nil + + // This is what calls subpatternsForVars. + def definedVars: List[Symbol] = + (boundVariables ::: (subpatternsForVars flatMap (_.definedVars))).reverse // XXX reverse? + + lazy val boundVariables = strip(boundTree) + + // XXX only a var for short-term experimentation. + private var _boundTree: Bind = null + def boundTree = if (_boundTree == null) tree else _boundTree + def withBoundTree(x: Bind): this.type = { + _boundTree = x + this + } + + // 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, annotatedType: Type = null): Pattern = { + val aType = if (annotatedType == null) tpe else annotatedType + rebindTo(Typed(WILD(tpe), TypeTree(aType)) 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) + + // Like rebindToEqualsCheck, but subtly different. Not trying to be + // mysterious -- I haven't sorted it all out yet. + def rebindToObjectCheck(): Pattern = { + val sType = mkSingleton + rebindToType(mkEqualsRef(sType), sType) + } + + /** Helpers **/ + + 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 + } + private def strip(t: Tree): List[Symbol] = t match { + case b @ Bind(_, pat) => b.symbol :: strip(pat) + case _ => Nil + } + } + case class Binding(pvar: Symbol, tvar: Symbol) { // see bug #1843 for the consequences of not setting info. // there is surely a better way to do this, especially since @@ -52,10 +112,8 @@ trait PatternBindings extends ast.TreeDSL if (tvar.info containsTp WildcardType) tvar setInfo pvar.info - def toIdent = - Ident(tvar) setType pvar.tpe - - def castIfNeeded = + def toIdent = Ident(tvar) setType pvar.tpe + def castIfNeeded = if (tvar.tpe <:< pvar.tpe) ID(tvar) else ID(tvar) AS_ANY pvar.tpe } @@ -71,8 +129,6 @@ trait PatternBindings extends ast.TreeDSL } class Bindings(private val vlist: List[Binding]) extends Function1[Symbol, Option[Ident]] { - def this() = this(Nil) - def vmap(v: Symbol): Option[Binding] = vlist find (_.pvar eq v) // filters the given list down to those defined in these bindings @@ -83,11 +139,10 @@ trait PatternBindings extends ast.TreeDSL val newBindings = vs.toList map (v => Binding(v, tvar)) new Bindings(newBindings ++ vlist) } - def apply(v: Symbol): Option[Ident] = vmap(v) map (_.toIdent) override def toString() = " Bound(%s)".format(vlist) } - val NoBinding: Bindings = new Bindings() + val NoBinding: Bindings = new Bindings(Nil) } \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala b/src/compiler/scala/tools/nsc/matching/PatternNodes.scala deleted file mode 100644 index c28a0790b2..0000000000 --- a/src/compiler/scala/tools/nsc/matching/PatternNodes.scala +++ /dev/null @@ -1,63 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Burak Emir - */ -// $Id$ - -package scala.tools.nsc -package matching - -import scala.tools.nsc.util.NoPosition - -/** - * @author Burak Emir - */ -trait PatternNodes extends ast.TreeDSL -{ - self: transform.ExplicitOuter => - - import global.{ typer => _, _ } - import CODE._ - import definitions.{ ListClass, ConsClass } - - object Types { - import definitions._ - implicit def enrichType(x: Type): RichType = new RichType(x) - - 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 - def isByte = is(ByteClass) - def isShort = is(ShortClass) - def isInt = is(IntClass) - def isChar = is(CharClass) - def isBoolean = is(BooleanClass) - def isNothing = is(NothingClass) - def isArray = is(ArrayClass) - } - } - - /** For folding a list into a well-typed x :: y :: etc :: tree. */ - private def listFolder(tpe: Type) = { - val MethodType(_, TypeRef(pre, sym, _)) = ConsClass.primaryConstructor.tpe - val consRef = typeRef(pre, sym, List(tpe)) - val listRef = typeRef(pre, ListClass, List(tpe)) - - def fold(x: Tree, xs: Tree) = unbind(x) match { - case _: Star => makeBind(Pattern(x).definedVars, WILD(x.tpe)) - case _ => - val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy") - val consType = MethodType(dummyMethod newSyntheticValueParams List(tpe, listRef), consRef) - - Apply(TypeTree(consType), List(x, xs)) setType consRef - } - - fold _ - } - - def normalizedListPattern(pats: List[Tree], tptArg: Type): Tree = - pats.foldRight(gen.mkNil)(listFolder(tptArg)) -} diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index b1c3726e36..35406d097f 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -7,6 +7,7 @@ package scala.tools.nsc package matching import symtab.Flags +import util.NoPosition /** * Simple pattern types: @@ -66,6 +67,8 @@ trait Patterns extends ast.TreeDSL { case class TypedPattern(tree: Typed) extends Pattern { private val Typed(expr, tpt) = tree + override def subpatternsForVars: List[Pattern] = List(Pattern(expr)) + override def irrefutableFor(tpe: Type) = tpe <:< tree.tpe override def simplify(testVar: Symbol) = Pattern(expr) match { case ExtractorPattern(ua) if testVar.tpe <:< tpt.tpe => this rebindTo expr @@ -142,8 +145,8 @@ trait Patterns extends ast.TreeDSL { } // 8.1.7 - case class ExtractorPattern(tree: UnApply) extends Pattern { - private val UnApply(Apply(fn, _), args) = tree + case class ExtractorPattern(tree: UnApply) extends UnapplyPattern { + private val Apply(fn, _) = unfn private val MethodType(List(arg, _*), _) = fn.tpe private def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe @@ -158,16 +161,35 @@ trait Patterns extends ast.TreeDSL { } // 8.1.8 (unapplySeq calls) - case class SequenceExtractorPattern(tree: UnApply) extends Pattern { + case class SequenceExtractorPattern(tree: UnApply) extends UnapplyPattern { private val UnApply( Apply(TypeApply(Select(_, nme.unapplySeq), List(tptArg)), _), List(ArrayValue(_, elems)) ) = tree + /** For folding a list into a well-typed x :: y :: etc :: tree. */ + private def listFolder = { + val tpe = tptArg.tpe + val MethodType(_, TypeRef(pre, sym, _)) = ConsClass.primaryConstructor.tpe + val consRef = typeRef(pre, sym, List(tpe)) + val listRef = typeRef(pre, ListClass, List(tpe)) + + def fold(x: Tree, xs: Tree) = unbind(x) match { + case _: Star => makeBind(Pattern(x).definedVars, WILD(x.tpe)) + case _ => + val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy") + val consType = MethodType(dummyMethod newSyntheticValueParams List(tpe, listRef), consRef) + + Apply(TypeTree(consType), List(x, xs)) setType consRef + } + + fold _ + } + // @pre: is not right-ignoring (no star pattern) ; no exhaustivity check override def simplify(testVar: Symbol) = { testVar setFlag Flags.TRANS_FLAG - this rebindTo normalizedListPattern(elems, tptArg.tpe) + this rebindTo elems.foldRight(gen.mkNil)(listFolder) } override def toString() = "UnapplySeq(%s)".format(elems) } @@ -178,6 +200,8 @@ trait Patterns extends ast.TreeDSL { lazy val elemPatterns = toPats(elems) lazy val nonStarPatterns = if (hasStar) elemPatterns.init else elemPatterns + override def subpatternsForVars: List[Pattern] = elemPatterns + def hasStar = isRightIgnoring(tree) def nonStarLength = nonStarPatterns.length def isAllDefaults = nonStarPatterns forall (_.isDefault) @@ -345,7 +369,7 @@ trait Patterns extends ast.TreeDSL { /** Some intermediate pattern classes with shared structure **/ - trait SelectPattern extends NamePattern { + sealed trait SelectPattern extends NamePattern { def select: Select lazy val Select(qualifier, name) = select def pathSegments = getPathSegments(tree) @@ -367,7 +391,7 @@ trait Patterns extends ast.TreeDSL { } } - trait NamePattern extends Pattern { + sealed trait NamePattern extends Pattern { def name: Name override def simplify(testVar: Symbol) = this.rebindToEqualsCheck() override def matchingType = mkSingleton @@ -377,8 +401,15 @@ trait Patterns extends ast.TreeDSL { // def simplify(testVar: Symbol): Pattern = this // } - sealed abstract class ApplyPattern extends Pattern { + sealed trait UnapplyPattern extends Pattern { + lazy val UnApply(unfn, args) = tree + override def subpatternsForVars: List[Pattern] = toPats(args) + } + + sealed trait ApplyPattern extends Pattern { protected lazy val Apply(fn, args) = tree + override def subpatternsForVars: List[Pattern] = toPats(args) + def isConstructorPattern = fn.isType } @@ -449,70 +480,6 @@ trait Patterns extends ast.TreeDSL { override def hashCode() = boundTree.hashCode() } - trait PatternBindingLogic { - self: Pattern => - - // XXX only a var for short-term experimentation. - private var _boundTree: Bind = null - def boundTree = if (_boundTree == null) tree else _boundTree - def withBoundTree(x: Bind): this.type = { - _boundTree = x - this - } - lazy val boundVariables = strip(boundTree) - - def definedVars = definedVarsInternal(boundTree) - private def definedVarsInternal(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 - } - - 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, annotatedType: Type = null): Pattern = { - val aType = if (annotatedType == null) tpe else annotatedType - rebindTo(Typed(WILD(tpe), TypeTree(aType)) 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) - - // Like rebindToEqualsCheck, but subtly different. Not trying to be - // mysterious -- I haven't sorted it all out yet. - def rebindToObjectCheck(): Pattern = { - val sType = mkSingleton - rebindToType(mkEqualsRef(sType), sType) - } - - /** Helpers **/ - private def strip(t: Tree): List[Symbol] = t match { - case b @ Bind(_, pat) => b.symbol :: strip(pat) - case _ => Nil - } - } /*** Extractors ***/ diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index c5d8e481fe..0118c0f9cc 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -10,7 +10,7 @@ package transform import symtab._ import Flags.{ CASE => _, _ } import scala.collection.mutable.ListBuffer -import matching.{ TransMatcher, Patterns, PatternNodes, ParallelMatching } +import matching.{ TransMatcher, Patterns, ParallelMatching } /** This class ... * @@ -19,7 +19,6 @@ import matching.{ TransMatcher, Patterns, PatternNodes, ParallelMatching } */ abstract class ExplicitOuter extends InfoTransform with TransMatcher - with PatternNodes with Patterns with ParallelMatching with TypingTransformers -- cgit v1.2.3