diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 5ecf1601db8a..688e582e025f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -153,16 +153,18 @@ object Applications { def tupleComponentTypes(tp: Type)(using Context): List[Type] = tp.widenExpr.dealias.normalized match - case tp: AppliedType => - if defn.isTupleClass(tp.tycon.typeSymbol) then - tp.args - else if tp.tycon.derivesFrom(defn.PairClass) then - val List(head, tail) = tp.args - head :: tupleComponentTypes(tail) - else + case defn.NamedTuple(_, vals) => + tupleComponentTypes(vals) + case tp: AppliedType => + if defn.isTupleClass(tp.tycon.typeSymbol) then + tp.args + else if tp.tycon.derivesFrom(defn.PairClass) then + val List(head, tail) = tp.args + head :: tupleComponentTypes(tail) + else + Nil + case _ => Nil - case _ => - Nil def productArity(tp: Type, errorPos: SrcPos = NoSourcePosition)(using Context): Int = if (defn.isProductSubType(tp)) productSelectorTypes(tp, errorPos).size else -1 @@ -2585,7 +2587,7 @@ trait Applications extends Compatibility { /** Is `formal` a product type which is elementwise compatible with `params`? */ def ptIsCorrectProduct(formal: Type, params: List[untpd.ValDef])(using Context): Boolean = isFullyDefined(formal, ForceDegree.flipBottom) - && defn.isProductSubType(formal) + && (defn.isProductSubType(formal) || formal.isNamedTupleType) && tupleComponentTypes(formal).corresponds(params): (argType, param) => param.tpt.isEmpty || argType.widenExpr <:< typedAheadType(param.tpt).tpe diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c2e65337a7fe..e5841a3de768 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1943,8 +1943,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val firstFormal = protoFormals.head.loBound if ptIsCorrectProduct(firstFormal, params) then val isGenericTuple = - firstFormal.derivesFrom(defn.TupleClass) - && !defn.isTupleClass(firstFormal.typeSymbol) + firstFormal.isNamedTupleType + || (firstFormal.derivesFrom(defn.TupleClass) + && !defn.isTupleClass(firstFormal.typeSymbol)) desugared = desugar.makeTupledFunction(params, fnBody, isGenericTuple) else if protoFormals.length > 1 && params.length == 1 then def isParamRef(scrut: untpd.Tree): Boolean = scrut match diff --git a/tests/run/i23440.scala b/tests/run/i23440.scala new file mode 100644 index 000000000000..58885bd3bf05 --- /dev/null +++ b/tests/run/i23440.scala @@ -0,0 +1,12 @@ +@main def Test: Unit = + List((42, "asdads")) match + case List((a, b)) => 1 + List((a = 42, b = "asdads")) match + case List((a, b)) => 1 + val tuple_list = List((42, "asdads")) + tuple_list.map((a, b) => println(s"$a $b")) + val named_tuple_list = List((a = 42, b = "asdads")) + named_tuple_list.foreach((a, b) => println(s"$a $b")) + named_tuple_list.foreach { case (a, b) => println(s"$a $b") } + val l = Seq.empty[(name: String, age: Int)] + l.map((name, i) => name + i) \ No newline at end of file