Skip to content

Commit 1d3a34b

Browse files
committed
Reprioritise seq-match over product-seq-match
Prioritise a seq match from the result of a get, over a product-seq match
1 parent b1d1fe8 commit 1d3a34b

File tree

4 files changed

+84
-28
lines changed

4 files changed

+84
-28
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,9 @@ object PatternMatcher {
377377
val arity = productArity(get.tpe, unapp.srcPos)
378378
if (isUnapplySeq)
379379
letAbstract(get) { getResult =>
380-
if (arity > 0) unapplyProductSeqPlan(getResult, args, arity)
381-
else unapplySeqPlan(getResult, args)
380+
if unapplySeqTypeElemTp(get.tpe).exists
381+
then unapplySeqPlan(getResult, args)
382+
else unapplyProductSeqPlan(getResult, args, arity)
382383
}
383384
else
384385
letAbstract(get) { getResult =>

tests/pos/i19219.orig.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
object Test:
2+
class Custom extends scala.Product1[String]:
3+
def length: Int = ???
4+
def apply(i: Int): Boolean = ???
5+
def drop(n: Int): scala.Seq[Boolean] = ???
6+
def toSeq: scala.Seq[Boolean] = ???
7+
8+
def canEqual(that: Any): Boolean = ???
9+
10+
val _1: String = ???
11+
val _2: String = ???
12+
val _3: Seq[String] = ???
13+
14+
class Unapplied:
15+
def isEmpty: Boolean = ???
16+
def get: Custom = ???
17+
18+
object A:
19+
def unapplySeq(i: Int): Unapplied = ???
20+
21+
val A(rest: _*) = 1

tests/pos/i19220.orig.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
object Test:
2+
class Custom extends scala.Product1[String]:
3+
def length: Int = ???
4+
def apply(i: Int): Boolean = ???
5+
def drop(n: Int): scala.Seq[Boolean] = ???
6+
def toSeq: scala.Seq[Boolean] = ???
7+
8+
def canEqual(that: Any): Boolean = ???
9+
10+
val _1: String = ???
11+
val _3: Seq[String] = ???
12+
13+
class Unapplied:
14+
def isEmpty: Boolean = ???
15+
def get: Custom = ???
16+
17+
object A:
18+
def unapplySeq(i: Int): Unapplied = ???
19+
20+
val A(a, rest*) = 1

tests/pos/i19221.scala

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,49 @@
1-
class T1
1+
// Product component types, and the sequence element type
2+
final class A; final class B; final class C
3+
final class E
24

3-
class P1
4-
final class P2
5-
class P3
5+
// Conforms to both sequence matches and product sequence matches
6+
class Both extends Product1[A]:
7+
def length: Int = toSeq.length
8+
def apply(i: Int): E = toSeq.apply(i)
9+
def drop(n: Int): Seq[E] = toSeq.drop(n)
10+
def toSeq: Seq[E] = Seq(new E, new E)
611

7-
class E1
8-
class E2 extends E1
9-
class E3 extends E1
12+
def canEqual(that: Any) = that.isInstanceOf[Both @unchecked]
1013

11-
object VarExt:
12-
def unapplySeq(t1: T1): U1 = new U1
14+
val _1: A = new A
15+
val _2: B = new B
16+
val _3: Seq[C] = Seq(new C)
1317

14-
class U1 extends Product1[P1]:
15-
def canEqual(that: Any): Boolean = ???
18+
// Like Both, but with a missing _2
19+
class AlmostBoth extends Product1[A]:
20+
def length: Int = toSeq.length
21+
def apply(i: Int): E = toSeq.apply(i)
22+
def drop(n: Int): Seq[E] = toSeq.drop(n)
23+
def toSeq: Seq[E] = Seq(new E, new E)
1624

17-
val _1: P1 = new P1
18-
val _2: P2 = new P2
19-
val _3: Seq[P3] = Seq(new P3)
25+
def canEqual(that: Any) = that.isInstanceOf[AlmostBoth @unchecked]
2026

21-
def length: Int = ???
22-
def apply(i: Int): E1 = ???
23-
def drop(n: Int): Seq[E2] = ???
24-
def toSeq: Seq[E3] = ???
27+
val _1: A = new A
28+
val _3: Seq[C] = Seq(new C)
2529

26-
class Test:
27-
def m1(t1: T1): Unit = t1 match
28-
case VarExt(c1, cs*) => // CCE: class P1 cannot be cast to class E1
29-
val e1: E1 = c1
30-
val e1s: Seq[E1] = cs
30+
// An extractor result holder, to return Both or BothAlmost
31+
class GetBoth { def isEmpty: Boolean = false; def get = new Both }
32+
class GetAlmostBoth { def isEmpty: Boolean = false; def get = new AlmostBoth }
3133

32-
object Main:
33-
def main(args: Array[String]): Unit =
34-
new Test().m1(new T1)
34+
// The extractors
35+
object Both { def unapplySeq(x: Any): Both = new Both }
36+
object AlmostBoth { def unapplySeq(x: Any): Both = new Both }
37+
object GetBoth { def unapplySeq(x: Any): GetBoth = new GetBoth }
38+
object GetAlmostBoth { def unapplySeq(x: Any): GetAlmostBoth = new GetAlmostBoth }
3539

40+
class Test:
41+
def t1a(x: Any): Seq[E] = x match { case Both(es*) => es }
42+
def t1b(x: Any): Seq[E] = x match { case AlmostBoth(es*) => es }
43+
def t1c(x: Any): Seq[E] = x match { case GetBoth(es*) => es }
44+
def t1d(x: Any): Seq[E] = x match { case GetAlmostBoth(es*) => es }
45+
46+
def t2a(x: Any): (E, Seq[E]) = x match { case Both(e, es*) => (e, es) }
47+
def t2b(x: Any): (E, Seq[E]) = x match { case AlmostBoth(e, es*) => (e, es) }
48+
def t2c(x: Any): (E, Seq[E]) = x match { case GetBoth(e, es*) => (e, es) }
49+
def t2d(x: Any): (E, Seq[E]) = x match { case GetAlmostBoth(e, es*) => (e, es) }

0 commit comments

Comments
 (0)