summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-04-23 22:04:36 +0000
committerPaul Phillips <paulp@improving.org>2011-04-23 22:04:36 +0000
commit63c7c9d857568879bfda146dd31bfc4ee38cb9fb (patch)
treef11372dc3d38c1eb0a327b33afb9fb25a0a7a658
parent21121ff62ea72523ed5ea6a906b2ce42e9e47f69 (diff)
downloadscala-63c7c9d857568879bfda146dd31bfc4ee38cb9fb.tar.gz
scala-63c7c9d857568879bfda146dd31bfc4ee38cb9fb.tar.bz2
scala-63c7c9d857568879bfda146dd31bfc4ee38cb9fb.zip
Working my way through pattern matcher sequence...
Working my way through pattern matcher sequence issues mostly caused by the special handling of Lists. Also deleting all kinds of useless or almost useless code which is presently only clutter. Closes #2756, #2800, #3050, #3530, #3972, no review.
-rw-r--r--src/compiler/scala/tools/nsc/matching/Matrix.scala1
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala105
-rw-r--r--src/compiler/scala/tools/nsc/matching/PatternBindings.scala10
-rw-r--r--src/compiler/scala/tools/nsc/matching/Patterns.scala180
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala58
-rw-r--r--test/files/pos/bug3972.scala11
-rw-r--r--test/files/run/bug2800.check14
-rw-r--r--test/files/run/bug2800.scala36
-rw-r--r--test/files/run/bug3050.scala (renamed from test/pending/run/bug3050.scala)2
-rw-r--r--test/files/run/bug3530.check13
-rw-r--r--test/files/run/bug3530.scala36
12 files changed, 253 insertions, 215 deletions
diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala
index 5648f97f84..8dc960894c 100644
--- a/src/compiler/scala/tools/nsc/matching/Matrix.scala
+++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala
@@ -88,6 +88,7 @@ trait Matrix extends MatrixAdditions {
context: MatrixContext): Tree =
{
import context._
+ TRACE("handlePattern", "(%s: %s) match { %s cases }", selector, selector.tpe, cases.size)
val matrixInit: MatrixInit = {
val v = copyVar(selector, isChecked, selector.tpe, "temp")
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index 1b0265ce5d..f41c37080a 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -39,15 +39,16 @@ trait ParallelMatching extends ast.TreeDSL
def data: MatrixContext#MatrixInit
- lazy val MatrixInit(roots, cases, failTree) = data
- lazy val ExpandedMatrix(rows, targets) = expand(roots, cases)
- lazy val expansion: Rep = make(roots, rows)
+ lazy val MatrixInit(roots, cases, failTree) = data
+ lazy val (rows, targets) = expand(roots, cases).unzip
+ lazy val expansion: Rep = make(roots, rows)
- val shortCuts = new ListBuffer[Symbol]()
+ private val shortCuts = mutable.HashMap[Int, Symbol]()
- final def shortCut(theLabel: Symbol): Int = {
- shortCuts += theLabel
- -shortCuts.length
+ final def createShortCut(theLabel: Symbol): Int = {
+ val key = shortCuts.size + 1
+ shortCuts(key) = theLabel
+ -key
}
/** first time bx is requested, a LabelDef is returned. next time, a jump.
@@ -55,18 +56,25 @@ trait ParallelMatching extends ast.TreeDSL
*/
final def requestBody(bx: Int, subst: Bindings): Tree = {
// shortcut
- if (bx < 0) Apply(ID(shortCuts(-bx-1)), Nil)
+ if (bx < 0) Apply(ID(shortCuts(-bx)), Nil)
else targets(bx) labelBody subst
}
- /** the injection here handles alternatives and unapply type tests */
- final def make(tvars: PatternVarGroup, row1: List[Row]): Rep = {
- // TRACE("make(%s%s)", pp(tvars.pvs, 1, true), pp(row1, 1, true))
- def classifyPat(opat: Pattern, j: Int): Pattern = opat simplify tvars(j)
+ /** This is the recursively focal point for translating the current
+ * list of pattern variables and a list of pattern match rows into
+ * a tree suitable for entering erasure.
+ *
+ * The first time it is called, the variables are (copies of) the
+ * original pattern matcher roots, and the rows correspond to the
+ * original casedefs.
+ */
+ final def make(roots1: PatternVarGroup, rows1: List[Row]): Rep = {
+ traceCategory("New Match", "%sx%s (%s)", roots1.size, rows1.size, roots1.syms.mkString(", "))
+ def classifyPat(opat: Pattern, j: Int): Pattern = opat simplify roots1(j)
- val rows = row1 flatMap (_ expandAlternatives classifyPat)
- if (rows.length != row1.length) make(tvars, rows) // recursive call if any change
- else Rep(tvars, rows).checkExhaustive
+ val newRows = rows1 flatMap (_ expandAlternatives classifyPat)
+ if (rows1.length != newRows.length) make(roots1, newRows) // recursive call if any change
+ else Rep(roots1, newRows).checkExhaustive
}
override def toString() = "MatchMatrix(%s) { %s }".format(matchResultType, indentAll(targets))
@@ -182,17 +190,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)
@@ -327,7 +329,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
@@ -494,7 +496,9 @@ trait ParallelMatching extends ast.TreeDSL
val compareFn: Tree => Tree = (t: Tree) => compareOp((t DOT methodOp)(LIT(pivotLen)), ZERO)
// wrapping in a null check on the scrutinee
+ // XXX this needs to use the logic in "def condition"
nullSafe(compareFn, FALSE)(scrut.id)
+ // condition(head.tpe, scrut.id, head.boundVariables.nonEmpty)
}
lazy val success = squeezedBlock(pvs map (_.valDef), remake(successRows, pvs, hasStar).toTree)
lazy val failure = remake(failRows).toTree
@@ -521,7 +525,7 @@ trait ParallelMatching extends ast.TreeDSL
lazy val success = remake(List(
rest.rows.head.insert2(List(NoPattern), head.boundVariables, scrut.sym),
- Row(emptyPatterns(1 + rest.tvars.size), NoBinding, EmptyTree, shortCut(label))
+ Row(emptyPatterns(1 + rest.tvars.size), NoBinding, EmptyTree, createShortCut(label))
)).toTree
lazy val failure = LabelDef(label, Nil, labelBody)
@@ -615,8 +619,6 @@ trait ParallelMatching extends ast.TreeDSL
case class Row(pats: List[Pattern], subst: Bindings, guard: Tree, bx: Int) {
private def nobindings = subst.get().isEmpty
private def bindstr = if (nobindings) "" else pp(subst)
- // if (pats exists (p => !p.isDefault))
- // traceCategory("Row", "%s%s", pats, bindstr)
/** Extracts the 'i'th pattern. */
def extractColumn(i: Int) = {
@@ -655,29 +657,6 @@ trait ParallelMatching extends ast.TreeDSL
}
}
- object ExpandedMatrix {
- def unapply(x: ExpandedMatrix) = Some((x.rows, x.targets))
- def apply(rowz: List[(Row, FinalState)]) =
- new ExpandedMatrix(rowz map (_._1), rowz map (_._2) toIndexedSeq)
- }
-
- class ExpandedMatrix(val rows: List[Row], val targets: IndexedSeq[FinalState]) {
- require(rows.size == targets.size)
-
- override def toString() = {
- def vprint(vs: List[Any]) = if (vs.isEmpty) "" else ": %s".format(pp(vs))
- def rprint(r: Row) = pp(r)
- def tprint(t: FinalState) =
- if (t.params.isEmpty) " ==> %s".format(pp(t.body))
- else " ==>\n %s".format(pp(t.params -> t.body))
-
- val xs = rows zip targets map { case (r,t) => rprint(r) + tprint(t) }
- val ppstr = pp(xs, newlines = true)
-
- "ExpandedMatrix(%d rows)".format(rows.size) + ppstr
- }
- }
-
case class FinalState(bx: Int, body: Tree, params: List[Symbol]) {
private var referenceCount = 0
// typer is not able to digest a body of type Nothing being assigned result type Unit
@@ -762,21 +741,19 @@ trait ParallelMatching extends ast.TreeDSL
}
/** Expands the patterns recursively. */
- final def expand(roots: List[PatternVar], cases: List[CaseDef]) =
- tracing("Expanded")(ExpandedMatrix(
- for ((CaseDef(pat, guard, body), index) <- cases.zipWithIndex) yield {
- def mkRow(ps: List[Tree]) = Row(toPats(ps), NoBinding, guard, index)
-
- val pattern = Pattern(pat)
- val row = mkRow(pat match {
- case x if roots.length <= 1 => List(x)
- case Apply(_, args) => args
- case WILD() => emptyTrees(roots.length)
- })
-
- row -> FinalState(index, body, pattern.deepBoundVariables)
- })
- )
+ final def expand(roots: List[PatternVar], cases: List[CaseDef]) = tracing("expand") {
+ for ((CaseDef(pat, guard, body), index) <- cases.zipWithIndex) yield {
+ val subtrees = pat match {
+ case x if roots.length <= 1 => List(x)
+ case Apply(_, args) => args
+ case WILD() => emptyTrees(roots.length)
+ }
+ val row = Row(toPats(subtrees), NoBinding, guard, index)
+ val state = FinalState(index, body, Pattern(pat).deepBoundVariables)
+
+ row -> state
+ }
+ }
/** returns the condition in "if (cond) k1 else k2"
*/
diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
index bb062b3c0a..88983a792f 100644
--- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
+++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala
@@ -89,8 +89,8 @@ trait PatternBindings extends ast.TreeDSL
}
// Wrap this pattern's bindings around (_: Type)
- def rebindToType(tpe: Type, annotatedType: Type = null): Pattern = {
- val aType = if (annotatedType == null) tpe else annotatedType
+ def rebindToType(tpe: Type, ascription: Type = null): Pattern = {
+ val aType = if (ascription == null) tpe else ascription
rebindTo(Typed(WILD(tpe), TypeTree(aType)) setType tpe)
}
@@ -104,10 +104,8 @@ 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(sufficientType), sufficientType)
/** 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 742ab32736..e1f8204960 100644
--- a/src/compiler/scala/tools/nsc/matching/Patterns.scala
+++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala
@@ -27,6 +27,16 @@ trait Patterns extends ast.TreeDSL {
type PatternMatch = MatchMatrix#PatternMatch
private type PatternVar = MatrixContext#PatternVar
+ // private def unapplyArgs(x: Any) = x match {
+ // case UnApply(Apply(TypeApply(_, targs), args), _) => (targs map (_.symbol), args map (_.symbol))
+ // case _ => (Nil, Nil)
+ // }
+ //
+ // private def unapplyCall(x: Any) = x match {
+ // case UnApply(t, _) => treeInfo.methPart(t).symbol
+ // case _ => NoSymbol
+ // }
+
// Fresh patterns
def emptyPatterns(i: Int): List[Pattern] = List.fill(i)(NoPattern)
def emptyTrees(i: Int): List[Tree] = List.fill(i)(EmptyTree)
@@ -45,14 +55,12 @@ trait Patterns extends ast.TreeDSL {
val Ident(name) = tree
require(isVarPattern(tree) && name != nme.WILDCARD)
- override def irrefutableFor(tpe: Type) = true
override def description = "%s".format(name)
}
// 8.1.1 (b)
case class WildcardPattern() extends Pattern {
val tree = EmptyTree
- override def irrefutableFor(tpe: Type) = true
override def isDefault = true
override def description = "_"
}
@@ -62,11 +70,9 @@ trait Patterns extends ast.TreeDSL {
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(pv: PatternVar) = Pattern(expr) match {
- case ExtractorPattern(ua) if pv.sym.tpe <:< tpt.tpe => this rebindTo expr
- case _ => this
+ case ExtractorPattern(ua) if pv.sym.tpe <:< tpt.tpe => this rebindTo expr
+ case _ => this
}
override def description = "Typ(%s: %s)".format(Pattern(expr), tpt)
}
@@ -159,77 +165,67 @@ trait Patterns extends ast.TreeDSL {
if (isColonColon) "%s :: %s".format(Pattern(args(0)), Pattern(args(1)))
else "%s(%s)".format(name, toPats(args).mkString(", "))
}
-
- // XXX todo
- // override def irrefutableFor(tpe: Type) = false
}
// 8.1.6
case class TuplePattern(tree: Apply) extends ApplyPattern {
- // XXX todo
- // override def irrefutableFor(tpe: Type) = false
override def description = "((%s))".format(args.size, toPats(args).mkString(", "))
}
- // 8.1.7
+ // 8.1.7 / 8.1.8 (unapply and unapplySeq calls)
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
-
- override def necessaryType = arg.tpe
-
override def simplify(pv: PatternVar) =
- if (pv.sym.tpe <:< arg.tpe) this
+ if (pv.tpe <:< arg.tpe) this
else this rebindTo uaTyped
- override def description = "UnApp(%s => %s)".format(necessaryType, resTypesString)
+ override def description = "Unapply(%s => %s)".format(necessaryType, resTypesString)
}
- // 8.1.8 (unapplySeq calls)
- case class SequenceExtractorPattern(tree: UnApply) extends UnapplyPattern with SequenceLikePattern {
+ case class SequenceExtractorPattern(tree: UnApply, elems: List[Tree]) extends UnapplyPattern with SequenceLikePattern {
+ override def simplify(pv: PatternVar) = {
+ pv.sym setFlag NO_EXHAUSTIVE
- lazy val UnApply(
- Apply(TypeApply(Select(_, nme.unapplySeq), List(tptArg)), _),
- List(ArrayValue(_, elems))
- ) = tree
+ if (pv.tpe <:< arg.tpe) this
+ else this rebindTo uaTyped
+ }
- /** 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))
+ override def description = "UnapplySeq(%s => %s)".format(necessaryType, resTypesString)
+ }
- def fold(x: Tree, xs: Tree) = unbind(x) match {
- case _: Star => Pattern(x) rebindTo WILD(x.tpe) boundTree // this is using boundVariables instead of deepBoundVariables
- case _ =>
- val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy")
- val consType = MethodType(dummyMethod newSyntheticValueParams List(tpe, listRef), consRef)
+ // Special List handling. It was like that when I got here.
+ case class ListExtractorPattern(tree: UnApply, tpt: Tree, elems: List[Tree]) extends UnapplyPattern with SequenceLikePattern {
+ private val cons = ConsClass.primaryConstructor.tpe.resultType
+ private val consRef = typeRef(cons.prefix, ConsClass, List(tpt.tpe))
+ private val listRef = typeRef(cons.prefix, ListClass, List(tpt.tpe))
- Apply(TypeTree(consType), List(x, xs)) setType consRef
- }
+ // Fold a list into a well-typed x :: y :: etc :: tree.
+ private def listFolder(x: Tree, xs: Tree) = unbind(x) match {
+ case _: Star => Pattern(x) rebindTo WILD(x.tpe) boundTree
+ case _ =>
+ val dummyMethod = new TermSymbol(NoSymbol, NoPosition, "matching$dummy")
+ val consType = MethodType(dummyMethod newSyntheticValueParams List(tpt.tpe, listRef), consRef)
- fold _
+ Apply(TypeTree(consType), List(x, xs)) setType consRef
}
-
- // @pre: is not right-ignoring (no star pattern) ; no exhaustivity check
+ override def necessaryType = if (nonStarPatterns.nonEmpty) consRef else listRef
override def simplify(pv: PatternVar) = {
pv.sym setFlag NO_EXHAUSTIVE
- this rebindTo elems.foldRight(gen.mkNil)(listFolder)
+
+ if (pv.tpe <:< necessaryType)
+ this rebindTo elems.foldRight(gen.mkNil)(listFolder)
+ else
+ this rebindTo (Typed(tree, TypeTree(necessaryType)) setType necessaryType)
}
- override def description = "UnSeq(%s => %s)".format(tptArg, resTypesString)
+ override def description = "List(%s => %s)".format(tpt.tpe, resTypesString)
}
trait SequenceLikePattern extends Pattern {
def elems: List[Tree]
- def elemPatterns = toPats(elems)
-
- def nonStarPatterns: List[Pattern] = if (hasStar) elemPatterns.init else elemPatterns
- def nonStarLength = nonStarPatterns.length
- def isAllDefaults = nonStarPatterns forall (_.isDefault)
+ override def hasStar = elems.nonEmpty && isStar(elems.last)
- def isShorter(other: SequenceLikePattern) = nonStarLength < other.nonStarLength
- def isSameLength(other: SequenceLikePattern) = nonStarLength == other.nonStarLength
+ def elemPatterns = toPats(elems)
+ def nonStarElems = if (hasStar) elems.init else elems
+ def nonStarPatterns = toPats(nonStarElems)
+ def nonStarLength = nonStarElems.length
}
// 8.1.8 (b) (literal ArrayValues)
@@ -273,16 +269,6 @@ trait Patterns extends ast.TreeDSL {
private val cache = new collection.mutable.HashMap[Tree, Pattern]
def clear() = cache.clear()
- def unadorn(x: Tree): Tree = x match {
- case Typed(expr, _) => unadorn(expr)
- case Bind(_, x) => unadorn(x)
- case _ => x
- }
-
- def isRightIgnoring(t: Tree) = cond(unadorn(t)) {
- case ArrayValue(_, xs) if !xs.isEmpty => isStar(unadorn(xs.last))
- }
-
def apply(tree: Tree): Pattern = {
if (cache contains tree)
return cache(tree)
@@ -321,21 +307,22 @@ trait Patterns extends ast.TreeDSL {
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 unapply(x: UnApply) = x match {
+ case UnApply(
+ Apply(TypeApply(Select(qual, nme.unapplySeq), List(tpt)), _),
+ List(ArrayValue(_, elems))) =>
+ Some(qual.symbol, tpt, elems)
+ case _ =>
+ None
+ }
}
- def apply(x: UnApply): Pattern = {
- x match {
- case UnapplySeq(_, _) => SequenceExtractorPattern(x)
- case _ => ExtractorPattern(x)
- }
+ def apply(x: UnApply): Pattern = x match {
+ case UnapplySeq(container, tpt, elems) =>
+ if (container == ListModule) ListExtractorPattern(x, tpt, elems)
+ else SequenceExtractorPattern(x, elems)
+ case _ =>
+ ExtractorPattern(x)
}
}
@@ -401,7 +388,15 @@ trait Patterns extends ast.TreeDSL {
sealed trait UnapplyPattern extends Pattern {
lazy val UnApply(unfn, args) = tree
- override def subpatternsForVars: List[Pattern] = toPats(args)
+ lazy val Apply(fn, _) = unfn
+ lazy val MethodType(List(arg, _*), _) = fn.tpe
+ protected def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe
+
+ override def necessaryType = arg.tpe
+ override def subpatternsForVars = args match {
+ case List(ArrayValue(elemtpe, elems)) => toPats(elems)
+ case _ => toPats(args)
+ }
def resTypes = analyzer.unapplyTypeList(unfn.symbol, unfn.tpe)
def resTypesString = resTypes match {
@@ -433,23 +428,10 @@ trait Patterns extends ast.TreeDSL {
// returns either a simplification of this pattern or identity.
def simplify(pv: PatternVar): Pattern = this
- def simplify(): Pattern = this simplify null
// the right number of dummies for this pattern
def dummies: List[Pattern] = Nil
- // 8.1.13
- // A pattern p is irrefutable for type T if any of the following applies:
- // 1) p is a variable pattern
- // 2) p is a typed pattern x: T', and T <: T'
- // 3) p is a constructor pattern C(p1,...,pn), the type T is an instance of class C,
- // the primary constructor of type T has argument types T1,...,Tn and and each
- // 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
@@ -460,34 +442,18 @@ trait Patterns extends ast.TreeDSL {
// (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 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 isModule = sym.isModule || tpe.termSymbol.isModule
def isCaseClass = tpe.typeSymbol.isCase
- def isObject = isSymValid && prefix.isStable // XXX not entire logic
+ def isObject = (sym != null) && (sym != NoSymbol) && tpe.prefix.isStable // XXX not entire logic
- def unadorn(t: Tree): Tree = Pattern unadorn t
-
- private def isStar(x: Tree) = cond(unadorn(x)) { case Star(_) => true }
- private def endsStar(xs: List[Tree]) = xs.nonEmpty && isStar(xs.last)
-
- def isStarSequence = isSequence && hasStar
- def isSequence = cond(unadorn(tree)) {
- case ArrayValue(_, _) => true
- }
- def hasStar = cond(unadorn(tree)) {
- case ArrayValue(_, xs) if endsStar(xs) => true
- }
+ def hasStar = false
def setType(tpe: Type): this.type = {
tree setType tpe
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 8969196da1..5f9c2b544a 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -392,7 +392,7 @@ abstract class ExplicitOuter extends InfoTransform
if (guard == EmptyTree) EmptyTree
else {
val guardDef = makeGuardDef(used, guard)
- nguard += transform(guardDef) // building up list of guards
+ nguard += transform(guardDef) // building up list of guards
localTyper typed (Ident(guardDef.symbol) APPLY (used map Ident))
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index fb71c8caae..9b23cf188b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2466,35 +2466,33 @@ trait Typers extends Modes {
/* --- begin unapply --- */
case otpe if inPatternMode(mode) && unapplyMember(otpe).exists =>
- val unapp = unapplyMember(otpe)
- assert(unapp.exists, tree)
- val unappType = otpe.memberType(unapp)
- val argDummyType = pt // was unappArg
- // @S: do we need to memoize this?
- val argDummy = context.owner.newValue(fun.pos, nme.SELECTOR_DUMMY)
- .setFlag(SYNTHETIC)
- .setInfo(argDummyType)
if (args.length > MaxTupleArity)
error(fun.pos, "too many arguments for unapply pattern, maximum = "+MaxTupleArity)
- val arg = Ident(argDummy) setType argDummyType
- val oldArgType = arg.tpe
- if (!isApplicableSafe(List(), unappType, List(arg.tpe), WildcardType)) {
+
+ def freshArgType(tp: Type): (Type, List[Symbol]) = (tp: @unchecked) match {
+ case MethodType(param :: _, _) =>
+ (param.tpe, Nil)
+ case PolyType(tparams, restype) =>
+ val tparams1 = cloneSymbols(tparams)
+ (freshArgType(restype)._1.substSym(tparams, tparams1), tparams1)
+ case OverloadedType(_, _) =>
+ error(fun.pos, "cannot resolve overloaded unapply")
+ (ErrorType, Nil)
+ }
+
+ val unapp = unapplyMember(otpe)
+ val unappType = otpe.memberType(unapp)
+ val argDummy = context.owner.newValue(fun.pos, nme.SELECTOR_DUMMY) setFlag SYNTHETIC setInfo pt
+ val arg = Ident(argDummy) setType pt
+
+ if (!isApplicableSafe(Nil, unappType, List(pt), WildcardType)) {
//Console.println("UNAPP: need to typetest, arg.tpe = "+arg.tpe+", unappType = "+unappType)
- def freshArgType(tp: Type): (Type, List[Symbol]) = tp match {
- case MethodType(params, _) =>
- (params(0).tpe, Nil)
- case PolyType(tparams, restype) =>
- val tparams1 = cloneSymbols(tparams)
- (freshArgType(restype)._1.substSym(tparams, tparams1), tparams1)
- case OverloadedType(_, _) =>
- error(fun.pos, "cannot resolve overloaded unapply")
- (ErrorType, Nil)
- }
val (unappFormal, freeVars) = freshArgType(unappType.skolemizeExistential(context.owner, tree))
val context1 = context.makeNewScope(context.tree, context.owner)
freeVars foreach context1.scope.enter
+
val typer1 = newTyper(context1)
- val pattp = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe)
+ val pattp = typer1.infer.inferTypedPattern(tree.pos, unappFormal, arg.tpe)
// turn any unresolved type variables in freevars into existential skolems
val skolems = freeVars map { fv =>
@@ -2504,8 +2502,7 @@ trait Typers extends Modes {
skolem
}
arg.tpe = pattp.substSym(freeVars, skolems)
- //todo: replace arg with arg.asInstanceOf[inferTypedPattern(unappFormal, arg.tpe)] instead.
- argDummy.setInfo(arg.tpe) // bq: this line fixed #1281. w.r.t. comment ^^^, maybe good enough?
+ argDummy setInfo arg.tpe
}
// setType null is necessary so that ref will be stabilized; see bug 881
@@ -2517,12 +2514,13 @@ trait Typers extends Modes {
val formals1 = formalTypes(formals0, args.length)
if (sameLength(formals1, args)) {
val args1 = typedArgs(args, mode, formals0, formals1)
- if (!isFullyDefined(pt)) assert(false, tree+" ==> "+UnApply(fun1, args1)+", pt = "+pt)
- val itype = glb(List(pt, arg.tpe))
- // restore old type (arg is a dummy tree, just needs to pass typechecking)
- arg.tpe = oldArgType
+ assert(isFullyDefined(pt), tree+" ==> "+UnApply(fun1, args1)+", pt = "+pt)
+
+ val itype = glb(List(pt, arg.tpe))
+ arg.tpe = pt // restore type (arg is a dummy tree, just needs to pass typechecking)
UnApply(fun1, args1) setPos tree.pos setType itype
- } else {
+ }
+ else {
errorTree(tree, "wrong number of arguments for "+treeSymTypeMsg(fun))
}
}
@@ -3890,7 +3888,7 @@ trait Typers extends Modes {
case UnApply(fun, args) =>
val fun1 = typed(fun)
val tpes = formalTypes(unapplyTypeList(fun.symbol, fun1.tpe), args.length)
- val args1 = (args, tpes).zipped map (typedPattern(_, _))
+ val args1 = (args, tpes).zipped map typedPattern
treeCopy.UnApply(tree, fun1, args1) setType pt
case ArrayValue(elemtpt, elems) =>
diff --git a/test/files/pos/bug3972.scala b/test/files/pos/bug3972.scala
new file mode 100644
index 0000000000..5dfc10fcef
--- /dev/null
+++ b/test/files/pos/bug3972.scala
@@ -0,0 +1,11 @@
+object CompilerCrash {
+ def main(args: Array[String]) {
+ args match {
+ case Array("a", a @ _*) => { } // The code compiles fine if this line is commented out or "@ _*" is deleted or this line is swapped for the next line
+ case Array("b") => { } // The code compiles fine if this line is commented out
+ case Array("c", c) => {
+ 0 // The code compiles fine if this line is commented out
+ }
+ }
+ }
+}
diff --git a/test/files/run/bug2800.check b/test/files/run/bug2800.check
new file mode 100644
index 0000000000..546ee52413
--- /dev/null
+++ b/test/files/run/bug2800.check
@@ -0,0 +1,14 @@
+false
+false
+List()
+false
+false
+false
+false
+Vector(1)
+false
+false
+true
+false
+false
+false
diff --git a/test/files/run/bug2800.scala b/test/files/run/bug2800.scala
new file mode 100644
index 0000000000..84d1de0507
--- /dev/null
+++ b/test/files/run/bug2800.scala
@@ -0,0 +1,36 @@
+object Test {
+ def f1 = ("": Any) match { case List(x @ _*) => x ; case _ => false }
+ def f2 = (5: Any) match { case List(x @ _*) => x ; case _ => false }
+ def f3 = (Nil: Any) match { case List(x @ _*) => x ; case _ => false }
+ def f4 = (Array(1): Any) match { case List(x @ _*) => x ; case _ => false }
+
+ def f5 = ("": Any) match { case Array(x @ _*) => x ; case _ => false }
+ def f6 = (5: Any) match { case Array(x @ _*) => x ; case _ => false }
+ def f7 = (Nil: Any) match { case Array(x @ _*) => x ; case _ => false }
+ def f8 = (Array(1): Any) match { case Array(x @ _*) => x ; case _ => false }
+
+ def f9 = ("": Any) match { case x @ List(_*) => x ; case _ => false }
+ def f10 = ("": Any) match { case List(_*) => true ; case _ => false }
+ def f11 = (Nil: Any) match { case List(_*) => true ; case _ => false }
+ def f12 = ("": Any) match { case x @ Array(_*) => x ; case _ => false }
+ def f13 = ("": Any) match { case Array(_*) => true ; case _ => false }
+ def f14 = (Nil: Any) match { case Array(_*) => true ; case _ => false }
+
+
+ def main(args: Array[String]): Unit = {
+ println(f1)
+ println(f2)
+ println(f3)
+ println(f4)
+ println(f5)
+ println(f6)
+ println(f7)
+ println(f8)
+ println(f9)
+ println(f10)
+ println(f11)
+ println(f12)
+ println(f13)
+ println(f14)
+ }
+}
diff --git a/test/pending/run/bug3050.scala b/test/files/run/bug3050.scala
index aaec99ec14..d1f3f13bec 100644
--- a/test/pending/run/bug3050.scala
+++ b/test/files/run/bug3050.scala
@@ -4,6 +4,6 @@ object Test {
try { ("": Any) match { case List(_*) => true } }
catch { case _ => false }
- assert(x == false)
+ assert(!x)
}
}
diff --git a/test/files/run/bug3530.check b/test/files/run/bug3530.check
index 633c15d9d7..1f906680e9 100644
--- a/test/files/run/bug3530.check
+++ b/test/files/run/bug3530.check
@@ -1 +1,12 @@
-Some List
+two
+three
+list: 4
+list: 0
+list: 5
+not a list
+
+two
+three
+list: 4
+list: 0
+list: 5
diff --git a/test/files/run/bug3530.scala b/test/files/run/bug3530.scala
index f2c0034691..f6f7fb4229 100644
--- a/test/files/run/bug3530.scala
+++ b/test/files/run/bug3530.scala
@@ -1,9 +1,35 @@
object Test {
+ def f(x: Any) = println(x match {
+ case List(_, _) => "two"
+ case List(_, _, _) => "three"
+ case xs @ List(_*) => "list: " + xs.length
+ case _ => "not a list"
+ })
+
+ def f2[T](x: List[T]) = println(x match {
+ case List(_, _) => "two"
+ case List(_, _, _) => "three"
+ case List(xs @ _*) => "list: " + xs.length
+ // bug: the default case is marked unreachable
+ // case _ => "not a list"
+ })
+
def main(args: Array[String]) {
- val list = List(1,2,3)
- list match {
- case List(_, _) => println("List with two elements")
- case List(_*) => println("Some List")
- }
+ f(List(1, 2))
+ f(List('a', 'b', 'c'))
+ f(List('a', 'b', 'c', 'd'))
+ f(Nil)
+ f(List(1,2,3,4,5))
+ f(null)
+
+ println
+
+ f2(List(1, 2))
+ f2(List('a', 'b', 'c'))
+ f2(List('a', 'b', 'c', 'd'))
+ f2(Nil)
+ f2(List(1,2,3,4,5))
+ // bug: this NPEs on xs.length
+ // f2(null)
}
} \ No newline at end of file