@@ -198,6 +198,8 @@ object PatternMatcher {
198198 case object NonNullTest extends Test // scrutinee ne null
199199 case object GuardTest extends Test // scrutinee
200200
201+ val noLengthTest = LengthTest (0 , exact = false )
202+
201203 // ------- Generating plans from trees ------------------------
202204
203205 /** A set of variabes that are known to be not null */
@@ -291,38 +293,67 @@ object PatternMatcher {
291293 /** Plan for matching the sequence in `seqSym` against sequence elements `args`.
292294 * If `exact` is true, the sequence is not permitted to have any elements following `args`.
293295 */
294- def matchElemsPlan (seqSym : Symbol , args : List [Tree ], exact : Boolean , onSuccess : Plan ) = {
295- val selectors = args.indices.toList.map(idx =>
296- ref(seqSym).select(defn.Seq_apply .matchingMember(seqSym.info)).appliedTo(Literal (Constant (idx))))
297- TestPlan (LengthTest (args.length, exact), seqSym, seqSym.span,
298- matchArgsPlan(selectors, args, onSuccess))
299- }
296+ def matchElemsPlan (seqSym : Symbol , args : List [Tree ], lengthTest : LengthTest , onSuccess : Plan ) =
297+ val selectors = args.indices.toList.map: idx =>
298+ ref(seqSym).select(defn.Seq_apply .matchingMember(seqSym.info)).appliedTo(Literal (Constant (idx)))
299+ if lengthTest.len == 0 && lengthTest.exact == false then // redundant test
300+ matchArgsPlan(selectors, args, onSuccess)
301+ else
302+ TestPlan (lengthTest, seqSym, seqSym.span,
303+ matchArgsPlan(selectors, args, onSuccess))
300304
301305 /** Plan for matching the sequence in `getResult` against sequence elements
302- * and a possible last varargs argument `args`.
306+ * `args`. Sequence elements may contain a varargs argument.
307+ * Example:
308+ *
309+ * lst match case Seq(1, xs*, 2, 3) => ...
310+ *
311+ * generates code which is equivalent to:
312+ *
313+ * if lst != null then
314+ * if lst.lengthCompare >= 3 then
315+ * if lst(0) == 1 then
316+ * val x1 = lst.drop(1)
317+ * val xs = x1.dropRight(2)
318+ * val x2 = lst.takeRight(2)
319+ * if x2(0) == 2 && x2(1) == 3 then
320+ * return[matchResult] ...
303321 */
304- def unapplySeqPlan (getResult : Symbol , args : List [Tree ]): Plan = args.lastOption match {
305- case Some (VarArgPattern (arg)) =>
306- val matchRemaining =
307- if (args.length == 1 ) {
308- val toSeq = ref(getResult)
309- .select(defn.Seq_toSeq .matchingMember(getResult.info))
310- letAbstract(toSeq) { toSeqResult =>
311- patternPlan(toSeqResult, arg, onSuccess)
312- }
313- }
314- else {
315- val dropped = ref(getResult)
316- .select(defn.Seq_drop .matchingMember(getResult.info))
317- .appliedTo(Literal (Constant (args.length - 1 )))
318- letAbstract(dropped) { droppedResult =>
319- patternPlan(droppedResult, arg, onSuccess)
320- }
321- }
322- matchElemsPlan(getResult, args.init, exact = false , matchRemaining)
323- case _ =>
324- matchElemsPlan(getResult, args, exact = true , onSuccess)
325- }
322+ def unapplySeqPlan (getResult : Symbol , args : List [Tree ]): Plan =
323+ val (leading, varargAndRest) = args.span:
324+ case VarArgPattern (_) => false
325+ case _ => true
326+ varargAndRest match
327+ case VarArgPattern (arg) :: trailing =>
328+ val remaining =
329+ if leading.isEmpty then
330+ ref(getResult)
331+ .select(defn.Seq_toSeq .matchingMember(getResult.info))
332+ else
333+ ref(getResult)
334+ .select(defn.Seq_drop .matchingMember(getResult.info))
335+ .appliedTo(Literal (Constant (leading.length)))
336+ val matchRemaining =
337+ letAbstract(remaining): remainingResult =>
338+ if trailing.isEmpty then
339+ patternPlan(remainingResult, arg, onSuccess)
340+ else
341+ val seq = ref(remainingResult)
342+ .select(defn.Seq_dropRight .matchingMember(remainingResult.info))
343+ .appliedTo(Literal (Constant (trailing.length)))
344+ letAbstract(seq): seqResult =>
345+ val rest = ref(remainingResult)
346+ .select(defn.Seq_takeRight .matchingMember(remainingResult.info))
347+ .appliedTo(Literal (Constant (trailing.length)))
348+ val matchTrailing =
349+ letAbstract(rest): trailingResult =>
350+ matchElemsPlan(trailingResult, trailing, noLengthTest, onSuccess)
351+ patternPlan(seqResult, arg, matchTrailing)
352+ matchElemsPlan(getResult, leading,
353+ LengthTest (leading.length + trailing.length, exact = false ),
354+ matchRemaining)
355+ case _ =>
356+ matchElemsPlan(getResult, args, LengthTest (args.length, exact = true ), onSuccess)
326357
327358 /** Plan for matching the sequence in `getResult`
328359 *
@@ -491,7 +522,7 @@ object PatternMatcher {
491522 case WildcardPattern () | This (_) =>
492523 onSuccess
493524 case SeqLiteral (pats, _) =>
494- matchElemsPlan(scrutinee, pats, exact = true , onSuccess)
525+ matchElemsPlan(scrutinee, pats, LengthTest (pats.length, exact = true ) , onSuccess)
495526 case _ =>
496527 TestPlan (EqualTest (tree), scrutinee, tree.span, onSuccess)
497528 }
0 commit comments