@@ -281,21 +281,34 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
281
281
282
282
private def productMirror (mirroredType : Type , formal : Type , span : Span )(using Context ): TreeWithErrors =
283
283
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
285
300
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
291
307
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
299
312
300
313
/** for a case class, if it will have an anonymous mirror,
301
314
* check that its constructor can be accessed
@@ -314,10 +327,10 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
314
327
cls.is(Scala2x ) || cls.linkedClass.is(Case )
315
328
316
329
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 )
318
331
val accessors = mirroredClass.caseAccessors.filterNot(_.isAllOf(PrivateLocal ))
319
332
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 {
321
334
TypeOps .nestedPairs(accessors.map(mirroredType.resultType.memberInfo(_).widenExpr))
322
335
}
323
336
val (monoType, elemsType) = mirroredType match
@@ -334,7 +347,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
334
347
.refinedWith(tpnme.MirroredElemLabels , TypeAlias (elemsLabels))
335
348
val mirrorRef =
336
349
if genAnonyousMirror(mirroredClass) then
337
- anonymousMirror(monoType, ExtendsProductMirror , isSafeGenericTuple.map(_.size), span)
350
+ anonymousMirror(monoType, ExtendsProductMirror , isSafeGenericTuple.map(_( 1 ) .size), span)
338
351
else companionPath(mirroredType, span)
339
352
withNoErrors(mirrorRef.cast(mirrorType))
340
353
end makeProductMirror
0 commit comments