diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index dca2fbeb0dea..4ddd0006dc26 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1667,7 +1667,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 diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 164df6aae5b8..92e0030ae8aa 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -208,20 +208,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) && args.lengthCompare(productArity(tp)) <= 0 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] = diff --git a/tests/neg/named-tuples-4.check b/tests/neg/named-tuples-4.check new file mode 100644 index 000000000000..2ebf9981b93c --- /dev/null +++ b/tests/neg/named-tuples-4.check @@ -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 diff --git a/tests/neg/named-tuples-4.scala b/tests/neg/named-tuples-4.scala new file mode 100644 index 000000000000..60621c57baf5 --- /dev/null +++ b/tests/neg/named-tuples-4.scala @@ -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