@@ -26,7 +26,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
26
26
/** Handlers to synthesize implicits for special types */
27
27
type SpecialHandler = (Type , Span ) => Context ?=> TreeWithErrors
28
28
private type SpecialHandlers = List [(ClassSymbol , SpecialHandler )]
29
-
29
+
30
30
val synthesizedClassTag : SpecialHandler = (formal, span) =>
31
31
formal.argInfos match
32
32
case arg :: Nil =>
@@ -223,16 +223,19 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
223
223
/** Create an anonymous class `new Object { type MirroredMonoType = ... }`
224
224
* and mark it with given attachment so that it is made into a mirror at PostTyper.
225
225
*/
226
- private def anonymousMirror (monoType : Type , attachment : Property .StickyKey [Unit ], span : Span )(using Context ) =
226
+ private def anonymousMirror (monoType : Type , attachment : Property .StickyKey [Unit ], tupleArity : Option [ Int ], span : Span )(using Context ) =
227
227
if ctx.isAfterTyper then ctx.compilationUnit.needsMirrorSupport = true
228
228
val monoTypeDef = untpd.TypeDef (tpnme.MirroredMonoType , untpd.TypeTree (monoType))
229
- val newImpl = untpd.Template (
229
+ var newImpl = untpd.Template (
230
230
constr = untpd.emptyConstructor,
231
231
parents = untpd.TypeTree (defn.ObjectType ) :: Nil ,
232
232
derived = Nil ,
233
233
self = EmptyValDef ,
234
234
body = monoTypeDef :: Nil
235
235
).withAttachment(attachment, ())
236
+ tupleArity.foreach { n =>
237
+ newImpl = newImpl.withAttachment(GenericTupleArity , n)
238
+ }
236
239
typer.typed(untpd.New (newImpl).withSpan(span))
237
240
238
241
/** The mirror type
@@ -278,9 +281,18 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
278
281
279
282
private def productMirror (mirroredType : Type , formal : Type , span : Span )(using Context ): TreeWithErrors =
280
283
284
+ var isSafeGenericTuple = Option .empty[List [Type ]]
285
+
286
+ def illegalGenericTuple (tp : AppliedType ): Boolean =
287
+ val tupleArgs = tp.tupleElementTypes
288
+ val isTooLarge = tupleArgs.length > Definitions .MaxTupleArity
289
+ isSafeGenericTuple = Option .when(! isTooLarge)(tupleArgs)
290
+ isTooLarge
291
+
281
292
/** do all parts match the class symbol? */
282
293
def acceptable (tp : Type , cls : Symbol ): Boolean = tp match
283
294
case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] => false
295
+ case tp @ AppliedType (cons : TypeRef , _) if cons.isRef(defn.PairClass ) && illegalGenericTuple(tp) => false
284
296
case tp : TypeProxy => acceptable(tp.underlying, cls)
285
297
case OrType (tp1, tp2) => acceptable(tp1, cls) && acceptable(tp2, cls)
286
298
case _ => tp.classSymbol eq cls
@@ -299,12 +311,15 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
299
311
}
300
312
301
313
def genAnonyousMirror (cls : Symbol ): Boolean =
302
- cls.is(Scala2x ) || cls.linkedClass.is(Case )
314
+ isSafeGenericTuple.isDefined || cls.is(Scala2x ) || cls.linkedClass.is(Case )
303
315
304
316
def makeProductMirror (cls : Symbol ): TreeWithErrors =
305
- val accessors = cls.caseAccessors.filterNot(_.isAllOf(PrivateLocal ))
317
+ val mirroredClass = isSafeGenericTuple.fold(cls)(tps => defn.TupleType (tps.size).nn.classSymbol)
318
+ val accessors = mirroredClass.caseAccessors.filterNot(_.isAllOf(PrivateLocal ))
306
319
val elemLabels = accessors.map(acc => ConstantType (Constant (acc.name.toString)))
307
- val nestedPairs = TypeOps .nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
320
+ val nestedPairs = isSafeGenericTuple.map(TypeOps .nestedPairs).getOrElse {
321
+ TypeOps .nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
322
+ }
308
323
val (monoType, elemsType) = mirroredType match
309
324
case mirroredType : HKTypeLambda =>
310
325
(mkMirroredMonoType(mirroredType), mirroredType.derivedLambdaType(resType = nestedPairs))
@@ -318,18 +333,20 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
318
333
.refinedWith(tpnme.MirroredElemTypes , TypeAlias (elemsType))
319
334
.refinedWith(tpnme.MirroredElemLabels , TypeAlias (elemsLabels))
320
335
val mirrorRef =
321
- if (genAnonyousMirror(cls)) anonymousMirror(monoType, ExtendsProductMirror , span)
336
+ if genAnonyousMirror(cls) then
337
+ anonymousMirror(monoType, ExtendsProductMirror , isSafeGenericTuple.map(_.size), span)
322
338
else companionPath(mirroredType, span)
323
339
withNoErrors(mirrorRef.cast(mirrorType))
324
340
end makeProductMirror
325
341
326
- def getError (cls : Symbol ): String =
327
- val reason = if ! cls.isGenericProduct then
328
- i " because ${cls.whyNotGenericProduct}"
329
- else if ! canAccessCtor(cls) then
330
- i " because the constructor of $cls is innaccessible from the calling scope. "
331
- else
332
- " "
342
+ def getError (cls : Symbol ): String =
343
+ val reason =
344
+ if ! cls.isGenericProduct then
345
+ i " because ${cls.whyNotGenericProduct}"
346
+ else if ! canAccessCtor(cls) then
347
+ i " because the constructor of $cls is innaccessible from the calling scope. "
348
+ else
349
+ " "
333
350
i " $cls is not a generic product $reason"
334
351
end getError
335
352
@@ -350,8 +367,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
350
367
else
351
368
val cls = mirroredType.classSymbol
352
369
if acceptable(mirroredType, cls)
353
- && cls.isGenericProduct
354
- && canAccessCtor(cls)
370
+ && isSafeGenericTuple.isDefined || (cls.isGenericProduct && canAccessCtor(cls))
355
371
then
356
372
makeProductMirror(cls)
357
373
else
@@ -424,11 +440,11 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
424
440
.refinedWith(tpnme.MirroredElemLabels , TypeAlias (TypeOps .nestedPairs(elemLabels)))
425
441
val mirrorRef =
426
442
if useCompanion then companionPath(mirroredType, span)
427
- else anonymousMirror(monoType, ExtendsSumMirror , span)
443
+ else anonymousMirror(monoType, ExtendsSumMirror , tupleArity = None , span)
428
444
withNoErrors(mirrorRef.cast(mirrorType))
429
445
else if ! clsIsGenericSum then
430
446
(EmptyTree , List (i " $cls is not a generic sum because ${cls.whyNotGenericSum(declScope)}" ))
431
- else
447
+ else
432
448
EmptyTreeNoError
433
449
end sumMirror
434
450
@@ -595,7 +611,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
595
611
tp.baseType(cls)
596
612
val base = baseWithRefinements(formal)
597
613
val result =
598
- if (base <:< formal.widenExpr)
614
+ if (base <:< formal.widenExpr)
599
615
// With the subtype test we enforce that the searched type `formal` is of the right form
600
616
handler(base, span)
601
617
else EmptyTreeNoError
@@ -609,19 +625,19 @@ end Synthesizer
609
625
610
626
object Synthesizer :
611
627
612
- /** Tuple used to store the synthesis result with a list of errors. */
628
+ /** Tuple used to store the synthesis result with a list of errors. */
613
629
type TreeWithErrors = (Tree , List [String ])
614
630
private def withNoErrors (tree : Tree ): TreeWithErrors = (tree, List .empty)
615
631
616
632
private val EmptyTreeNoError : TreeWithErrors = withNoErrors(EmptyTree )
617
633
618
634
private def orElse (treeWithErrors1 : TreeWithErrors , treeWithErrors2 : => TreeWithErrors ): TreeWithErrors = treeWithErrors1 match
619
- case (tree, errors) if tree eq genericEmptyTree =>
635
+ case (tree, errors) if tree eq genericEmptyTree =>
620
636
val (tree2, errors2) = treeWithErrors2
621
637
(tree2, errors ::: errors2)
622
638
case _ => treeWithErrors1
623
639
624
- private def clearErrorsIfNotEmpty (treeWithErrors : TreeWithErrors ) = treeWithErrors match
640
+ private def clearErrorsIfNotEmpty (treeWithErrors : TreeWithErrors ) = treeWithErrors match
625
641
case (tree, _) if tree eq genericEmptyTree => treeWithErrors
626
642
case (tree, _) => withNoErrors(tree)
627
643
0 commit comments