Skip to content

Commit 081cd06

Browse files
committed
Fix #6849: support irrefutable sequence match
1 parent 08cf458 commit 081cd06

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import collection.mutable
88
import Symbols._, Contexts._, Types._, StdNames._, NameOps._
99
import ast.Trees._
1010
import util.Spans._
11-
import typer.Applications.{isProductMatch, isGetMatch, isProductSeqMatch, productSelectors, productArity}
11+
import typer.Applications.{isProductMatch, isGetMatch, isProductSeqMatch, productSelectors, productArity, unapplySeqTypeElemTp}
1212
import SymUtils._
1313
import Flags._, Constants._
1414
import Decorators._
@@ -323,10 +323,13 @@ object PatternMatcher {
323323
.map(ref(unappResult).select(_))
324324
matchArgsPlan(selectors, args, onSuccess)
325325
}
326-
else if (isProductSeqMatch(unapp.tpe.widen, args.length, unapp.sourcePos) && isUnapplySeq) {
326+
else if (isUnapplySeq && isProductSeqMatch(unapp.tpe.widen, args.length, unapp.sourcePos)) {
327327
val arity = productArity(unapp.tpe.widen, unapp.sourcePos)
328328
unapplyProductSeqPlan(unappResult, args, arity)
329329
}
330+
else if (isUnapplySeq && unapplySeqTypeElemTp(unapp.tpe.widen.finalResultType).exists) {
331+
unapplySeqPlan(unappResult, args)
332+
}
330333
else {
331334
assert(isGetMatch(unapp.tpe))
332335
val argsPlan = {

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,21 @@ object SpaceEngine {
295295
isEmptyTp <:< ConstantType(Constant(true))
296296
}
297297
}
298+
299+
/** Is the unapplySeq irrefutable?
300+
* @param unapp The unapplySeq function reference
301+
*/
302+
def isIrrefutableUnapplySeq(unapp: tpd.Tree, patSize: Int)(implicit ctx: Context): Boolean = {
303+
val unappResult = unapp.tpe.widen.finalResultType
304+
unappResult.isRef(defn.SomeClass) ||
305+
(unapp.symbol.is(Synthetic) && unapp.symbol.owner.linkedClass.is(Case)) || // scala2 compatibility
306+
unapplySeqTypeElemTp(unappResult).exists ||
307+
isProductSeqMatch(unappResult, patSize) ||
308+
{
309+
val isEmptyTp = extractorMemberType(unappResult, nme.isEmpty, unapp.sourcePos)
310+
isEmptyTp <:< ConstantType(Constant(true))
311+
}
312+
}
298313
}
299314

300315
/** Scala implementation of space logic */
@@ -348,9 +363,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
348363
else {
349364
val (arity, elemTp, resultTp) = unapplySeqInfo(fun.tpe.widen.finalResultType, fun.sourcePos)
350365
if (elemTp.exists)
351-
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, projectSeq(pats) :: Nil, isIrrefutableUnapply(fun, -1))
366+
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, projectSeq(pats) :: Nil, isIrrefutableUnapplySeq(fun, pats.size))
352367
else
353-
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.take(arity - 1).map(project) :+ projectSeq(pats.drop(arity - 1)), full = true)
368+
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.take(arity - 1).map(project) :+ projectSeq(pats.drop(arity - 1)), isIrrefutableUnapplySeq(fun, pats.size))
354369
}
355370
else
356371
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.map(project), isIrrefutableUnapply(fun, pats.length))

0 commit comments

Comments
 (0)