@@ -502,10 +502,12 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
502
502
503
503
def nameOf (tpe : Type ) = tpe.typeSymbol.name
504
504
505
- def mkHListValue (elems : List [Tree ]): Tree =
506
- elems.foldRight(q " _root_.shapeless.HNil " : Tree ) {
507
- case (elem, acc) => q " _root_.shapeless.::( $elem, $acc) "
505
+ def mkHListValue (elems : List [Tree ]): Tree = {
506
+ val cons = objectRef[:: .type ]
507
+ elems.foldRight(objectRef[HNil .type ]) {
508
+ case (elem, acc) => q " $cons( $elem, $acc) "
508
509
}
510
+ }
509
511
510
512
/**
511
513
* Fold `items` into a type using `cons` as a type constructor.
@@ -937,110 +939,110 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics {
937
939
}
938
940
}
939
941
942
+ @ deprecated(" Use CtorDtor.fromTo instead" , " 2.3.9" )
940
943
trait CtorDtor {
941
944
def construct (args : List [Tree ]): Tree
942
945
def binding : (Tree , List [Tree ])
943
946
def reprBinding : (Tree , List [Tree ])
944
947
}
945
948
946
949
object CtorDtor {
947
- def apply ( tpe : Type ) : CtorDtor = {
948
- val sym = tpe.typeSymbol
949
- val isCaseClass = sym.asClass.isCaseClass
950
-
951
- val repWCard = Star ( Ident (termNames. WILDCARD )) // like pq"_*" except that it does work
952
-
953
- def narrow ( tree : Tree , tpe : Type ): Tree =
954
- tpe match {
955
- case ConstantType (c ) =>
956
- q " $c .asInstanceOf[ $tpe ] "
957
- case _ =>
958
- tree
959
- }
950
+ @ deprecated( " Use CtorDtor.fromTo instead " , " 2.3.9 " )
951
+ def apply ( tpe : Type ) : CtorDtor = new CtorDtor {
952
+ private [ this ] val (from, to) =
953
+ fromTo(tpe, TypeTree (tpe))
954
+ private [ this ] val (funs, argss) =
955
+ from.body.collect { case Apply (fun, args) => (fun, args) }.reverse.unzip
956
+ def construct ( args : List [ Tree ] ): Tree =
957
+ funs.headOption.fold(from.body)(ctr => q " $ctr (... ${args :: argss.drop( 1 )} ) " )
958
+ val binding : ( Tree , List [ Tree ] ) =
959
+ (from.pat, argss.headOption.getOrElse( Nil ))
960
+ val reprBinding : ( Tree , List [ Tree ]) =
961
+ (to.pat, to.body.collect { case Apply (_, List (arg, _* )) => arg })
962
+ }
960
963
961
- def narrow1 (tree : Tree , tpe : Type ): Tree =
962
- if (isVararg(tpe))
963
- q " $tree: _* "
964
- else
965
- narrow(tree, tpe)
966
-
967
- def mkCtorDtor0 (elems0 : List [(TermName , Type )]) = {
968
- val elems = elems0.map { case (_, tpe) => (c.freshName(TermName (" pat" )), tpe) }
969
- val pattern = pq " ${companionRef(tpe)}(.. ${elems.map { case (binder, tpe) => if (isVararg(tpe)) pq " $binder @ $repWCard" else pq " $binder" }}) "
970
- val reprPattern =
971
- elems.foldRight(q " _root_.shapeless.HNil " : Tree ) {
972
- case ((bound, _), acc) => pq " _root_.shapeless.::( $bound, $acc) "
973
- }
974
- val nonCaseParamLists : List [List [Tree ]] = List .fill(numNonCaseParamLists(tpe))(Nil )
975
- new CtorDtor {
976
- def construct (args : List [Tree ]): Tree = q " ${companionRef(tpe)}[.. ${tpe.typeArgs}](... ${args :: nonCaseParamLists}) "
977
- def binding : (Tree , List [Tree ]) = (pattern, elems.map { case (binder, tpe) => narrow(q " $binder" , tpe) })
978
- def reprBinding : (Tree , List [Tree ]) = (reprPattern, elems.map { case (binder, tpe) => narrow1(q " $binder" , tpe) })
979
- }
964
+ final def fromTo (tpe : Type , reprTpt : Tree ): (CaseDef , CaseDef ) = {
965
+ import c .internal .gen
966
+
967
+ val wildcard = Ident (termNames.WILDCARD )
968
+ // like pq"_*" except that it does work
969
+ val repWCard = Star (wildcard)
970
+
971
+ def narrow (tree : Tree , tpe : Type ): Tree = tpe match {
972
+ case ConstantType (c) => q " $c.asInstanceOf[ $tpe] "
973
+ case _ => tree
980
974
}
981
975
982
- def mkCtorDtor1 (elems : List [(TermName , TermName , Type )], pattern : Tree , rhs : List [Tree ]) = {
983
- val reprPattern =
984
- elems.foldRight(q " _root_.shapeless.HNil " : Tree ) {
985
- case ((bound, _, _), acc) => pq " _root_.shapeless.::( $bound, $acc) "
986
- }
987
- new CtorDtor {
988
- def construct (args : List [Tree ]): Tree = q " new $tpe(.. $args) "
989
- def binding : (Tree , List [Tree ]) = (pattern, rhs)
990
- def reprBinding : (Tree , List [Tree ]) = (reprPattern, elems.map { case (binder, _, tpe) => narrow1(q " $binder" , tpe) })
976
+ def const (tree : Tree ): CaseDef =
977
+ cq " _ => $tree"
978
+
979
+ def mkHListPattern (elems : List [TermName ]): Tree = {
980
+ val cons = objectRef[:: .type ]
981
+ elems.foldRight(objectRef[HNil .type ]) {
982
+ case (elem, acc) => pq " $cons( $elem, $acc) "
991
983
}
992
984
}
993
985
986
+ def from (fields : List [(TermName , Type )])(construct : List [Tree ] => Tree ): CaseDef = {
987
+ val (pats, args) = fields.map { case (field, tpe) =>
988
+ val pat = c.freshName(field)
989
+ (pat, if (isVararg(tpe)) q " $pat: _* " else narrow(q " $pat" , tpe))
990
+ }.unzip
991
+ cq " ${mkHListPattern(pats)} => ${construct(args)}"
992
+ }
993
+
994
+ def to (pattern : Tree , args : List [Tree ]): CaseDef =
995
+ cq " $pattern => ${mkHListValue(args)}.asInstanceOf[ $reprTpt] "
996
+
997
+ def fromApply (fields : List [(TermName , Type )]): CaseDef = from(fields) { args =>
998
+ val nonCaseArgs = List .fill(numNonCaseParamLists(tpe))(List .empty[Tree ])
999
+ q " ${companionRef(tpe)}[.. ${tpe.typeArgs}](.. $args)(... $nonCaseArgs) "
1000
+ }
1001
+
1002
+ def fromConstructor (fields : List [(TermName , Type )]): CaseDef =
1003
+ from(fields)(args => q " new $tpe(.. $args) " )
1004
+
1005
+ def toUnapply (fields : List [(TermName , Type )]): CaseDef = {
1006
+ val (pats, args) = fields.map { case (field, tpe) =>
1007
+ val pat = c.freshName(field)
1008
+ (Bind (pat, if (isVararg(tpe)) repWCard else wildcard), narrow(Ident (pat), tpe))
1009
+ }.unzip
1010
+ to(pq " ${companionRef(tpe)}(.. $pats) " , args)
1011
+ }
1012
+
1013
+ def toGetters (fields : List [(TermName , Type )]): CaseDef = {
1014
+ val pattern = c.freshName(TermName (" x" ))
1015
+ to(pq " $pattern" , fields.map { case (field, tpe) => narrow(q " $pattern. $field" , tpe) })
1016
+ }
1017
+
994
1018
lowerKind(tpe) match {
995
1019
// case 1: Unit
996
1020
case tpe if tpe =:= typeOf[Unit ] =>
997
- new CtorDtor {
998
- def construct (args : List [Tree ]): Tree = q " () "
999
- def binding : (Tree , List [Tree ]) = (pq " () " , Nil )
1000
- def reprBinding : (Tree , List [Tree ]) = (pq " _root_.shapeless.HNil " , Nil )
1001
- }
1002
-
1021
+ (const(q " () " ), const(objectRef[HNil .type ]))
1003
1022
// case 2: singleton
1004
1023
case tpe if isCaseObjectLike(tpe.typeSymbol.asClass) =>
1005
- val singleton =
1006
- tpe match {
1007
- case SingleType (pre, sym) =>
1008
- c.internal.gen.mkAttributedRef(pre, sym)
1009
- case TypeRef (pre, sym, List ()) if sym.isModule =>
1010
- c.internal.gen.mkAttributedRef(pre, sym.asModule)
1011
- case TypeRef (pre, sym, List ()) if sym.isModuleClass =>
1012
- c.internal.gen.mkAttributedRef(pre, sym.asClass.module)
1013
- case _ =>
1014
- abort(s " Bad case object-like type $tpe" )
1015
- }
1016
- new CtorDtor {
1017
- def construct (args : List [Tree ]): Tree = q " $singleton: $tpe"
1018
- def binding : (Tree , List [Tree ]) = (pq " _: $tpe" , Nil )
1019
- def reprBinding : (Tree , List [Tree ]) = (pq " _root_.shapeless.HNil " , Nil )
1024
+ val singleton = tpe match {
1025
+ case SingleType (pre, sym) => gen.mkAttributedRef(pre, sym)
1026
+ case TypeRef (pre, sym, Nil ) if sym.isModule => gen.mkAttributedRef(pre, sym.asModule)
1027
+ case TypeRef (pre, sym, Nil ) if sym.isModuleClass => gen.mkAttributedRef(pre, sym.asClass.module)
1028
+ case _ => abort(s " Bad case object-like type $tpe" )
1020
1029
}
1021
-
1030
+ (const(singleton), const(objectRef[ HNil . type ]))
1022
1031
// case 3: case class
1023
- case tpe if isCaseClass => mkCtorDtor0(fieldsOf(tpe))
1024
-
1032
+ case tpe if tpe.typeSymbol.asClass.isCaseClass =>
1033
+ val fields = fieldsOf(tpe)
1034
+ (fromApply(fields), toUnapply(fields))
1025
1035
// case 4: exactly one matching public apply/unapply
1026
- case HasApplyUnapply (args) => mkCtorDtor0(args)
1027
-
1036
+ case HasApplyUnapply (args) =>
1037
+ (fromApply(args), toUnapply(args))
1028
1038
// case 5: concrete, exactly one public constructor with matching public unapply
1029
1039
case HasCtorUnapply (args) =>
1030
- val elems = args.map { case (name, tpe) => (TermName (c.freshName(" pat" )), name, tpe) }
1031
- val pattern = pq " ${companionRef(tpe)}(.. ${elems.map { case (binder, _, tpe) => if (isVararg(tpe)) pq " $binder @ $repWCard" else pq " $binder" }}) "
1032
- val rhs = elems.map { case (binder, _, tpe) => narrow(q " $binder" , tpe) }
1033
- mkCtorDtor1(elems, pattern, rhs)
1034
-
1040
+ (fromConstructor(args), toUnapply(args))
1035
1041
// case 6: concrete, exactly one public constructor with matching accessible fields
1036
1042
case HasUniqueCtor (args) =>
1037
- val elems = args.map { case (name, tpe) => (TermName (c.freshName(" pat" )), name, tpe) }
1038
- val binder = TermName (c.freshName(" pat" ))
1039
- val pattern = pq " $binder"
1040
- val rhs = elems.map { case (_, name, tpe) => narrow(q " $binder. $name" , tpe) }
1041
- mkCtorDtor1(elems, pattern, rhs)
1042
-
1043
- case _ => abort(s " Bad product type $tpe" )
1043
+ (fromConstructor(args), toGetters(args))
1044
+ case _ =>
1045
+ abort(s " Bad product type $tpe" )
1044
1046
}
1045
1047
}
1046
1048
}
@@ -1062,11 +1064,7 @@ class GenericMacros(val c: whitebox.Context) extends CaseClassMacros {
1062
1064
1063
1065
def mkProductGeneric (tpe : Type ): Tree = {
1064
1066
val repr = mkHListTpe(fieldsOf(tpe).map(_._2))
1065
- val ctorDtor = CtorDtor (tpe)
1066
- val (p, ts) = ctorDtor.binding
1067
- val to = cq " $p => ${mkHListValue(ts)}.asInstanceOf[ $repr] "
1068
- val (rp, rts) = ctorDtor.reprBinding
1069
- val from = cq " $rp => ${ctorDtor.construct(rts)}"
1067
+ val (from, to) = CtorDtor .fromTo(tpe, TypeTree (repr))
1070
1068
q " $generic.instance[ $tpe, $repr]({ case $to }, { case $from }) "
1071
1069
}
1072
1070
0 commit comments