Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fail more eagerly when trying to adapt named unapply patterns #22315

Merged
merged 1 commit into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ object Applications {
if (isValid) elemTp else NoType
}

def namedTupleOrProductTypes(tp: Type)(using Context): List[Type] =
if tp.isNamedTupleType then tp.namedTupleElementTypes.map(_(1))
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
Expand Down Expand Up @@ -177,9 +181,14 @@ object Applications {
else fallback

private def tryAdaptPatternArgs(elems: List[untpd.Tree], pt: Type)(using Context): Option[List[untpd.Tree]] =
tryEither[Option[List[untpd.Tree]]]
(Some(desugar.adaptPatternArgs(elems, pt)))
((_, _) => None)
namedTupleOrProductTypes(pt) match
case List(defn.NamedTuple(_, _))=>
// if the product types list is a singleton named tuple, autotupling might be applied, so don't fail eagerly
tryEither[Option[List[untpd.Tree]]]
(Some(desugar.adaptPatternArgs(elems, pt)))
((_, _) => None)
case pts =>
Some(desugar.adaptPatternArgs(elems, pt))

private def getUnapplySelectors(tp: Type)(using Context): List[Type] =
// We treat patterns as product elements if
Expand All @@ -199,7 +208,7 @@ object Applications {
else tp :: Nil

private def productUnapplySelectors(tp: Type)(using Context): Option[List[Type]] =
if defn.isProductSubType(tp) then
if defn.isProductSubType(tp) && args.lengthCompare(productArity(tp)) <= 0 then
tryAdaptPatternArgs(args, tp) match
case Some(args1) if isProductMatch(tp, args1.length, pos) =>
args = args1
Expand Down
30 changes: 30 additions & 0 deletions tests/neg/i22192.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-- Error: tests/neg/i22192.scala:6:12 ----------------------------------------------------------------------------------
6 | case City(iam = n, confused = p) => // error // error
| ^^^^^^^
| No element named `iam` is defined in selector type City
-- Error: tests/neg/i22192.scala:6:21 ----------------------------------------------------------------------------------
6 | case City(iam = n, confused = p) => // error // error
| ^^^^^^^^^^^^
| No element named `confused` is defined in selector type City
-- [E006] Not Found Error: tests/neg/i22192.scala:7:7 ------------------------------------------------------------------
7 | s"$n has a population of $p" // error // error
| ^
| Not found: n
|
| longer explanation available when compiling with `-explain`
-- [E006] Not Found Error: tests/neg/i22192.scala:7:30 -----------------------------------------------------------------
7 | s"$n has a population of $p" // error // error
| ^
| Not found: p
|
| longer explanation available when compiling with `-explain`
-- Error: tests/neg/i22192.scala:10:12 ---------------------------------------------------------------------------------
10 | case Some(iam = n) => // error
| ^^^^^^^
| No element named `iam` is defined in selector type City
-- [E006] Not Found Error: tests/neg/i22192.scala:11:4 -----------------------------------------------------------------
11 | n // error
| ^
| Not found: n
|
| longer explanation available when compiling with `-explain`
11 changes: 11 additions & 0 deletions tests/neg/i22192.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import scala.language.experimental.namedTuples

case class City(name: String, population: Int)

def getCityInfo(city: City) = city match
case City(iam = n, confused = p) => // error // error
s"$n has a population of $p" // error // error

def getCityInfo1(city: Option[City]) = city match
case Some(iam = n) => // error
n // error
20 changes: 20 additions & 0 deletions tests/neg/i22192a.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- Error: tests/neg/i22192a.scala:6:12 ---------------------------------------------------------------------------------
6 | case Some(iam = n) => // error
| ^^^^^^^
| No element named `iam` is defined in selector type (name : String)
-- [E006] Not Found Error: tests/neg/i22192a.scala:7:4 -----------------------------------------------------------------
7 | n // error
| ^
| Not found: n
|
| longer explanation available when compiling with `-explain`
-- Error: tests/neg/i22192a.scala:11:12 --------------------------------------------------------------------------------
11 | case Some(iam = n) => // error
| ^^^^^^^
| No element named `iam` is defined in selector type (name : String, population : Int)
-- [E006] Not Found Error: tests/neg/i22192a.scala:12:4 ----------------------------------------------------------------
12 | n // error
| ^
| Not found: n
|
| longer explanation available when compiling with `-explain`
13 changes: 13 additions & 0 deletions tests/neg/i22192a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import scala.language.experimental.namedTuples

type City = (name: String)

def getCityInfo(city: Option[City]) = city match
case Some(iam = n) => // error
n // error
case _ =>

def getCiryInfo1(city: Option[(name: String, population: Int)]) = city match
case Some(iam = n) => // error
n // error
case _ =>
15 changes: 15 additions & 0 deletions tests/pos/i22192.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import scala.language.experimental.namedTuples

case class City(name: String, population: Int)

def getCityInfo(city: City) = city match
case City(population = p, name = n) =>
s"$n has a population of $p"

def getCityInfo1(city: Option[(name: String)]) = city match
case Some(name = n) => n
case _ =>

def getCityInfo2(city: Option[(name: String, population: Int)]) = city match
case Some(name = n) => n
case _ =>
Loading