diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/Matrix.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/ParallelMatching.scala | 105 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/PatternBindings.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/matching/Patterns.scala | 180 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 58 | ||||
-rw-r--r-- | test/files/pos/bug3972.scala | 11 | ||||
-rw-r--r-- | test/files/run/bug2800.check | 14 | ||||
-rw-r--r-- | test/files/run/bug2800.scala | 36 | ||||
-rw-r--r-- | test/files/run/bug3050.scala (renamed from test/pending/run/bug3050.scala) | 2 | ||||
-rw-r--r-- | test/files/run/bug3530.check | 13 | ||||
-rw-r--r-- | test/files/run/bug3530.scala | 36 |
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 |