Skip to content

Commit e5e19c8

Browse files
authored
Support Mirror for generic tuples arity > 22 (#23363)
fixes #15398
1 parent a115c8d commit e5e19c8

File tree

4 files changed

+23
-9
lines changed

4 files changed

+23
-9
lines changed

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ object StdNames {
394394
val This: N = "This"
395395
val ThisType: N = "ThisType"
396396
val Tuple2: N = "Tuple2"
397+
val Tuple: N = "Tuple"
397398
val TYPE_ : N = "TYPE"
398399
val TypeApply: N = "TypeApply"
399400
val TypeRef: N = "TypeRef"

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -436,13 +436,24 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
436436
makeProductMirror(typeElems, elemLabels, tpnme.NamedTuple, mirrorRef)
437437
end makeNamedTupleProductMirror
438438

439+
def makeTupleProductMirror(tps: List[Type]): TreeWithErrors =
440+
val arity = tps.size
441+
if arity <= Definitions.MaxTupleArity then
442+
val tupleCls = defn.TupleType(arity).nn.classSymbol
443+
makeClassProductMirror(tupleCls.owner.reachableThisType, tupleCls, Some(tps))
444+
else
445+
val elemLabels = (for i <- 1 to arity yield ConstantType(Constant(s"_$i"))).toList
446+
val mirrorRef: Type => Tree = _ => newTupleMirror(arity)
447+
makeProductMirror(tps, elemLabels, tpnme.Tuple, mirrorRef)
448+
end makeTupleProductMirror
449+
439450
def makeClassProductMirror(pre: Type, cls: Symbol, tps: Option[List[Type]]) =
440451
val accessors = cls.caseAccessors
441452
val elemLabels = accessors.map(acc => ConstantType(Constant(acc.name.toString)))
442453
val typeElems = tps.getOrElse(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
443454
val mirrorRef = (monoType: Type) =>
444455
if cls.useCompanionAsProductMirror then companionPath(pre, cls, span)
445-
else if defn.isTupleClass(cls) then newTupleMirror(typeElems.size) // TODO: cls == defn.PairClass when > 22
456+
else if defn.isTupleClass(cls) then newTupleMirror(typeElems.size)
446457
else anonymousMirror(monoType, MirrorImpl.OfProduct(pre), span)
447458
makeProductMirror(typeElems, elemLabels, cls.name, mirrorRef)
448459
end makeClassProductMirror
@@ -482,14 +493,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
482493
}
483494
withNoErrors(singletonPath.cast(mirrorType).withSpan(span))
484495
case MirrorSource.GenericTuple(tps) =>
485-
val maxArity = Definitions.MaxTupleArity
486-
val arity = tps.size
487-
if tps.size <= maxArity then
488-
val tupleCls = defn.TupleType(arity).nn.classSymbol
489-
makeClassProductMirror(tupleCls.owner.reachableThisType, tupleCls, Some(tps))
490-
else
491-
val reason = s"it reduces to a tuple with arity $arity, expected arity <= $maxArity"
492-
withErrors(i"${defn.PairClass} is not a generic product because $reason")
496+
makeTupleProductMirror(tps)
493497
case MirrorSource.NamedTuple(nameTypePairs) =>
494498
makeNamedTupleProductMirror(nameTypePairs)
495499
case MirrorSource.ClassSymbol(pre, cls) =>
File renamed without changes.

tests/pos/i15398.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object i15398 {
2+
type Tuple23 = (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)
3+
4+
summon[Tuple.Size[Tuple23] =:= 23]
5+
val m = summon[scala.deriving.Mirror.Of[Tuple23]]
6+
summon[m.MirroredLabel =:= "Tuple"]
7+
summon[m.MirroredElemTypes =:= Tuple23]
8+
summon[m.MirroredElemLabels =:= ("_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8", "_9", "_10", "_11", "_12", "_13", "_14", "_15", "_16", "_17", "_18", "_19", "_20", "_21", "_22", "_23")]
9+
}

0 commit comments

Comments
 (0)