@@ -15,6 +15,7 @@ import reporting.diagnostic.messages._
1515import reporting .trace
1616import annotation .constructorOnly
1717import printing .Formatting .hl
18+ import config .Printers
1819
1920import scala .annotation .internal .sharable
2021
@@ -51,7 +52,7 @@ object desugar {
5152 private type VarInfo = (NameTree , Tree )
5253
5354 /** Is `name` the name of a method that can be invalidated as a compiler-generated
54- * case class method that clashes with a user-defined method?
55+ * case class method if it clashes with a user-defined method?
5556 */
5657 def isRetractableCaseClassMethodName (name : Name )(implicit ctx : Context ): Boolean = name match {
5758 case nme.apply | nme.unapply | nme.unapplySeq | nme.copy => true
@@ -394,6 +395,10 @@ object desugar {
394395 val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
395396 // This is not watertight, but `extends AnyVal` will be replaced by `inline` later.
396397
398+ /** The untyped analogue of SymUtils.isGenericProduct */
399+ val isGenericProduct =
400+ mods.is(Case , butNot = Abstract ) && constr1.vparamss.length == 1 && ! isValueClass
401+
397402 val originalTparams = constr1.tparams
398403 val originalVparamss = constr1.vparamss
399404 lazy val derivedEnumParams = enumClass.typeParams.map(derivedTypeParam)
@@ -585,11 +590,16 @@ object desugar {
585590 else Nil
586591 }
587592
593+ def mirrorMemberType (str : String ) =
594+ Select (Select (scalaDot(" deriving" .toTermName), " Mirror" .toTermName), str.toTypeName)
595+
588596 var parents1 = parents
589597 if (isEnumCase && parents.isEmpty)
590598 parents1 = enumClassTypeRef :: Nil
591- if (isCaseClass | isCaseObject )
599+ if (isCaseClass)
592600 parents1 = parents1 :+ scalaDot(str.Product .toTypeName) :+ scalaDot(nme.Serializable .toTypeName)
601+ else if (isCaseObject)
602+ parents1 = parents1 :+ mirrorMemberType(" Singleton" ) :+ scalaDot(nme.Serializable .toTypeName)
593603 else if (isObject)
594604 parents1 = parents1 :+ scalaDot(nme.Serializable .toTypeName)
595605 if (isEnum)
@@ -600,11 +610,11 @@ object desugar {
600610 if (mods.is(Module )) (impl.derived, Nil ) else (Nil , impl.derived)
601611
602612 // The thicket which is the desugared version of the companion object
603- // synthetic object C extends parentTpt derives class-derived { defs }
604- def companionDefs (parentTpt : Tree , defs : List [Tree ]) = {
613+ // synthetic object C extends parentTpts derives class-derived { defs }
614+ def companionDefs (parentTpts : List [ Tree ] , defs : List [Tree ]) = {
605615 val mdefs = moduleDef(
606616 ModuleDef (
607- className.toTermName, Template (emptyConstructor, parentTpt :: Nil , companionDerived, EmptyValDef , defs))
617+ className.toTermName, Template (emptyConstructor, parentTpts , companionDerived, EmptyValDef , defs))
608618 .withMods(companionMods | Synthetic ))
609619 .withSpan(cdef.span).toList
610620 if (companionDerived.nonEmpty)
@@ -627,6 +637,7 @@ object desugar {
627637 // For all other classes, the parent is AnyRef.
628638 val companions =
629639 if (isCaseClass) {
640+
630641 // The return type of the `apply` method, and an (empty or singleton) list
631642 // of widening coercions
632643 val (applyResultTpt, widenDefs) =
@@ -654,38 +665,53 @@ object desugar {
654665 // todo: also use anyRef if constructor has a dependent method type (or rule that out)!
655666 (constrVparamss :\ classTypeRef) (
656667 (vparams, restpe) => Function (vparams map (_.tpt), restpe))
668+ val companionParents =
669+ if (isGenericProduct) companionParent :: mirrorMemberType(" Product" ) :: Nil
670+ else companionParent :: Nil
657671 def widenedCreatorExpr =
658672 (creatorExpr /: widenDefs)((rhs, meth) => Apply (Ident (meth.name), rhs :: Nil ))
659673 val applyMeths =
660674 if (mods is Abstract ) Nil
661675 else {
662- val copiedFlagsMask = DefaultParameterized | (copiedAccessFlags & Private )
663- val appMods = {
664- val mods = Modifiers (Synthetic | constr1.mods.flags & copiedFlagsMask)
665- if (restrictedAccess) mods.withPrivateWithin(constr1.mods.privateWithin)
666- else mods
676+ def applyDef = {
677+ val copiedFlagsMask = DefaultParameterized | (copiedAccessFlags & Private )
678+ val appMods = {
679+ val mods = Modifiers (Synthetic | constr1.mods.flags & copiedFlagsMask)
680+ if (restrictedAccess) mods.withPrivateWithin(constr1.mods.privateWithin)
681+ else mods
682+ }
683+ DefDef (nme.apply, derivedTparams, derivedVparamss, applyResultTpt, widenedCreatorExpr)
684+ .withMods(appMods)
667685 }
668- val app = DefDef (nme.apply, derivedTparams, derivedVparamss, applyResultTpt, widenedCreatorExpr)
669- .withMods(appMods)
670- app :: widenDefs
686+ applyDef :: widenDefs
671687 }
688+
689+ val monoTypeDefs =
690+ if (isGenericProduct) {
691+ val monoType = appliedTypeTree(classTycon, constrTparams.map(_ => TypeBoundsTree (EmptyTree , EmptyTree )))
692+ TypeDef (tpnme.MonoType , monoType).withMods(synthetic) :: Nil
693+ }
694+ else Nil
695+
672696 val unapplyMeth = {
673697 val hasRepeatedParam = constrVparamss.head.exists {
674698 case ValDef (_, tpt, _) => isRepeated(tpt)
675699 }
676700 val methName = if (hasRepeatedParam) nme.unapplySeq else nme.unapply
677- val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
678- val unapplyRHS = if (arity == 0 ) Literal (Constant (true )) else Ident (unapplyParam .name)
679- DefDef (methName, derivedTparams, (unapplyParam :: Nil ) :: Nil , TypeTree (), unapplyRHS )
701+ val param = makeSyntheticParameter(tpt = classTypeRef)
702+ val rhs = if (arity == 0 ) Literal (Constant (true )) else Ident (param .name)
703+ DefDef (methName, derivedTparams, (param :: Nil ) :: Nil , TypeTree (), rhs )
680704 .withMods(synthetic)
681705 }
682- companionDefs(companionParent, applyMeths ::: unapplyMeth :: companionMembers)
706+ companionDefs(
707+ companionParents,
708+ applyMeths ::: unapplyMeth :: monoTypeDefs ::: companionMembers)
683709 }
684710 else if (companionMembers.nonEmpty || companionDerived.nonEmpty || isEnum)
685- companionDefs(anyRef, companionMembers)
711+ companionDefs(anyRef :: Nil , companionMembers)
686712 else if (isValueClass) {
687713 impl.constr.vparamss match {
688- case (_ :: Nil ) :: _ => companionDefs(anyRef, Nil )
714+ case (_ :: Nil ) :: _ => companionDefs(anyRef :: Nil , Nil )
689715 case _ => Nil // error will be emitted in typer
690716 }
691717 }
@@ -765,7 +791,7 @@ object desugar {
765791 }
766792
767793 flatTree(cdef1 :: companions ::: implicitWrappers)
768- }
794+ }.reporting(res => i " desugared: $res " , Printers .desugar)
769795
770796 /** Expand
771797 *
0 commit comments