From d10d0f10f898d8387dd04c74e241f8ed501f4962 Mon Sep 17 00:00:00 2001 From: Yoonjae Jeon Date: Tue, 26 May 2026 16:52:26 +0900 Subject: [PATCH 1/2] Handle generic tuple in getMatch branch --- .../tools/dotc/transform/PatternMatcher.scala | 27 ++++++++++++------- tests/pos/i25663.scala | 5 ++++ 2 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 tests/pos/i25663.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 481b3651793c..a357bb61ef9f 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -359,10 +359,9 @@ object PatternMatcher { * * `getResult` is a product, where the last element is a sequence of elements. */ - def unapplyProductSeqPlan(getResult: Symbol, args: List[Tree], arity: Int): Plan = { + def unapplyProductSeqPlan(selectors: List[Tree], args: List[Tree]): Plan = { + val arity = selectors.length assert(arity <= args.size + 1) - val selectors = productSelectors(getResult.info).map(ref(getResult).select(_)) - val matchSeq = letAbstract(selectors.last) { seqResult => unapplySeqPlan(seqResult, args.drop(arity - 1)) @@ -415,9 +414,9 @@ object PatternMatcher { else if isUnapplySeq && unapplySeqTypeElemTp(unappType.finalResultType).exists then unapplySeqPlan(unappResult, args) else if isUnapplySeq && isProductSeqMatch(unappType, args.length, unapp.srcPos) then - val arity = productArity(unappType, unapp.srcPos) - unapplyProductSeqPlan(unappResult, args, arity) - else if unappResult.info <:< defn.NonEmptyTupleTypeRef then + val selectors = productSelectors(unappType).map(ref(unappResult).select(_)) + unapplyProductSeqPlan(selectors, args) + else if unappResult.info <:< defn.NonEmptyTupleTypeRef then val components = (0 until unappResult.denot.info.tupleElementTypes.getOrElse(Nil).length) .toList.map(tupleApp(_, ref(unappResult))) @@ -426,12 +425,20 @@ object PatternMatcher { assert(isGetMatch(unappType)) val argsPlan = { val get = getOfGetMatch(ref(unappResult)) - val arity = productArity(get.tpe.stripNamedTuple, unapp.srcPos) if (isUnapplySeq) letAbstract(get) { getResult => - if unapplySeqTypeElemTp(get.tpe).exists - then unapplySeqPlan(getResult, args) - else unapplyProductSeqPlan(getResult, args, arity) + if unapplySeqTypeElemTp(get.tpe).exists then + unapplySeqPlan(getResult, args) + else if isGenericTuple(getResult.info) then + val elemTypes = getResult.info.tupleElementTypes.getOrElse(Nil) + val selectors = elemTypes.zipWithIndex.map { (tp, i) => + tupleApp(i, ref(getResult)).cast(tp) + } + unapplyProductSeqPlan(selectors, args) + else { + val selectors = productSelectors(getResult.info).map(ref(getResult).select(_)) + unapplyProductSeqPlan(selectors, args) + } } else letAbstract(get) { getResult => diff --git a/tests/pos/i25663.scala b/tests/pos/i25663.scala new file mode 100644 index 000000000000..fbbddb8e62ee --- /dev/null +++ b/tests/pos/i25663.scala @@ -0,0 +1,5 @@ +object Foo: + def unapplySeq(f: Int): Option[String *: Seq[Int] *: EmptyTuple] = ??? + +def foo(f: Int) = f match + case Foo(name, ns*) => ??? From 989866e3aa9899115927cb277f862a71e28bd1d2 Mon Sep 17 00:00:00 2001 From: Yoonjae Jeon Date: Tue, 26 May 2026 17:14:33 +0900 Subject: [PATCH 2/2] fmt --- compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index a357bb61ef9f..461569388cbb 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -416,7 +416,7 @@ object PatternMatcher { else if isUnapplySeq && isProductSeqMatch(unappType, args.length, unapp.srcPos) then val selectors = productSelectors(unappType).map(ref(unappResult).select(_)) unapplyProductSeqPlan(selectors, args) - else if unappResult.info <:< defn.NonEmptyTupleTypeRef then + else if unappResult.info <:< defn.NonEmptyTupleTypeRef then val components = (0 until unappResult.denot.info.tupleElementTypes.getOrElse(Nil).length) .toList.map(tupleApp(_, ref(unappResult)))