@@ -26,7 +26,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
2626 /** Handlers to synthesize implicits for special types */
2727 type SpecialHandler = (Type , Span ) => Context ?=> TreeWithErrors
2828 private type SpecialHandlers = List [(ClassSymbol , SpecialHandler )]
29-
29+
3030 val synthesizedClassTag : SpecialHandler = (formal, span) =>
3131 formal.argInfos match
3232 case arg :: Nil =>
@@ -223,16 +223,19 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
223223 /** Create an anonymous class `new Object { type MirroredMonoType = ... }`
224224 * and mark it with given attachment so that it is made into a mirror at PostTyper.
225225 */
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 ) =
227227 if ctx.isAfterTyper then ctx.compilationUnit.needsMirrorSupport = true
228228 val monoTypeDef = untpd.TypeDef (tpnme.MirroredMonoType , untpd.TypeTree (monoType))
229- val newImpl = untpd.Template (
229+ var newImpl = untpd.Template (
230230 constr = untpd.emptyConstructor,
231231 parents = untpd.TypeTree (defn.ObjectType ) :: Nil ,
232232 derived = Nil ,
233233 self = EmptyValDef ,
234234 body = monoTypeDef :: Nil
235235 ).withAttachment(attachment, ())
236+ tupleArity.foreach { n =>
237+ newImpl = newImpl.withAttachment(GenericTupleArity , n)
238+ }
236239 typer.typed(untpd.New (newImpl).withSpan(span))
237240
238241 /** The mirror type
@@ -278,9 +281,18 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
278281
279282 private def productMirror (mirroredType : Type , formal : Type , span : Span )(using Context ): TreeWithErrors =
280283
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+
281292 /** do all parts match the class symbol? */
282293 def acceptable (tp : Type , cls : Symbol ): Boolean = tp match
283294 case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] => false
295+ case tp @ AppliedType (cons : TypeRef , _) if cons.isRef(defn.PairClass ) && illegalGenericTuple(tp) => false
284296 case tp : TypeProxy => acceptable(tp.underlying, cls)
285297 case OrType (tp1, tp2) => acceptable(tp1, cls) && acceptable(tp2, cls)
286298 case _ => tp.classSymbol eq cls
@@ -299,12 +311,15 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
299311 }
300312
301313 def genAnonyousMirror (cls : Symbol ): Boolean =
302- cls.is(Scala2x ) || cls.linkedClass.is(Case )
314+ isSafeGenericTuple.isDefined || cls.is(Scala2x ) || cls.linkedClass.is(Case )
303315
304316 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 ))
306319 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+ }
308323 val (monoType, elemsType) = mirroredType match
309324 case mirroredType : HKTypeLambda =>
310325 (mkMirroredMonoType(mirroredType), mirroredType.derivedLambdaType(resType = nestedPairs))
@@ -318,18 +333,20 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
318333 .refinedWith(tpnme.MirroredElemTypes , TypeAlias (elemsType))
319334 .refinedWith(tpnme.MirroredElemLabels , TypeAlias (elemsLabels))
320335 val mirrorRef =
321- if (genAnonyousMirror(cls)) anonymousMirror(monoType, ExtendsProductMirror , span)
336+ if genAnonyousMirror(cls) then
337+ anonymousMirror(monoType, ExtendsProductMirror , isSafeGenericTuple.map(_.size), span)
322338 else companionPath(mirroredType, span)
323339 withNoErrors(mirrorRef.cast(mirrorType))
324340 end makeProductMirror
325341
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+ " "
333350 i " $cls is not a generic product $reason"
334351 end getError
335352
@@ -350,8 +367,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
350367 else
351368 val cls = mirroredType.classSymbol
352369 if acceptable(mirroredType, cls)
353- && cls.isGenericProduct
354- && canAccessCtor(cls)
370+ && isSafeGenericTuple.isDefined || (cls.isGenericProduct && canAccessCtor(cls))
355371 then
356372 makeProductMirror(cls)
357373 else
@@ -424,11 +440,11 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
424440 .refinedWith(tpnme.MirroredElemLabels , TypeAlias (TypeOps .nestedPairs(elemLabels)))
425441 val mirrorRef =
426442 if useCompanion then companionPath(mirroredType, span)
427- else anonymousMirror(monoType, ExtendsSumMirror , span)
443+ else anonymousMirror(monoType, ExtendsSumMirror , tupleArity = None , span)
428444 withNoErrors(mirrorRef.cast(mirrorType))
429445 else if ! clsIsGenericSum then
430446 (EmptyTree , List (i " $cls is not a generic sum because ${cls.whyNotGenericSum(declScope)}" ))
431- else
447+ else
432448 EmptyTreeNoError
433449 end sumMirror
434450
@@ -595,7 +611,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
595611 tp.baseType(cls)
596612 val base = baseWithRefinements(formal)
597613 val result =
598- if (base <:< formal.widenExpr)
614+ if (base <:< formal.widenExpr)
599615 // With the subtype test we enforce that the searched type `formal` is of the right form
600616 handler(base, span)
601617 else EmptyTreeNoError
@@ -609,19 +625,19 @@ end Synthesizer
609625
610626object Synthesizer :
611627
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. */
613629 type TreeWithErrors = (Tree , List [String ])
614630 private def withNoErrors (tree : Tree ): TreeWithErrors = (tree, List .empty)
615631
616632 private val EmptyTreeNoError : TreeWithErrors = withNoErrors(EmptyTree )
617633
618634 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 =>
620636 val (tree2, errors2) = treeWithErrors2
621637 (tree2, errors ::: errors2)
622638 case _ => treeWithErrors1
623639
624- private def clearErrorsIfNotEmpty (treeWithErrors : TreeWithErrors ) = treeWithErrors match
640+ private def clearErrorsIfNotEmpty (treeWithErrors : TreeWithErrors ) = treeWithErrors match
625641 case (tree, _) if tree eq genericEmptyTree => treeWithErrors
626642 case (tree, _) => withNoErrors(tree)
627643
0 commit comments