Skip to content

Commit bce5daf

Browse files
committed
Fix #6849: support irrefutable sequence match
1 parent f824f25 commit bce5daf

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._
@@ -329,10 +329,13 @@ object PatternMatcher {
329329
.map(ref(unappResult).select(_))
330330
matchArgsPlan(selectors, args, onSuccess)
331331
}
332-
else if (isProductSeqMatch(unapp.tpe.widen, args.length, unapp.sourcePos) && isUnapplySeq) {
332+
else if (isUnapplySeq && isProductSeqMatch(unapp.tpe.widen, args.length, unapp.sourcePos)) {
333333
val arity = productArity(unapp.tpe.widen, unapp.sourcePos)
334334
unapplyProductSeqPlan(unappResult, args, arity)
335335
}
336+
else if (isUnapplySeq && unapplySeqTypeElemTp(unapp.tpe.widen.finalResultType).exists) {
337+
unapplySeqPlan(unappResult, args)
338+
}
336339
else {
337340
assert(isGetMatch(unapp.tpe))
338341
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
@@ -285,6 +285,21 @@ object SpaceEngine {
285285
isEmptyTp <:< ConstantType(Constant(true))
286286
}
287287
}
288+
289+
/** Is the unapplySeq irrefutable?
290+
* @param unapp The unapplySeq function reference
291+
*/
292+
def isIrrefutableUnapplySeq(unapp: tpd.Tree, patSize: Int)(implicit ctx: Context): Boolean = {
293+
val unappResult = unapp.tpe.widen.finalResultType
294+
unappResult.isRef(defn.SomeClass) ||
295+
(unapp.symbol.is(Synthetic) && unapp.symbol.owner.linkedClass.is(Case)) || // scala2 compatibility
296+
unapplySeqTypeElemTp(unappResult).exists ||
297+
isProductSeqMatch(unappResult, patSize) ||
298+
{
299+
val isEmptyTp = extractorMemberType(unappResult, nme.isEmpty, unapp.sourcePos)
300+
isEmptyTp <:< ConstantType(Constant(true))
301+
}
302+
}
288303
}
289304

290305
/** Scala implementation of space logic */
@@ -351,9 +366,9 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
351366
else {
352367
val (arity, elemTp, resultTp) = unapplySeqInfo(fun.tpe.widen.finalResultType, fun.sourcePos)
353368
if (elemTp.exists)
354-
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, projectSeq(pats) :: Nil, isIrrefutableUnapply(fun, -1))
369+
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, projectSeq(pats) :: Nil, isIrrefutableUnapplySeq(fun, pats.size))
355370
else
356-
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.take(arity - 1).map(project) :+ projectSeq(pats.drop(arity - 1)), full = true)
371+
Prod(erase(pat.tpe.stripAnnots), fun.tpe, fun.symbol, pats.take(arity - 1).map(project) :+ projectSeq(pats.drop(arity - 1)), isIrrefutableUnapplySeq(fun, pats.size))
357372
}
358373
else
359374
Prod(erase(pat.tpe.stripAnnots), erase(fun.tpe), fun.symbol, pats.map(project), isIrrefutableUnapply(fun, pats.length))

0 commit comments

Comments
 (0)