@@ -322,6 +322,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
322
322
case ClassSymbol (pre : Type , cls : Symbol )
323
323
case Singleton (src : Symbol , tref : TermRef )
324
324
case GenericTuple (tps : List [Type ])
325
+ case NamedTuple (nameTypePairs : List [(TermName , Type )])
325
326
326
327
/** Tests that both sides are tuples of the same arity */
327
328
infix def sameTuple (that : MirrorSource )(using Context ): Boolean =
@@ -351,6 +352,11 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
351
352
val arity = tps.size
352
353
if arity <= Definitions .MaxTupleArity then s " class Tuple $arity"
353
354
else s " trait Tuple { def size: $arity } "
355
+ case NamedTuple (nameTypePairs) =>
356
+ val (names, types) = nameTypePairs.unzip
357
+ val namesStr = names.map(_.show).mkString(" (\" " , " \" , \" " , " \" )" )
358
+ val typesStr = types.map(_.show).mkString(" (" , " , " , " )" )
359
+ s " NamedTuple.NamedTuple[ ${namesStr}, ${typesStr}] "
354
360
355
361
private [Synthesizer ] object MirrorSource :
356
362
@@ -398,6 +404,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
398
404
// avoid type aliases for tuples
399
405
Right (MirrorSource .GenericTuple (types))
400
406
case _ => reduce(tp.underlying)
407
+ case defn.NamedTupleDirect (_, _) =>
408
+ Right (MirrorSource .NamedTuple (tp.namedTupleElementTypes(derived = false )))
401
409
case tp : MatchType =>
402
410
val n = tp.tryNormalize
403
411
if n.exists then reduce(n) else Left (i " its subpart ` $tp` is an unreducible match type. " )
@@ -428,10 +436,25 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
428
436
def newTupleMirror (arity : Int ): Tree =
429
437
New (defn.RuntimeTupleMirrorTypeRef , Literal (Constant (arity)) :: Nil )
430
438
431
- def makeProductMirror (pre : Type , cls : Symbol , tps : Option [List [Type ]]): TreeWithErrors =
439
+ def makeNamedTupleProductMirror (nameTypePairs : List [(TermName , Type )]): TreeWithErrors =
440
+ val (labels, typeElems) = nameTypePairs.unzip
441
+ val elemLabels = labels.map(label => ConstantType (Constant (label.toString)))
442
+ val mirrorRef : Type => Tree = _ => newTupleMirror(typeElems.size)
443
+ makeProductMirror(typeElems, elemLabels, tpnme.NamedTuple , mirrorRef)
444
+ end makeNamedTupleProductMirror
445
+
446
+ def makeClassProductMirror (pre : Type , cls : Symbol , tps : Option [List [Type ]]) =
432
447
val accessors = cls.caseAccessors
433
448
val elemLabels = accessors.map(acc => ConstantType (Constant (acc.name.toString)))
434
449
val typeElems = tps.getOrElse(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
450
+ val mirrorRef = (monoType : Type ) =>
451
+ if cls.useCompanionAsProductMirror then companionPath(pre, cls, span)
452
+ else if defn.isTupleClass(cls) then newTupleMirror(typeElems.size) // TODO: cls == defn.PairClass when > 22
453
+ else anonymousMirror(monoType, MirrorImpl .OfProduct (pre), span)
454
+ makeProductMirror(typeElems, elemLabels, cls.name, mirrorRef)
455
+ end makeClassProductMirror
456
+
457
+ def makeProductMirror (typeElems : List [Type ], elemLabels : List [Type ], label : Name , mirrorRef : Type => Tree ): TreeWithErrors =
435
458
val nestedPairs = TypeOps .nestedPairs(typeElems)
436
459
val (monoType, elemsType) = mirroredType match
437
460
case mirroredType : HKTypeLambda =>
@@ -442,15 +465,11 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
442
465
checkRefinement(formal, tpnme.MirroredElemTypes , elemsType, span)
443
466
checkRefinement(formal, tpnme.MirroredElemLabels , elemsLabels, span)
444
467
val mirrorType = formal.constrained_& {
445
- mirrorCore(defn.Mirror_ProductClass , monoType, mirroredType, cls.name )
468
+ mirrorCore(defn.Mirror_ProductClass , monoType, mirroredType, label )
446
469
.refinedWith(tpnme.MirroredElemTypes , TypeAlias (elemsType))
447
470
.refinedWith(tpnme.MirroredElemLabels , TypeAlias (elemsLabels))
448
471
}
449
- val mirrorRef =
450
- if cls.useCompanionAsProductMirror then companionPath(pre, cls, span)
451
- else if defn.isTupleClass(cls) then newTupleMirror(typeElems.size) // TODO: cls == defn.PairClass when > 22
452
- else anonymousMirror(monoType, MirrorImpl .OfProduct (pre), span)
453
- withNoErrors(mirrorRef.cast(mirrorType).withSpan(span))
472
+ withNoErrors(mirrorRef(monoType).cast(mirrorType).withSpan(span))
454
473
end makeProductMirror
455
474
456
475
MirrorSource .reduce(mirroredType) match
@@ -474,10 +493,12 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
474
493
val arity = tps.size
475
494
if tps.size <= maxArity then
476
495
val tupleCls = defn.TupleType (arity).nn.classSymbol
477
- makeProductMirror (tupleCls.owner.reachableThisType, tupleCls, Some (tps))
496
+ makeClassProductMirror (tupleCls.owner.reachableThisType, tupleCls, Some (tps))
478
497
else
479
498
val reason = s " it reduces to a tuple with arity $arity, expected arity <= $maxArity"
480
499
withErrors(i " ${defn.PairClass } is not a generic product because $reason" )
500
+ case MirrorSource .NamedTuple (nameTypePairs) =>
501
+ makeNamedTupleProductMirror(nameTypePairs)
481
502
case MirrorSource .ClassSymbol (pre, cls) =>
482
503
if cls.isGenericProduct then
483
504
if ctx.runZincPhases then
@@ -486,7 +507,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
486
507
val rec = ctx.compilationUnit.depRecorder
487
508
rec.addClassDependency(cls, DependencyByMemberRef )
488
509
rec.addUsedName(cls.primaryConstructor)
489
- makeProductMirror (pre, cls, None )
510
+ makeClassProductMirror (pre, cls, None )
490
511
else withErrors(i " $cls is not a generic product because ${cls.whyNotGenericProduct}" )
491
512
case Left (msg) =>
492
513
withErrors(i " type ` $mirroredType` is not a generic product because $msg" )
@@ -501,6 +522,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
501
522
val arity = tps.size
502
523
val cls = if arity <= Definitions .MaxTupleArity then defn.TupleType (arity).nn.classSymbol else defn.PairClass
503
524
(" " , NoType , cls)
525
+ case Right (MirrorSource .NamedTuple (_)) =>
526
+ (" named tuples are not sealed classes" , NoType , NoSymbol )
504
527
case Left (msg) => (msg, NoType , NoSymbol )
505
528
506
529
val clsIsGenericSum = cls.isGenericSum(pre)
0 commit comments