From 248b9f1bee04e79c965d0c9498cea6ad9333be05 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Thu, 12 Jun 2025 18:44:18 +0200 Subject: [PATCH 1/3] Check for error type before checking members of product in getUnapplySelectors --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 2 +- tests/pos/i23156.scala | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i23156.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index bf9ebf7b9926..d3656e6eab38 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -218,7 +218,7 @@ object Applications { val isProduct = args match case x :: xs => x.isInstanceOf[untpd.NamedArg] || xs.nonEmpty case _ => false - if isProduct && !tp.derivesFrom(defn.SeqClass) then + if isProduct && !tp.derivesFrom(defn.SeqClass) && !tp.isError then productUnapplySelectors(tp).getOrElse: // There are unapplys with return types which have `get` and `_1, ..., _n` // as members, but which are not subtypes of Product. So `productUnapplySelectors` diff --git a/tests/pos/i23156.scala b/tests/pos/i23156.scala new file mode 100644 index 000000000000..35edef49bcc4 --- /dev/null +++ b/tests/pos/i23156.scala @@ -0,0 +1,6 @@ +object Unpack { + (1, 2) match { + case Unpack(first, _) => first + } + def unapply(e: (Int, Int)): Option[T] = ??? +} \ No newline at end of file From af5d91129efd45883b8279fe0225540514bf2191 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Thu, 12 Jun 2025 18:53:25 +0200 Subject: [PATCH 2/3] move test to neg --- tests/{pos => neg}/i23156.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{pos => neg}/i23156.scala (57%) diff --git a/tests/pos/i23156.scala b/tests/neg/i23156.scala similarity index 57% rename from tests/pos/i23156.scala rename to tests/neg/i23156.scala index 35edef49bcc4..c8f01ab16857 100644 --- a/tests/pos/i23156.scala +++ b/tests/neg/i23156.scala @@ -2,5 +2,5 @@ object Unpack { (1, 2) match { case Unpack(first, _) => first } - def unapply(e: (Int, Int)): Option[T] = ??? + def unapply(e: (Int, Int)): Option[T] = ??? // error } \ No newline at end of file From 4c2f6b3666440a3beceec0062bf426ac66da45eb Mon Sep 17 00:00:00 2001 From: aherlihy Date: Fri, 13 Jun 2025 13:12:49 +0200 Subject: [PATCH 3/3] Move error check into productSelectorTypes --- compiler/src/dotty/tools/dotc/typer/Applications.scala | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index d3656e6eab38..d03f7e7f8a56 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -131,8 +131,11 @@ object Applications { else productSelectorTypes(tp, NoSourcePosition) def productSelectorTypes(tp: Type, errorPos: SrcPos)(using Context): List[Type] = { - val sels = for (n <- Iterator.from(0)) yield extractorMemberType(tp, nme.selectorName(n), errorPos) - sels.takeWhile(_.exists).toList + if tp.isError then + Nil + else + val sels = for (n <- Iterator.from(0)) yield extractorMemberType(tp, nme.selectorName(n), errorPos) + sels.takeWhile(_.exists).toList } def tupleComponentTypes(tp: Type)(using Context): List[Type] = @@ -218,7 +221,7 @@ object Applications { val isProduct = args match case x :: xs => x.isInstanceOf[untpd.NamedArg] || xs.nonEmpty case _ => false - if isProduct && !tp.derivesFrom(defn.SeqClass) && !tp.isError then + if isProduct && !tp.derivesFrom(defn.SeqClass) then productUnapplySelectors(tp).getOrElse: // There are unapplys with return types which have `get` and `_1, ..., _n` // as members, but which are not subtypes of Product. So `productUnapplySelectors`