summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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