Skip to content

Commit

Permalink
For generic tuples, call Tuples.apply instead of _1/_2/..
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Jan 19, 2022
1 parent 9e14f5f commit 31dfa0f
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
19 changes: 12 additions & 7 deletions compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala
Expand Up @@ -231,8 +231,8 @@ object PatternMatcher {
case _ =>
tree.tpe

/** Plan for matching `selectors` against argument patterns `args` */
def matchArgsPlan(selectors: List[Tree], args: List[Tree], onSuccess: Plan): Plan = {
/** Plan for matching `components` against argument patterns `args` */
def matchArgsPlan(components: List[Tree], args: List[Tree], onSuccess: Plan): Plan = {
/* For a case with arguments that have some test on them such as
* ```
* case Foo(1, 2) => someCode
Expand All @@ -249,9 +249,9 @@ object PatternMatcher {
* } else ()
* ```
*/
def matchArgsSelectorsPlan(selectors: List[Tree], syms: List[Symbol]): Plan =
selectors match {
case selector :: selectors1 => letAbstract(selector, selector.avoidPatBoundType())(sym => matchArgsSelectorsPlan(selectors1, sym :: syms))
def matchArgsComponentsPlan(components: List[Tree], syms: List[Symbol]): Plan =
components match {
case component :: components1 => letAbstract(component, component.avoidPatBoundType())(sym => matchArgsComponentsPlan(components1, sym :: syms))
case Nil => matchArgsPatternPlan(args, syms.reverse)
}
def matchArgsPatternPlan(args: List[Tree], syms: List[Symbol]): Plan =
Expand All @@ -263,7 +263,7 @@ object PatternMatcher {
assert(syms.isEmpty)
onSuccess
}
matchArgsSelectorsPlan(selectors, Nil)
matchArgsComponentsPlan(components, Nil)
}

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

if (isSyntheticScala2Unapply(unapp.symbol) && caseAccessors.length == args.length)
matchArgsPlan(caseAccessors.map(ref(scrutinee).select(_)), args, onSuccess)
def tupleSel(sym: Symbol) = ref(scrutinee).select(sym)
def tupleApp(i: Int) = // manually inlining the call to NonEmptyTuple#apply, because it's an inline method
ref(defn.RuntimeTuplesModule).select(defn.RuntimeTuples_apply).appliedTo(ref(scrutinee), Literal(Constant(i)))
val isGenericTuple = tree.tpe.derivesFrom(defn.PairClass)
val components = if isGenericTuple then caseAccessors.indices.toList.map(tupleApp) else caseAccessors.map(tupleSel)
matchArgsPlan(components, args, onSuccess)
else if (unapp.tpe <:< (defn.BooleanType))
TestPlan(GuardTest, unapp, unapp.span, onSuccess)
else
Expand Down
26 changes: 26 additions & 0 deletions tests/run/i13968.scala
@@ -0,0 +1,26 @@
object Bar {
def unapply(x: Any): Option[Int *: Int *: EmptyTuple] = Some(1 *: 2 *: Tuple())
}

object Bar23 {
def unapply(x: Any): Option[
Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *:
Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *:
Int *: Int *: Int *: EmptyTuple
] = Some(
1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *:
11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *:
21 *: 22 *: 23 *: Tuple()
)
}

@main def Test() =
"" match
case Bar((a, b)) => assert(a == 1 && b == 2, (a, b))

"" match
case Bar23((
u1, u2, u3, u4, u5, u6, u7, u8, u9, u10,
u11, u12, u13, u14, u15, u16, u17, u18, u19, u20,
u21, u22, u23
)) => assert(u1 == 1 && u23 == 23, (u1, u23))

0 comments on commit 31dfa0f

Please sign in to comment.