Skip to content

Commit 61bb394

Browse files
committed
For generic tuples, call Tuples.apply instead of _1/_2/..
1 parent 9e14f5f commit 61bb394

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ object PatternMatcher {
231231
case _ =>
232232
tree.tpe
233233

234-
/** Plan for matching `selectors` against argument patterns `args` */
235-
def matchArgsPlan(selectors: List[Tree], args: List[Tree], onSuccess: Plan): Plan = {
234+
/** Plan for matching `components` against argument patterns `args` */
235+
def matchArgsPlan(components: List[Tree], args: List[Tree], onSuccess: Plan): Plan = {
236236
/* For a case with arguments that have some test on them such as
237237
* ```
238238
* case Foo(1, 2) => someCode
@@ -249,9 +249,9 @@ object PatternMatcher {
249249
* } else ()
250250
* ```
251251
*/
252-
def matchArgsSelectorsPlan(selectors: List[Tree], syms: List[Symbol]): Plan =
253-
selectors match {
254-
case selector :: selectors1 => letAbstract(selector, selector.avoidPatBoundType())(sym => matchArgsSelectorsPlan(selectors1, sym :: syms))
252+
def matchArgsComponentsPlan(components: List[Tree], syms: List[Symbol]): Plan =
253+
components match {
254+
case component :: components1 => letAbstract(component, component.avoidPatBoundType())(sym => matchArgsComponentsPlan(components1, sym :: syms))
255255
case Nil => matchArgsPatternPlan(args, syms.reverse)
256256
}
257257
def matchArgsPatternPlan(args: List[Tree], syms: List[Symbol]): Plan =
@@ -263,7 +263,7 @@ object PatternMatcher {
263263
assert(syms.isEmpty)
264264
onSuccess
265265
}
266-
matchArgsSelectorsPlan(selectors, Nil)
266+
matchArgsComponentsPlan(components, Nil)
267267
}
268268

269269
/** Plan for matching the sequence in `seqSym` against sequence elements `args`.
@@ -326,7 +326,15 @@ object PatternMatcher {
326326
sym.isAllOf(SyntheticCase) && sym.owner.is(Scala2x)
327327

328328
if (isSyntheticScala2Unapply(unapp.symbol) && caseAccessors.length == args.length)
329-
matchArgsPlan(caseAccessors.map(ref(scrutinee).select(_)), args, onSuccess)
329+
def tupleSel(sym: Symbol) = ref(scrutinee).select(sym)
330+
def tupleApp(i: Int) = // manually inlining the call to NonEmptyTuple#apply, because it's an inline method
331+
ref(defn.RuntimeTuplesModule)
332+
.select(defn.RuntimeTuples_apply)
333+
.appliedTo(ref(scrutinee), Literal(Constant(i)))
334+
.cast(args(i).tpe.widen)
335+
val isGenericTuple = defn.isTupleClass(caseClass) && !defn.isTupleNType(tree.tpe)
336+
val components = if isGenericTuple then caseAccessors.indices.toList.map(tupleApp) else caseAccessors.map(tupleSel)
337+
matchArgsPlan(components, args, onSuccess)
330338
else if (unapp.tpe <:< (defn.BooleanType))
331339
TestPlan(GuardTest, unapp, unapp.span, onSuccess)
332340
else

tests/run/i13968.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
object Bar {
2+
def unapply(x: Any): Option[Int *: Int *: EmptyTuple] = Some(1 *: 2 *: Tuple())
3+
}
4+
5+
object Bar23 {
6+
def unapply(x: Any): Option[
7+
Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *:
8+
Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *:
9+
Int *: Int *: Int *: EmptyTuple
10+
] = Some(
11+
1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *:
12+
11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *:
13+
21 *: 22 *: 23 *: Tuple()
14+
)
15+
}
16+
17+
@main def Test() =
18+
"" match
19+
case Bar((a, b)) => assert(a == 1 && b == 2, (a, b))
20+
21+
"" match
22+
case Bar23((
23+
u1, u2, u3, u4, u5, u6, u7, u8, u9, u10,
24+
u11, u12, u13, u14, u15, u16, u17, u18, u19, u20,
25+
u21, u22, u23
26+
)) => assert(u1 == 1 && u23 == 23, (u1, u23))

0 commit comments

Comments
 (0)