@@ -71,8 +71,16 @@ let ld_attr_json_drop_default =
7171 Attribute. get
7272 (Attribute. declare " json.drop_default"
7373 Attribute.Context. label_declaration
74- Ast_pattern. (pstr nil)
75- () )
74+ Ast_pattern. (
75+ pstr (map0 ~f: None nil) (* flag form *)
76+ ||| single_expr_payload (map1 ~f: Option. some __)
77+ (* comparison function *) )
78+ (fun x -> x))
79+
80+ let ld_attr_json_drop_default_if_json_equal =
81+ Attribute. get
82+ (Attribute. declare_flag " json.drop_default_if_json_equal"
83+ Attribute.Context. label_declaration)
7684
7785let ld_attr_default ld =
7886 match ld_attr_json_default ld with
@@ -84,14 +92,75 @@ let ld_attr_default ld =
8492 Some [% expr Stdlib.Option. None ]
8593 | None -> None )
8694
95+ let rec equal_of_core_type ~loc ct =
96+ match ct.ptyp_desc with
97+ | Ptyp_constr ({ txt = Lident name ; _ } , args ) ->
98+ let fn = pexp_ident ~loc { loc; txt = lident (" equal_" ^ name) } in
99+ List. fold_left (List. rev args) ~init: fn ~f: (fun acc arg ->
100+ pexp_apply ~loc acc [ Nolabel , equal_of_core_type ~loc arg ])
101+ | Ptyp_constr ({ txt = Ldot (prefix , name ); _ } , args ) ->
102+ let name = if name = " t" then " equal" else " equal_" ^ name in
103+ let fn = pexp_ident ~loc { loc; txt = Ldot (prefix, name) } in
104+ List. fold_left (List. rev args) ~init: fn ~f: (fun acc arg ->
105+ pexp_apply ~loc acc [ Nolabel , equal_of_core_type ~loc arg ])
106+ | Ptyp_var name ->
107+ pexp_ident ~loc { loc; txt = lident (" equal_" ^ name) }
108+ | _ ->
109+ Location. raise_errorf ~loc
110+ " [@drop_default]: cannot derive equal for this type, provide a \
111+ comparison function via [@json.drop_default f]"
112+
87113let ld_drop_default ld =
88114 let loc = ld.pld_loc in
89- match ld_attr_json_drop_default ld, ld_attr_json_option ld with
90- | Some () , None ->
115+ let drop_default = ld_attr_json_drop_default ld in
116+ let drop_json_equal = ld_attr_json_drop_default_if_json_equal ld in
117+ match drop_default, drop_json_equal with
118+ | Some _ , Some () ->
91119 Location. raise_errorf ~loc
92- " found [@drop_default] attribute without [@option]"
93- | Some () , Some () -> `Drop_option
94- | None , _ -> `No
120+ " [@drop_default] and [@drop_default_if_json_equal] are mutually \
121+ exclusive"
122+ | None , None -> `No
123+ | None , Some () -> begin
124+ match ld_attr_json_option ld, ld_attr_json_default ld with
125+ | None , Some def -> `Drop_default_if_json_equal def
126+ | Some () , None ->
127+ Location. raise_errorf ~loc
128+ " [@drop_default_if_json_equal] cannot be used with \
129+ [@option]. Use [@drop_default] instead."
130+ | Some () , Some _ ->
131+ Location. raise_errorf ~loc
132+ " [@drop_default_if_json_equal] cannot be used with both \
133+ [@option] and [@default]. Use [@json.default] only."
134+ | None , None ->
135+ Location. raise_errorf ~loc
136+ " [@drop_default_if_json_equal] requires [@json.default]"
137+ end
138+ | Some None , None -> begin
139+ (* flag form: [@json.drop_default] *)
140+ match ld_attr_json_option ld, ld_attr_json_default ld with
141+ | Some () , None -> `Drop_option
142+ | None , Some def ->
143+ let cmp = equal_of_core_type ~loc ld.pld_type in
144+ `Drop_default (cmp, def)
145+ | Some () , Some _ ->
146+ Location. raise_errorf ~loc
147+ " [@drop_default] cannot be used with both [@option] and \
148+ [@default]"
149+ | None , None ->
150+ Location. raise_errorf ~loc
151+ " [@drop_default] requires either [@option] or [@default]"
152+ end
153+ | Some (Some cmp ), None -> begin
154+ (* expression form: [@json.drop_default expr] *)
155+ match ld_attr_json_option ld, ld_attr_json_default ld with
156+ | None , Some def -> `Drop_default (cmp, def)
157+ | Some () , _ ->
158+ Location. raise_errorf ~loc
159+ " [@drop_default expr] cannot be used with [@option]"
160+ | None , None ->
161+ Location. raise_errorf ~loc
162+ " [@drop_default expr] requires [@default]"
163+ end
95164
96165let expand_via ~what ~through make ~ctxt (rec_flag , tds ) =
97166 let loc = Expansion_context.Deriver. derived_item_loc ctxt in
0 commit comments