From f0581771464aea978184601ac5b6ae88c80d97dd Mon Sep 17 00:00:00 2001 From: aherlihy Date: Fri, 24 Jan 2025 16:20:36 +0100 Subject: [PATCH 1/3] Special case NamedTuple.From for arguments derived from Tuple --- compiler/src/dotty/tools/dotc/core/TypeEval.scala | 9 +++++++++ tests/pos/i22036.scala | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/pos/i22036.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeEval.scala b/compiler/src/dotty/tools/dotc/core/TypeEval.scala index 4d5496cff880..f96ba9a7aadb 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeEval.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeEval.scala @@ -111,6 +111,15 @@ object TypeEval: nestedPairs(fieldLabels) :: nestedPairs(fieldTypes) :: Nil else arg.widenDealias match case arg @ defn.NamedTuple(_, _) => Some(arg) + case arg if arg.derivesFrom(defn.TupleClass) => + val fieldTypesOpt = tupleElementTypes(arg) + fieldTypesOpt match + case Some(fieldTypes) => + val fieldLabels = fieldTypes.zipWithIndex.map((_, i) => ConstantType(Constant(s"_$i"))) + Some: + defn.NamedTupleTypeRef.appliedTo: + nestedPairs(fieldLabels) :: nestedPairs(fieldTypes) :: Nil + case _ => None case _ => None def constantFold1[T](extractor: Type => Option[T], op: T => Any): Option[Type] = diff --git a/tests/pos/i22036.scala b/tests/pos/i22036.scala new file mode 100644 index 000000000000..e981722d895d --- /dev/null +++ b/tests/pos/i22036.scala @@ -0,0 +1,13 @@ +//> using options -experimental -language:experimental.namedTuples +import language.experimental.namedTuples + +type Foo[T] = T +val x: NamedTuple.From[Tuple.Map[(Int, Int), Foo]] = ??? +val res = x._1 + +type Z = NamedTuple.From[(Foo[Int], Foo[Int])] +val x2: Z = ??? +val res2 = x2._1 + +val x3: Foo[NamedTuple.From[Tuple.Map[(Int, Int), Foo]]] = ??? +val res3 = x3._1 From 6023e4779c170aa4771f8c1dd49414efad6acc6d Mon Sep 17 00:00:00 2001 From: anna herlihy Date: Mon, 27 Jan 2025 09:52:37 +0100 Subject: [PATCH 2/3] Update compiler/src/dotty/tools/dotc/core/TypeEval.scala Co-authored-by: Guillaume Martres --- compiler/src/dotty/tools/dotc/core/TypeEval.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeEval.scala b/compiler/src/dotty/tools/dotc/core/TypeEval.scala index f96ba9a7aadb..9fd8b9952e8f 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeEval.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeEval.scala @@ -115,7 +115,7 @@ object TypeEval: val fieldTypesOpt = tupleElementTypes(arg) fieldTypesOpt match case Some(fieldTypes) => - val fieldLabels = fieldTypes.zipWithIndex.map((_, i) => ConstantType(Constant(s"_$i"))) + val fieldLabels = (for i <- 1 to fieldTypes.length yield ConstantType(Constant(s"_$i")))).toList Some: defn.NamedTupleTypeRef.appliedTo: nestedPairs(fieldLabels) :: nestedPairs(fieldTypes) :: Nil From f6e23fc8f6dd61f91575b205c308baf83bd7f979 Mon Sep 17 00:00:00 2001 From: aherlihy Date: Mon, 27 Jan 2025 10:05:47 +0100 Subject: [PATCH 3/3] more tests --- compiler/src/dotty/tools/dotc/core/TypeEval.scala | 2 +- tests/pos/i22036.scala | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/TypeEval.scala b/compiler/src/dotty/tools/dotc/core/TypeEval.scala index 9fd8b9952e8f..03821ad4812a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeEval.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeEval.scala @@ -115,7 +115,7 @@ object TypeEval: val fieldTypesOpt = tupleElementTypes(arg) fieldTypesOpt match case Some(fieldTypes) => - val fieldLabels = (for i <- 1 to fieldTypes.length yield ConstantType(Constant(s"_$i")))).toList + val fieldLabels = (for i <- 1 to fieldTypes.length yield ConstantType(Constant(s"_$i"))).toList Some: defn.NamedTupleTypeRef.appliedTo: nestedPairs(fieldLabels) :: nestedPairs(fieldTypes) :: Nil diff --git a/tests/pos/i22036.scala b/tests/pos/i22036.scala index e981722d895d..99a1502a253f 100644 --- a/tests/pos/i22036.scala +++ b/tests/pos/i22036.scala @@ -11,3 +11,16 @@ val res2 = x2._1 val x3: Foo[NamedTuple.From[Tuple.Map[(Int, Int), Foo]]] = ??? val res3 = x3._1 + +def foo[T <: (Int, String)](tup: T): Int = + tup._1 + +def union[T](tup: (Int, String) +|(Int, String) +): Int = + tup._1 + +def intersect[T](tup: (Int, String) +& T +): Int = + tup._1 \ No newline at end of file