diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index dd20c2db9192..6c7cd5143b66 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1334,12 +1334,19 @@ class Definitions { case ByNameFunction(_) => true case _ => false + object NamedTupleDirect: + def unapply(t: Type)(using Context): Option[(Type, Type)] = + t match + case AppliedType(tycon, nmes :: vals :: Nil) if tycon.typeSymbol == NamedTupleTypeRef.symbol => + Some((nmes, vals)) + case _ => None + object NamedTuple: def apply(nmes: Type, vals: Type)(using Context): Type = AppliedType(NamedTupleTypeRef, nmes :: vals :: Nil) def unapply(t: Type)(using Context): Option[(Type, Type)] = t match - case AppliedType(tycon, nmes :: vals :: Nil) if tycon.typeSymbol == NamedTupleTypeRef.symbol => + case NamedTupleDirect(nmes, vals) => Some((nmes, vals)) case tp: TypeProxy => val t = unapply(tp.superType); t diff --git a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala index 14ccf32c7787..739cc2b74a16 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala @@ -128,22 +128,19 @@ class TypeUtils: case None => throw new AssertionError("not a tuple") def namedTupleElementTypesUpTo(bound: Int, derived: Boolean, normalize: Boolean = true)(using Context): List[(TermName, Type)] = + def extractNamesTypes(nmes: Type, vals: Type): List[(TermName, Type)] = + val names = nmes.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil).map(_.dealias).map: + case ConstantType(Constant(str: String)) => str.toTermName + case t => throw TypeError(em"Malformed NamedTuple: names must be string types, but $t was found.") + val values = vals.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil) + names.zip(values) + (if normalize then self.normalized else self).dealias match // for desugaring and printer, ignore derived types to avoid infinite recursion in NamedTuple.unapply - case AppliedType(tycon, nmes :: vals :: Nil) if !derived && tycon.typeSymbol == defn.NamedTupleTypeRef.symbol => - val names = nmes.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil).map(_.dealias).map: - case ConstantType(Constant(str: String)) => str.toTermName - case t => throw TypeError(em"Malformed NamedTuple: names must be string types, but $t was found.") - val values = vals.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil) - names.zip(values) + case defn.NamedTupleDirect(nmes, vals) => extractNamesTypes(nmes, vals) case t if !derived => Nil // default cause, used for post-typing - case defn.NamedTuple(nmes, vals) => - val names = nmes.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil).map(_.dealias).map: - case ConstantType(Constant(str: String)) => str.toTermName - case t => throw TypeError(em"Malformed NamedTuple: names must be string types, but $t was found.") - val values = vals.tupleElementTypesUpTo(bound, normalize).getOrElse(Nil) - names.zip(values) + case defn.NamedTuple(nmes, vals) => extractNamesTypes(nmes, vals) case t => Nil