@@ -755,87 +755,6 @@ object JsonCodecMaker {
755
755
def isEnumOrModuleValue (tpe : TypeRepr ): Boolean = tpe.isSingleton &&
756
756
(tpe.typeSymbol.flags.is(Flags .Module ) || tpe.termSymbol.flags.is(Flags .Enum ))
757
757
758
- def adtChildren (tpe : TypeRepr ): Seq [TypeRepr ] = { // TODO: explore yet one variant with mirrors
759
- def resolveParentTypeArg (child : Symbol , fromNudeChildTarg : TypeRepr , parentTarg : TypeRepr ,
760
- binding : Map [String , TypeRepr ]): Map [String , TypeRepr ] =
761
- if (fromNudeChildTarg.typeSymbol.isTypeParam) { // TODO: check for paramRef instead ?
762
- val paramName = fromNudeChildTarg.typeSymbol.name
763
- binding.get(paramName) match
764
- case None => binding.updated(paramName, parentTarg)
765
- case Some (oldBinding) =>
766
- if (oldBinding =:= parentTarg) binding
767
- else fail(s " Type parameter $paramName in class ${child.name} appeared in the constructor of " +
768
- s " ${tpe.show} two times differently, with ${oldBinding.show} and ${parentTarg.show}" )
769
- } else if (fromNudeChildTarg <:< parentTarg) binding // TODO: assure parentTag is covariant, get covariance from type parameters
770
- else {
771
- (fromNudeChildTarg, parentTarg) match
772
- case (AppliedType (ctycon, ctargs), AppliedType (ptycon, ptargs)) =>
773
- ctargs.zip(ptargs).foldLeft(resolveParentTypeArg(child, ctycon, ptycon, binding)) { (b, e) =>
774
- resolveParentTypeArg(child, e._1, e._2, b)
775
- }
776
- case _ => fail(s " Failed unification of type parameters of ${tpe.show} from child $child - " +
777
- s " ${fromNudeChildTarg.show} and ${parentTarg.show}" )
778
- }
779
-
780
- def resolveParentTypeArgs (child : Symbol , nudeChildParentTags : List [TypeRepr ], parentTags : List [TypeRepr ],
781
- binding : Map [String , TypeRepr ]): Map [String , TypeRepr ] =
782
- nudeChildParentTags.zip(parentTags).foldLeft(binding)((s, e) => resolveParentTypeArg(child, e._1, e._2, s))
783
-
784
- tpe.typeSymbol.children.map { sym =>
785
- if (sym.isType) {
786
- if (sym.name == " <local child>" ) // problem - we have no other way to find this other return the name
787
- fail(s " Local child symbols are not supported, please consider change ' ${tpe.show}' or implement a " +
788
- " custom implicitly accessible codec" )
789
- val nudeSubtype = TypeIdent (sym).tpe
790
- val tpeArgsFromChild = typeArgs(nudeSubtype.baseType(tpe.typeSymbol))
791
- nudeSubtype.memberType(sym.primaryConstructor) match
792
- case MethodType (_, _, resTp) => resTp
793
- case PolyType (names, bounds, resPolyTp) =>
794
- val targs = typeArgs(tpe)
795
- val tpBinding = resolveParentTypeArgs(sym, tpeArgsFromChild, targs, Map .empty)
796
- val ctArgs = names.map { name =>
797
- tpBinding.getOrElse(name, fail(s " Type parameter $name of $sym can't be deduced from " +
798
- s " type arguments of ${tpe.show}. Please provide a custom implicitly accessible codec for it. " ))
799
- }
800
- val polyRes = resPolyTp match
801
- case MethodType (_, _, resTp) => resTp
802
- case other => other // hope we have no multiple typed param lists yet.
803
- if (ctArgs.isEmpty) polyRes
804
- else polyRes match
805
- case AppliedType (base, _) => base.appliedTo(ctArgs)
806
- case AnnotatedType (AppliedType (base, _), annot) => AnnotatedType (base.appliedTo(ctArgs), annot)
807
- case _ => polyRes.appliedTo(ctArgs)
808
- case other => fail(s " Primary constructior for ${tpe.show} is not MethodType or PolyType but $other" )
809
- } else if (sym.isTerm) Ref (sym).tpe
810
- else fail(" Only Scala classes & objects are supported for ADT leaf classes. Please consider using of " +
811
- s " them for ADT with base ' ${tpe.show}' or provide a custom implicitly accessible codec for the ADT base. " +
812
- s " Failed symbol: $sym (fullName= ${sym.fullName}) \n " )
813
- }
814
- }
815
-
816
- def adtLeafClasses (adtBaseTpe : TypeRepr ): Seq [TypeRepr ] = {
817
- def collectRecursively (tpe : TypeRepr ): Seq [TypeRepr ] =
818
- val leafTpes = adtChildren(tpe).flatMap { subTpe =>
819
- if (isEnumOrModuleValue(subTpe) || subTpe =:= TypeRepr .of[None .type ]) subTpe :: Nil
820
- else if (isSealedClass(subTpe)) collectRecursively(subTpe)
821
- else if (isNonAbstractScalaClass(subTpe)) subTpe :: Nil
822
- else fail(if (subTpe.typeSymbol.flags.is(Flags .Abstract ) || subTpe.typeSymbol.flags.is(Flags .Trait ) ) {
823
- " Only sealed intermediate traits or abstract classes are supported. Please consider using of them " +
824
- s " for ADT with base ' ${adtBaseTpe.show}' or provide a custom implicitly accessible codec for the ADT base. "
825
- } else {
826
- " Only Scala classes & objects are supported for ADT leaf classes. Please consider using of them " +
827
- s " for ADT with base ' ${adtBaseTpe.show}' or provide a custom implicitly accessible codec for the ADT base. "
828
- })
829
- }
830
- if (isNonAbstractScalaClass(tpe)) leafTpes :+ tpe
831
- else leafTpes
832
-
833
- val classes = collectRecursively(adtBaseTpe).distinct
834
- if (classes.isEmpty) fail(s " Cannot find leaf classes for ADT base ' ${adtBaseTpe.show}'. " +
835
- " Please add them or provide a custom implicitly accessible codec for the ADT base." )
836
- classes
837
- }
838
-
839
758
def isOption (tpe : TypeRepr , types : List [TypeRepr ]): Boolean = tpe <:< TypeRepr .of[Option [_]] &&
840
759
(cfg.skipNestedOptionValues || ! types.headOption.exists(_ <:< TypeRepr .of[Option [_]]))
841
760
@@ -1122,6 +1041,90 @@ object JsonCodecMaker {
1122
1041
(cfg.inlineOneValueClasses && isNonAbstractScalaClass(tpe) && ! isCollection(tpe) && getClassInfo(tpe).fields.size == 1 ||
1123
1042
tpe <:< TypeRepr .of[AnyVal ])
1124
1043
1044
+ def adtChildren (tpe : TypeRepr ): Seq [TypeRepr ] = { // TODO: explore yet one variant with mirrors
1045
+ def resolveParentTypeArg (child : Symbol , fromNudeChildTarg : TypeRepr , parentTarg : TypeRepr ,
1046
+ binding : Map [String , TypeRepr ]): Map [String , TypeRepr ] =
1047
+ if (fromNudeChildTarg.typeSymbol.isTypeParam) { // TODO: check for paramRef instead ?
1048
+ val paramName = fromNudeChildTarg.typeSymbol.name
1049
+ binding.get(paramName) match
1050
+ case None => binding.updated(paramName, parentTarg)
1051
+ case Some (oldBinding) =>
1052
+ if (oldBinding =:= parentTarg) binding
1053
+ else fail(s " Type parameter $paramName in class ${child.name} appeared in the constructor of " +
1054
+ s " ${tpe.show} two times differently, with ${oldBinding.show} and ${parentTarg.show}" )
1055
+ } else if (fromNudeChildTarg <:< parentTarg) binding // TODO: assure parentTag is covariant, get covariance from type parameters
1056
+ else {
1057
+ (fromNudeChildTarg, parentTarg) match
1058
+ case (AppliedType (ctycon, ctargs), AppliedType (ptycon, ptargs)) =>
1059
+ ctargs.zip(ptargs).foldLeft(resolveParentTypeArg(child, ctycon, ptycon, binding)) { (b, e) =>
1060
+ resolveParentTypeArg(child, e._1, e._2, b)
1061
+ }
1062
+ case _ => fail(s " Failed unification of type parameters of ${tpe.show} from child $child - " +
1063
+ s " ${fromNudeChildTarg.show} and ${parentTarg.show}" )
1064
+ }
1065
+
1066
+ def resolveParentTypeArgs (child : Symbol , nudeChildParentTags : List [TypeRepr ], parentTags : List [TypeRepr ],
1067
+ binding : Map [String , TypeRepr ]): Map [String , TypeRepr ] =
1068
+ nudeChildParentTags.zip(parentTags).foldLeft(binding)((s, e) => resolveParentTypeArg(child, e._1, e._2, s))
1069
+
1070
+ tpe.typeSymbol.children.map { sym =>
1071
+ if (sym.isType) {
1072
+ if (sym.name == " <local child>" ) // problem - we have no other way to find this other return the name
1073
+ fail(s " Local child symbols are not supported, please consider change ' ${tpe.show}' or implement a " +
1074
+ " custom implicitly accessible codec" )
1075
+ val nudeSubtype = TypeIdent (sym).tpe
1076
+ val tpeArgsFromChild = typeArgs(nudeSubtype.baseType(tpe.typeSymbol))
1077
+ nudeSubtype.memberType(sym.primaryConstructor) match
1078
+ case MethodType (_, _, resTp) => resTp
1079
+ case PolyType (names, bounds, resPolyTp) =>
1080
+ val targs = typeArgs(tpe)
1081
+ val tpBinding = resolveParentTypeArgs(sym, tpeArgsFromChild, targs, Map .empty)
1082
+ val ctArgs = names.map { name =>
1083
+ tpBinding.getOrElse(name, fail(s " Type parameter $name of $sym can't be deduced from " +
1084
+ s " type arguments of ${tpe.show}. Please provide a custom implicitly accessible codec for it. " ))
1085
+ }
1086
+ val polyRes = resPolyTp match
1087
+ case MethodType (_, _, resTp) => resTp
1088
+ case other => other // hope we have no multiple typed param lists yet.
1089
+ if (ctArgs.isEmpty) polyRes
1090
+ else polyRes match
1091
+ case AppliedType (base, _) => base.appliedTo(ctArgs)
1092
+ case AnnotatedType (AppliedType (base, _), annot) => AnnotatedType (base.appliedTo(ctArgs), annot)
1093
+ case _ => polyRes.appliedTo(ctArgs)
1094
+ case other => fail(s " Primary constructior for ${tpe.show} is not MethodType or PolyType but $other" )
1095
+ } else if (sym.isTerm) Ref (sym).tpe
1096
+ else fail(" Only Scala classes & objects are supported for ADT leaf classes. Please consider using of " +
1097
+ s " them for ADT with base ' ${tpe.show}' or provide a custom implicitly accessible codec for the ADT base. " +
1098
+ s " Failed symbol: $sym (fullName= ${sym.fullName}) \n " )
1099
+ }
1100
+ }
1101
+
1102
+ def adtLeafClasses (adtBaseTpe : TypeRepr ): Seq [TypeRepr ] = {
1103
+ def collectRecursively (tpe : TypeRepr ): Seq [TypeRepr ] =
1104
+ val leafTpes = adtChildren(tpe).flatMap { subTpe =>
1105
+ if (isEnumOrModuleValue(subTpe) || subTpe =:= TypeRepr .of[None .type ]) subTpe :: Nil
1106
+ else if (isSealedClass(subTpe)) collectRecursively(subTpe)
1107
+ else if (isValueClass(subTpe)) {
1108
+ fail(" 'AnyVal' and one value classes with 'CodecMakerConfig.withInlineOneValueClasses(true)' are not " +
1109
+ s " supported as leaf classes for ADT with base ' ${adtBaseTpe.show}'. " )
1110
+ } else if (isNonAbstractScalaClass(subTpe)) subTpe :: Nil
1111
+ else fail(if (subTpe.typeSymbol.flags.is(Flags .Abstract ) || subTpe.typeSymbol.flags.is(Flags .Trait ) ) {
1112
+ " Only sealed intermediate traits or abstract classes are supported. Please consider using of them " +
1113
+ s " for ADT with base ' ${adtBaseTpe.show}' or provide a custom implicitly accessible codec for the ADT base. "
1114
+ } else {
1115
+ " Only Scala classes & objects are supported for ADT leaf classes. Please consider using of them " +
1116
+ s " for ADT with base ' ${adtBaseTpe.show}' or provide a custom implicitly accessible codec for the ADT base. "
1117
+ })
1118
+ }
1119
+ if (isNonAbstractScalaClass(tpe)) leafTpes :+ tpe
1120
+ else leafTpes
1121
+
1122
+ val classes = collectRecursively(adtBaseTpe).distinct
1123
+ if (classes.isEmpty) fail(s " Cannot find leaf classes for ADT base ' ${adtBaseTpe.show}'. " +
1124
+ " Please add them or provide a custom implicitly accessible codec for the ADT base." )
1125
+ classes
1126
+ }
1127
+
1125
1128
def genReadKey [T : Type ](types : List [TypeRepr ], in : Expr [JsonReader ])(using Quotes ): Expr [T ] =
1126
1129
val tpe = types.head
1127
1130
val implKeyCodec = findImplicitKeyCodec(types)
0 commit comments