@@ -49,6 +49,15 @@ let fresh_type_maker type_decl =
49
49
bound := newvar :: ! bound;
50
50
Typ. var newvar
51
51
52
+ (* * [pp_type_of_decl decl] returns type for [pp_xxx] where xxx is the type name.
53
+ For example, for [type ('a, 'b) map] it produces
54
+ [(formatter -> 'a -> unit) -> (formatter -> 'b -> unit) -> formatter -> ('a, 'b) map -> unit].
55
+ For GADTs, the optional parameter [refined_param_pos] specifies the index of refined
56
+ parameters i.e., [0] for ['a] in [type ('a, 'b) map] and [1] for ['b].
57
+ If present, the type parameter is rendered as any [type _] type, to mark the type parameter is
58
+ actually ignored. For example, for [type ('a, 'b) map] with [refined_param_pos=[1]], it produces
59
+ [(formatter -> 'a -> unit) -> (formatter -> _ -> unit) -> formatter -> ('a, 'b) map -> unit]
60
+ (see [_] instead of ['b] in the type for the second argument). *)
52
61
let pp_type_of_decl ?(refined_param_pos =[] ) type_decl =
53
62
let loc = type_decl.ptype_loc in
54
63
let typ = Ppx_deriving. core_type_of_type_decl type_decl in
@@ -60,6 +69,8 @@ let pp_type_of_decl ?(refined_param_pos=[]) type_decl =
60
69
type_decl
61
70
[% type : Ppx_deriving_runtime.Format. formatter -> [% t typ] -> Ppx_deriving_runtime. unit ]
62
71
72
+ (* * Same as [pp_type_of_decl] but type parameters are rendered as locally abstract types rather than
73
+ type variables. *)
63
74
let pp_type_of_decl_newtype ?(refined_param_pos =[] ) type_decl =
64
75
let loc = type_decl.ptype_loc in
65
76
let typ = Ppx_deriving. core_type_of_type_decl_with_newtype type_decl in
@@ -70,6 +81,8 @@ let pp_type_of_decl_newtype ?(refined_param_pos=[]) type_decl =
70
81
type_decl
71
82
[% type : Ppx_deriving_runtime.Format. formatter -> [% t typ] -> Ppx_deriving_runtime. unit ]
72
83
84
+ (* * [show_type_of_decl decl] returns type for [show_xxx] where xxx is the type name.
85
+ The optional parameter [refined_param_pos] behaves same as [pp_type_of_decl]. *)
73
86
let show_type_of_decl ?(refined_param_pos =[] ) type_decl =
74
87
let loc = type_decl.ptype_loc in
75
88
let typ = Ppx_deriving. core_type_of_type_decl type_decl in
@@ -87,9 +100,13 @@ let sig_of_type type_decl =
87
100
Sig. value (Val. mk (mknoloc (Ppx_deriving. mangle_type_decl (`Prefix " show" ) type_decl))
88
101
(show_type_of_decl type_decl))]
89
102
90
- let rec expr_of_typ ~effective_variables quoter typ =
103
+ (* * [expr_of_typ typ] returns an expression that pretty-prints a value of the given type.
104
+ For type variables available in [type_params], it puts [poly_N] which pretty-prints
105
+ the type parameter [N], assuming that [poly_N] is supplied by the caller.
106
+ Otherwise, it is rendered as a 'degenerate' pretty printer which is never called. *)
107
+ let rec expr_of_typ ~type_params quoter typ =
91
108
let loc = typ.ptyp_loc in
92
- let expr_of_typ = expr_of_typ ~effective_variables quoter in
109
+ let expr_of_typ = expr_of_typ ~type_params quoter in
93
110
match Attribute. get ct_attr_printer typ with
94
111
| Some printer -> [% expr [% e wrap_printer quoter printer] fmt]
95
112
| None ->
@@ -203,13 +220,14 @@ let rec expr_of_typ ~effective_variables quoter typ =
203
220
in
204
221
Exp. function_ cases
205
222
| { ptyp_desc = Ptyp_var name } ->
206
- if List. mem name effective_variables then
223
+ if List. mem name type_params then
207
224
[% expr [% e evar (" poly_" ^ name)] fmt]
208
225
else
209
- (* We assume some 'calling convention' here: for type variables not appear in the declaration,
210
- we supply a 'degenerate' pretty printer which is never called, as we deem them 'refined' to
211
- a concrete type at some point. *)
212
- [% expr (fun () (* never type here*) -> failwith " impossible" )]
226
+ (* We assume a 'calling convention' here: type variables not in the type parameter list will be refined
227
+ by the GADT taking that variable as an argument, and thus pretty printer for that type is never called.
228
+ For such a printer, we supply a 'degenerate' one which could not be called in any ways.
229
+ If this invariant breaks, type error will be reported. *)
230
+ [% expr (fun (_ : [`this_type_is_refined_and_no_pretty_printer_is_supplied] ) -> failwith " impossible" )]
213
231
| { ptyp_desc = Ptyp_alias (typ , _ ) } -> expr_of_typ typ
214
232
| { ptyp_loc } ->
215
233
raise_errorf ~loc: ptyp_loc " %s cannot be derived for %s"
@@ -241,18 +259,17 @@ let refined_param_pos_of_type_decl type_decl =
241
259
| (_idx , {ptyp_desc =Ptyp_var var } ) when List. mem var type_variables ->
242
260
(* The type parameter is a variable. It is likely that the constructor does not refine the variable.
243
261
However, there are cases that even if the constructor does not refine the type parameter,
244
- the constructor's argument type does. In that case, the type parameter should be considered refined as well.
245
- To express that the type parameter is refined, the programmer can change the type parameter in the return type
246
- to a type that is not same as the one in the declaration.
247
- For example,
262
+ the constructor's argument type does. To express that the type parameter is refined in such cases,
263
+ we introduce a convention that the refined type parameter will have different name from the one in the return type of
264
+ some constructor. For example
248
265
type 'a term = Var : string * 'a typ -> 'a term | ...
249
- Here, when the programmer knows that the parameter 'a in type 'a type is refined, there should be a way to express that.
250
- To express that, the programmer change the return type of the constructor to be different from the declaration, say 'v,
266
+ Here, if the programmer knows that the parameter 'a in type 'a type is refined, the programmer change the return type
267
+ of the constructor to be different from the declaration, say 'v:
251
268
type 'a term = Var : string * 'v typ -> 'v term | ...
252
269
So that poly_a is never called to print the type.
253
270
254
271
Note that, there are cases that the constructor itself does not refine the paramter but its declaration is GADT-ish:
255
- existential variables.
272
+ use of existential variables.
256
273
If one needs existential type variables while a type parameter is not refined, the programmer would keep using
257
274
the same variable name as in the declaration, for example:
258
275
type 'state transition = Print : 'v term * 'state -> 'state transition | ...
@@ -269,11 +286,11 @@ let refined_param_pos_of_type_decl type_decl =
269
286
let str_of_type ~with_path ~path ({ ptype_loc = loc } as type_decl ) =
270
287
let quoter = Ppx_deriving. create_quoter () in
271
288
let path = Ppx_deriving. path_of_type_decl ~path type_decl in
272
- let type_variables = Ppx_deriving. type_param_names_of_type_decl type_decl in
289
+ let type_params = Ppx_deriving. type_param_names_of_type_decl type_decl in
273
290
let prettyprinter =
274
291
match type_decl.ptype_kind, type_decl.ptype_manifest with
275
292
| Ptype_abstract , Some manifest ->
276
- [% expr fun fmt -> [% e expr_of_typ ~effective_variables: type_variables quoter manifest]]
293
+ [% expr fun fmt -> [% e expr_of_typ ~type_params quoter manifest]]
277
294
| Ptype_variant constrs , _ ->
278
295
let cases =
279
296
constrs |> List. map (fun ({ pcd_name = { txt = name' } ; pcd_args; pcd_attributes } as constr ) ->
@@ -304,7 +321,7 @@ let str_of_type ~with_path ~path ({ ptype_loc = loc } as type_decl) =
304
321
(app (wrap_printer quoter printer) ([% expr fmt] :: args))
305
322
| None , Pcstr_tuple (typs ) ->
306
323
let args =
307
- List. mapi (fun i typ -> app (expr_of_typ ~effective_variables: type_variables quoter typ) [evar (argn i)]) typs in
324
+ List. mapi (fun i typ -> app (expr_of_typ ~type_params quoter typ) [evar (argn i)]) typs in
308
325
let printer =
309
326
match args with
310
327
| [] -> [% expr Ppx_deriving_runtime.Format. pp_print_string fmt [% e str constr_name]]
@@ -326,7 +343,7 @@ let str_of_type ~with_path ~path ({ ptype_loc = loc } as type_decl) =
326
343
labels |> List. map (fun ({ pld_name = { txt = n } ; _ } as pld ) ->
327
344
[% expr
328
345
Ppx_deriving_runtime.Format. fprintf fmt " @[%s =@ " [% e str n];
329
- [% e expr_of_label_decl ~effective_variables: type_variables quoter pld]
346
+ [% e expr_of_label_decl ~type_params quoter pld]
330
347
[% e evar (argl n)];
331
348
Ppx_deriving_runtime.Format. fprintf fmt " @]"
332
349
])
@@ -348,7 +365,7 @@ let str_of_type ~with_path ~path ({ ptype_loc = loc } as type_decl) =
348
365
let field_name = if i = 0 then expand_path ~with_path ~path name else name in
349
366
[% expr
350
367
Ppx_deriving_runtime.Format. fprintf fmt " @[%s =@ " [% e str field_name];
351
- [% e expr_of_label_decl ~effective_variables: type_variables quoter pld]
368
+ [% e expr_of_label_decl ~type_params quoter pld]
352
369
[% e Exp. field (evar " x" ) (mknoloc (Lident name))];
353
370
Ppx_deriving_runtime.Format. fprintf fmt " @]"
354
371
])
@@ -434,7 +451,7 @@ let derive_extension =
434
451
Ast_pattern. (ptyp __) (fun ~ctxt ->
435
452
let loc = Expansion_context.Extension. extension_point_loc ctxt in
436
453
Ppx_deriving. with_quoter (fun quoter typ ->
437
- [% expr fun x -> Ppx_deriving_runtime.Format. asprintf " %a" (fun fmt -> [% e expr_of_typ ~effective_variables : [] quoter typ]) x]))
454
+ [% expr fun x -> Ppx_deriving_runtime.Format. asprintf " %a" (fun fmt -> [% e expr_of_typ ~type_params : [] quoter typ]) x]))
438
455
let derive_transformation =
439
456
Driver. register_transformation
440
457
deriver
0 commit comments