@@ -76,13 +76,18 @@ trait ProductTypesPlatform extends ProductTypes { this: DefinitionsPlatform =>
76
76
val A = TypeRepr .of[A ]
77
77
val sym = A .typeSymbol
78
78
79
- // case class fields appear once in sym.caseFields as vals and once in sym.declaredMethods as methods
80
- // additionally sometimes they appear twice! once as "val name" and once as "method name " (notice space at the end
81
- // of name). This breaks matching by order (tuples) but has to be fixed in a way that doesn't filter out fields
82
- // for normal cases.
79
+ def sameNamedSymbolIn (syms : Set [Symbol ]): Symbol => Boolean = {
80
+ val names = syms.map(_.name.trim).toSet
81
+ sym2 => names(sym2.name.trim)
82
+ }
83
+
83
84
val (argVals, bodyVals) = {
84
- val fields = ListSet .from(
85
- sym.declaredFields.zipWithIndex
85
+ // case class fields appear once in sym.caseFields as vals and once in sym.declaredMethods as methods
86
+ // additionally sometimes they appear twice! once as "val name" and once as "method name " (notice space at the end
87
+ // of name). This breaks matching by order (tuples) but has to be fixed in a way that doesn't filter out fields
88
+ // for normal cases.
89
+ def sanitize (syms : List [Symbol ]): List [Symbol ] =
90
+ syms.zipWithIndex
86
91
.groupBy(_._1.name.trim)
87
92
.view
88
93
.map {
@@ -93,27 +98,40 @@ trait ProductTypesPlatform extends ProductTypes { this: DefinitionsPlatform =>
93
98
.toList
94
99
.sortBy(_._2)
95
100
.map(_._1)
96
- )
97
- val args = ListSet .from(paramListsOf(A , sym.primaryConstructor).flatten.filter(fields))
98
- val body = fields.filterNot(args)
99
- (args, body)
101
+
102
+ // Make sure that: we only use public definitions, output is sorted by the order of definition
103
+ def sortedPublicUnique (syms : List [Symbol ]): ListSet [Symbol ] =
104
+ ListSet .from(sanitize(syms.filter(isPublic)).sorted)
105
+
106
+ // To distinct between vals defined in constructor and in body
107
+ val isArg = sameNamedSymbolIn(paramListsOf(A , sym.primaryConstructor).flatten.filter(isPublic).toSet)
108
+
109
+ val caseFields = sortedPublicUnique(sym.caseFields)
110
+
111
+ // As silly as it looks: when I tried to get rid of caseFields and handle everything with fieldMembers
112
+ // the result was really bad. It probably can be done, but it's error prone at best.
113
+ val (argFields, bodyFields) =
114
+ sortedPublicUnique(sym.fieldMembers.filterNot(sameNamedSymbolIn(caseFields))).partition(isArg)
115
+
116
+ (caseFields ++ argFields, bodyFields)
100
117
}
101
118
val accessorsAndGetters = ListSet .from(
102
119
sym.methodMembers
103
120
.filterNot(_.paramSymss.exists(_.exists(_.isType))) // remove methods with type parameters
104
121
.filterNot(isGarbageSymbol)
105
122
.filter(isAccessor)
106
- .filterNot(argVals)
107
- .filterNot(bodyVals)
123
+ .filter(isPublic)
124
+ .filterNot(sameNamedSymbolIn(argVals))
125
+ .filterNot(sameNamedSymbolIn(bodyVals))
126
+ .sorted
108
127
)
109
128
110
129
val isArgumentField = argVals
111
130
val isBodyField = bodyVals
112
131
val localDefinitions = (sym.declaredMethods ++ sym.declaredFields).toSet
113
132
114
- // if we are taking caseFields but then we also are using ALL fieldMembers shouldn't we just use fieldMembers?
115
- (argVals ++ bodyVals ++ accessorsAndGetters).filter(_.isPublic).map { getter =>
116
- val name = getter.name
133
+ (argVals ++ bodyVals ++ accessorsAndGetters).map { getter =>
134
+ val name = getter.name.trim
117
135
val tpe = ExistentialType (returnTypeOf[Any ](A , getter))
118
136
def conformToIsGetters = ! name.take(2 ).equalsIgnoreCase(" is" ) || tpe.Underlying <:< Type [Boolean ]
119
137
name -> tpe.mapK[Product .Getter [A , * ]] { implicit Tpe : Type [tpe.Underlying ] => _ =>
0 commit comments