Skip to content

Commit da39571

Browse files
committed
Fix exhaustivity check
1 parent 00857dd commit da39571

File tree

2 files changed

+40
-18
lines changed

2 files changed

+40
-18
lines changed

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,25 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
335335
case Bind(_, pat) => project(pat)
336336
case SeqLiteral(pats, _) => projectSeq(pats)
337337
case UnApply(fun, _, pats) =>
338-
if (fun.symbol.name == nme.unapplySeq)
339-
if (fun.symbol.owner == scalaSeqFactoryClass)
340-
projectSeq(pats)
341-
else
338+
if (fun.symbol.owner == scalaSeqFactoryClass && fun.symbol.name == nme.unapplySeq)
339+
projectSeq(pats)
340+
else {
341+
var tp = fun.tpe.widen.finalResultType
342+
var arity = productArity(tp, fun.sourcePos)
343+
if (arity <= 0) {
344+
tp = fun.tpe.widen.finalResultType.select(nme.get).finalResultType.widen
345+
if (pats.length == 1)
346+
return Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.map(project), irrefutable(fun))
347+
arity = productSelectorTypes(tp, fun.sourcePos).size
348+
}
349+
350+
if (arity > 0 && arity != pats.length)
351+
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.take(arity - 1).map(project) :+ projectSeq(pats.drop(arity - 1)), irrefutable(fun))
352+
else if (arity <= 0 && unapplySeqTypeElemTp(tp).exists)
342353
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, projectSeq(pats) :: Nil, irrefutable(fun))
343-
else
344-
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.map(project), irrefutable(fun))
354+
else
355+
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.map(project), irrefutable(fun))
356+
}
345357
case Typed(pat @ UnApply(_, _, _), _) => project(pat)
346358
case Typed(expr, tpt) =>
347359
Typ(erase(expr.tpe.stripAnnots), true)
@@ -424,17 +436,27 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
424436
List()
425437
else {
426438
val isUnapplySeq = unappSym.name == nme.unapplySeq
427-
if (productArity(mt.finalResultType, unappSym.sourcePos) > 0 && !isUnapplySeq) {
428-
productSelectors(mt.finalResultType).take(argLen)
429-
.map(_.info.asSeenFrom(mt.finalResultType, mt.resultType.classSymbol).widenExpr)
439+
val arity = productArity(mt.finalResultType, unappSym.sourcePos)
440+
if (arity > 0 && !isUnapplySeq) {
441+
if (arity != argLen) {
442+
val sels = productSeqSelectors(mt.finalResultType, arity, unappSym.sourcePos)
443+
sels.init :+ scalaListType.appliedTo(sels.last)
444+
}
445+
else
446+
productSelectors(mt.finalResultType)
447+
.map(_.info.asSeenFrom(mt.finalResultType, mt.resultType.classSymbol).widenExpr)
430448
}
431449
else {
432450
val resTp = mt.finalResultType.select(nme.get).finalResultType.widen
433-
if (isUnapplySeq) scalaListType.appliedTo(resTp.argTypes.head) :: Nil
434-
else if (argLen == 0) Nil
435-
else if (isProductMatch(resTp, argLen))
451+
val arity = productArity(resTp, unappSym.sourcePos)
452+
if (isUnapplySeq && arity < 0) scalaListType.appliedTo(resTp.argTypes.head) :: Nil
453+
else if (argLen == 1) resTp :: Nil
454+
else if (arity > 0 && arity != argLen) {
455+
val sels = productSeqSelectors(resTp, arity, unappSym.sourcePos)
456+
sels.init :+ scalaListType.appliedTo(sels.last)
457+
}
458+
else
436459
productSelectors(resTp).map(_.info.asSeenFrom(resTp, resTp.classSymbol).widenExpr)
437-
else resTp :: Nil
438460
}
439461
}
440462

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,15 @@ object Applications {
133133
if (args.length > 1 && !(tp.derivesFrom(defn.SeqClass))) {
134134
val sels = productSelectorTypes(tp, pos)
135135
if (sels.length == args.length) sels
136-
else if (isProductSeqMatch(tp, args.length, pos)) productSeqSelectors(tp, args, pos)
136+
else if (isProductSeqMatch(tp, args.length, pos)) productSeqSelectors(tp, args.length, pos)
137137
else tp :: Nil
138138
} else tp :: Nil
139139

140-
def productSeqSelectors(tp: Type, args: List[untpd.Tree], pos: SourcePosition)(implicit ctx: Context): List[Type] = {
140+
def productSeqSelectors(tp: Type, argsNum: Int, pos: SourcePosition)(implicit ctx: Context): List[Type] = {
141141
val selTps = productSelectorTypes(tp, pos)
142142
val arity = selTps.length
143143
val elemTp = unapplySeqTypeElemTp(selTps.last)
144-
(0 until args.length).map(i => if (i < arity - 1) selTps(i) else elemTp).toList
144+
(0 until argsNum).map(i => if (i < arity - 1) selTps(i) else elemTp).toList
145145
}
146146

147147
def unapplyArgs(unapplyResult: Type, unapplyFn: Tree, args: List[untpd.Tree], pos: SourcePosition)(implicit ctx: Context): List[Type] = {
@@ -159,7 +159,7 @@ object Applications {
159159
if (isGetMatch(unapplyResult, pos)) {
160160
val elemTp = unapplySeqTypeElemTp(getTp)
161161
if (elemTp.exists) args.map(Function.const(elemTp))
162-
else if (isProductSeqMatch(getTp, args.length, pos)) productSeqSelectors(getTp, args, pos)
162+
else if (isProductSeqMatch(getTp, args.length, pos)) productSeqSelectors(getTp, args.length, pos)
163163
else fail
164164
}
165165
else fail
@@ -169,7 +169,7 @@ object Applications {
169169
if (isProductMatch(unapplyResult, args.length, pos))
170170
productSelectorTypes(unapplyResult, pos)
171171
else if (isProductSeqMatch(unapplyResult, args.length, pos))
172-
productSeqSelectors(unapplyResult, args, pos)
172+
productSeqSelectors(unapplyResult, args.length, pos)
173173
else if (isGetMatch(unapplyResult, pos))
174174
getUnapplySelectors(getTp, args, pos)
175175
else if (unapplyResult.widenSingleton isRef defn.BooleanClass)

0 commit comments

Comments
 (0)