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

Generate mirrors for named tuples #22469

Merged
merged 1 commit into from
Jan 31, 2025

Conversation

jchyb
Copy link
Contributor

@jchyb jchyb commented Jan 27, 2025

Fixes #22382
For summon[Mirror.Of[(foo: Int, bla: String)]] we generate:

new scala.runtime.TupleMirror(2).$asInstanceOf[
    scala.deriving.Mirror.Product{
      type MirroredMonoType = (foo : Int, bla : String);
        type MirroredType = (foo : Int, bla : String);
        type MirroredLabel = ("NamedTuple" : String);
        type MirroredElemTypes = (Int, String);
        type MirroredElemLabels = (("foo" : String),
          ("bla" : String))
    }
]

We reuse scala.runtime.TupleMirror, because it pretty much does everything we want it to, and fromProduct (with supplied Product types) call on that mirror still works there.
Since NamedTuple is not technically a Product type, I imagine users might be a little confused why they can't put a named tuple into a fromProduct argument, but this is easily worked around with .toTuple

@jchyb jchyb force-pushed the fix-i22382-named-tuple-mirror branch from 1251ae6 to 9077d4f Compare January 29, 2025 14:24
@jchyb jchyb marked this pull request as ready for review January 29, 2025 16:45
@jchyb jchyb requested a review from bishabosha January 30, 2025 10:53
@@ -398,6 +404,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
// avoid type aliases for tuples
Right(MirrorSource.GenericTuple(types))
case _ => reduce(tp.underlying)
case tp @ AppliedType(tref: TypeRef, List(_, typeTuple)) if tref == defn.NamedTupleTypeRef =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
case tp @ AppliedType(tref: TypeRef, List(_, typeTuple)) if tref == defn.NamedTupleTypeRef =>
case tp @ AppliedType(tref: TypeRef, List(_, _)) if tref == defn.NamedTupleTypeRef =>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up changing it into defn.NamedTupleDirect(_, _) (same AppliedType internally), for readability (I don't think that unapply was there when I started making this PR)

@@ -398,6 +404,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
// avoid type aliases for tuples
Right(MirrorSource.GenericTuple(types))
case _ => reduce(tp.underlying)
case tp @ AppliedType(tref: TypeRef, List(_, typeTuple)) if tref == defn.NamedTupleTypeRef =>
Right(MirrorSource.NamedTuple(tp.namedTupleElementTypes(false)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what changes with derived=true instead of false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

derived=true allows to convert union and intersection types of NamedTuples into NamedTuple AppliedType types. We already know it's a NamedTupleDirect from the unapply above, so we don't need to do that (and setting true would not change anything here).

val (labels, typeElems) = nameTypePairs.unzip
val elemLabels = labels.map(label => ConstantType(Constant(label.toString)))
val mirrorRef: Type => Tree = _ => newTupleMirror(typeElems.size)
makeProductMirror(typeElems, elemLabels, "NamedTuple".toTypeName, mirrorRef)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
makeProductMirror(typeElems, elemLabels, "NamedTuple".toTypeName, mirrorRef)
makeProductMirror(typeElems, elemLabels, tpnme.NamedTuple, mirrorRef)

if this doesnt exist it should

@@ -501,6 +522,10 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
val arity = tps.size
val cls = if arity <= Definitions.MaxTupleArity then defn.TupleType(arity).nn.classSymbol else defn.PairClass
("", NoType, cls)
case Right(MirrorSource.NamedTuple(nameTypePairs)) =>
val arity = nameTypePairs.size
val cls = if arity <= Definitions.MaxTupleArity then defn.TupleType(arity).nn.classSymbol else defn.PairClass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val cls = if arity <= Definitions.MaxTupleArity then defn.TupleType(arity).nn.classSymbol else defn.PairClass

unused? (is there a side-effect?)

@@ -501,6 +522,10 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
val arity = tps.size
val cls = if arity <= Definitions.MaxTupleArity then defn.TupleType(arity).nn.classSymbol else defn.PairClass
("", NoType, cls)
case Right(MirrorSource.NamedTuple(nameTypePairs)) =>
val arity = nameTypePairs.size
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(also unused)

@jchyb jchyb force-pushed the fix-i22382-named-tuple-mirror branch from 9077d4f to 0a6e367 Compare January 31, 2025 11:35
@jchyb jchyb enabled auto-merge (squash) January 31, 2025 13:51
@jchyb jchyb merged commit b908d81 into scala:main Jan 31, 2025
27 checks passed
@jchyb jchyb deleted the fix-i22382-named-tuple-mirror branch January 31, 2025 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mirror.Of is not implemented for named tuples
2 participants