@@ -281,21 +281,34 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
281281
282282 private def productMirror (mirroredType : Type , formal : Type , span : Span )(using Context ): TreeWithErrors =
283283
284- var isSafeGenericTuple = Option .empty[List [Type ]]
284+ var isSafeGenericTuple = Option .empty[(Symbol , List [Type ])]
285+
286+ /** do all parts match the class symbol? Or can we extract a generic tuple type out? */
287+ def acceptable (tp : Type , cls : Symbol ): Boolean =
288+ var genericTupleParts = List .empty[(Symbol , List [Type ])]
289+
290+ def acceptableGenericTuple (tp : AppliedType ): Boolean =
291+ val tupleArgs = tp.tupleElementTypes
292+ val arity = tupleArgs.size
293+ val isOk = arity <= Definitions .MaxTupleArity
294+ if isOk then
295+ genericTupleParts ::= {
296+ val cls = defn.TupleType (arity).nn.classSymbol
297+ (cls, tupleArgs)
298+ }
299+ isOk
285300
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
301+ def inner (tp : Type , cls : Symbol ): Boolean = tp match
302+ case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] => false
303+ case tp @ AppliedType (cons : TypeRef , _) if cons.isRef(defn.PairClass ) => acceptableGenericTuple(tp)
304+ case tp : TypeProxy => inner(tp.underlying, cls)
305+ case OrType (tp1, tp2) => inner(tp1, cls) && inner(tp2, cls)
306+ case _ => tp.classSymbol eq cls
291307
292- /** do all parts match the class symbol? */
293- def acceptable (tp : Type , cls : Symbol ): Boolean = tp match
294- case tp : HKTypeLambda if tp.resultType.isInstanceOf [HKTypeLambda ] => false
295- case tp @ AppliedType (cons : TypeRef , _) if cons.isRef(defn.PairClass ) && illegalGenericTuple(tp) => false
296- case tp : TypeProxy => acceptable(tp.underlying, cls)
297- case OrType (tp1, tp2) => acceptable(tp1, cls) && acceptable(tp2, cls)
298- case _ => tp.classSymbol eq cls
308+ val classPartsMatch = inner(tp, cls)
309+ classPartsMatch && genericTupleParts.map((cls, _) => cls).distinct.sizeIs <= 1 &&
310+ { isSafeGenericTuple = genericTupleParts.headOption ; true }
311+ end acceptable
299312
300313 /** for a case class, if it will have an anonymous mirror,
301314 * check that its constructor can be accessed
@@ -314,10 +327,10 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
314327 cls.is(Scala2x ) || cls.linkedClass.is(Case )
315328
316329 def makeProductMirror (cls : Symbol ): TreeWithErrors =
317- val mirroredClass = isSafeGenericTuple.fold(cls)(tps => defn. TupleType (tps.size).nn.classSymbol )
330+ val mirroredClass = isSafeGenericTuple.fold(cls)((cls, _) => cls )
318331 val accessors = mirroredClass.caseAccessors.filterNot(_.isAllOf(PrivateLocal ))
319332 val elemLabels = accessors.map(acc => ConstantType (Constant (acc.name.toString)))
320- val nestedPairs = isSafeGenericTuple.map(TypeOps .nestedPairs).getOrElse {
333+ val nestedPairs = isSafeGenericTuple.map((_, tps) => TypeOps .nestedPairs(tps) ).getOrElse {
321334 TypeOps .nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
322335 }
323336 val (monoType, elemsType) = mirroredType match
@@ -334,7 +347,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
334347 .refinedWith(tpnme.MirroredElemLabels , TypeAlias (elemsLabels))
335348 val mirrorRef =
336349 if genAnonyousMirror(mirroredClass) then
337- anonymousMirror(monoType, ExtendsProductMirror , isSafeGenericTuple.map(_.size), span)
350+ anonymousMirror(monoType, ExtendsProductMirror , isSafeGenericTuple.map(_( 1 ) .size), span)
338351 else companionPath(mirroredType, span)
339352 withNoErrors(mirrorRef.cast(mirrorType))
340353 end makeProductMirror
0 commit comments