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

Validate named patterns for case classes #22242

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1654,7 +1654,7 @@ object desugar {
AppliedTypeTree(
TypeTree(defn.throwsAlias.typeRef).withSpan(op.span), tpt :: excepts :: Nil)

private def checkWellFormedTupleElems(elems: List[Tree])(using Context): List[Tree] =
def checkWellFormedTupleElems(elems: List[Tree])(using Context): List[Tree] =
val seen = mutable.Set[Name]()
for case arg @ NamedArg(name, _) <- elems do
if seen.contains(name) then
Expand Down
20 changes: 11 additions & 9 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -199,20 +199,22 @@ object Applications {
else tp :: Nil

private def productUnapplySelectors(tp: Type)(using Context): Option[List[Type]] =
val validatedTupleElements = desugar.checkWellFormedTupleElems(args)

if defn.isProductSubType(tp) then
tryAdaptPatternArgs(args, tp) match
tryAdaptPatternArgs(validatedTupleElements, tp) match
case Some(args1) if isProductMatch(tp, args1.length, pos) =>
args = args1
Some(productSelectorTypes(tp, pos))
case _ => None
else tp.widen.normalized.dealias match
case tp @ defn.NamedTuple(_, tt) =>
tryAdaptPatternArgs(args, tp) match
case Some(args1) =>
args = args1
tt.tupleElementTypes
case _ => None
case _ => None
else tp.widen.normalized.dealias match
case tp @ defn.NamedTuple(_, tt) =>
tryAdaptPatternArgs(validatedTupleElements, tp) match
case Some(args1) =>
args = args1
tt.tupleElementTypes
case _ => None
case _ => None

/** The computed argument types which will be the scutinees of the sub-patterns. */
val argTypes: List[Type] =
Expand Down
16 changes: 16 additions & 0 deletions tests/neg/named-tuples-4.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- Error: tests/neg/named-tuples-4.scala:10:35 -------------------------------------------------------------------------
10 | case PersonCaseClass(name = n, age) => () // error
| ^^^
| Illegal combination of named and unnamed tuple elements
-- Error: tests/neg/named-tuples-4.scala:11:31 -------------------------------------------------------------------------
11 | case PersonCaseClass(name, age = a) => () // error
| ^^^^^^^
| Illegal combination of named and unnamed tuple elements
-- Error: tests/neg/named-tuples-4.scala:15:20 -------------------------------------------------------------------------
15 | case (name = n, age) => () // error
| ^^^
| Illegal combination of named and unnamed tuple elements
-- Error: tests/neg/named-tuples-4.scala:16:16 -------------------------------------------------------------------------
16 | case (name, age = a) => () // error
| ^^^^^^^
| Illegal combination of named and unnamed tuple elements
16 changes: 16 additions & 0 deletions tests/neg/named-tuples-4.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import language.experimental.namedTuples
import scala.annotation.experimental

@experimental object Test:

case class PersonCaseClass(name: String, age: Int)

val personCaseClass = PersonCaseClass("Bob", 33)
personCaseClass match
case PersonCaseClass(name = n, age) => () // error
case PersonCaseClass(name, age = a) => () // error

val person = (name = "Bob", age = 33): (name: String, age: Int)
person match
case (name = n, age) => () // error
case (name, age = a) => () // error
Loading