Skip to content

Commit e7edaa4

Browse files
committed
more docs
1 parent 9553805 commit e7edaa4

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

src_plugins/show/ppx_deriving_show.ml

+37-20
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ let fresh_type_maker type_decl =
4949
bound := newvar :: !bound;
5050
Typ.var newvar
5151

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). *)
5261
let pp_type_of_decl ?(refined_param_pos=[]) type_decl =
5362
let loc = type_decl.ptype_loc in
5463
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 =
6069
type_decl
6170
[%type: Ppx_deriving_runtime.Format.formatter -> [%t typ] -> Ppx_deriving_runtime.unit]
6271

72+
(** Same as [pp_type_of_decl] but type parameters are rendered as locally abstract types rather than
73+
type variables. *)
6374
let pp_type_of_decl_newtype ?(refined_param_pos=[]) type_decl =
6475
let loc = type_decl.ptype_loc in
6576
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 =
7081
type_decl
7182
[%type: Ppx_deriving_runtime.Format.formatter -> [%t typ] -> Ppx_deriving_runtime.unit]
7283

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]. *)
7386
let show_type_of_decl ?(refined_param_pos=[]) type_decl =
7487
let loc = type_decl.ptype_loc in
7588
let typ = Ppx_deriving.core_type_of_type_decl type_decl in
@@ -87,9 +100,13 @@ let sig_of_type type_decl =
87100
Sig.value (Val.mk (mknoloc (Ppx_deriving.mangle_type_decl (`Prefix "show") type_decl))
88101
(show_type_of_decl type_decl))]
89102

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 =
91108
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
93110
match Attribute.get ct_attr_printer typ with
94111
| Some printer -> [%expr [%e wrap_printer quoter printer] fmt]
95112
| None ->
@@ -203,13 +220,14 @@ let rec expr_of_typ ~effective_variables quoter typ =
203220
in
204221
Exp.function_ cases
205222
| { ptyp_desc = Ptyp_var name } ->
206-
if List.mem name effective_variables then
223+
if List.mem name type_params then
207224
[%expr [%e evar ("poly_"^name)] fmt]
208225
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")]
213231
| { ptyp_desc = Ptyp_alias (typ, _) } -> expr_of_typ typ
214232
| { ptyp_loc } ->
215233
raise_errorf ~loc:ptyp_loc "%s cannot be derived for %s"
@@ -241,18 +259,17 @@ let refined_param_pos_of_type_decl type_decl =
241259
| (_idx, {ptyp_desc=Ptyp_var var}) when List.mem var type_variables ->
242260
(* The type parameter is a variable. It is likely that the constructor does not refine the variable.
243261
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
248265
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:
251268
type 'a term = Var : string * 'v typ -> 'v term | ...
252269
So that poly_a is never called to print the type.
253270
254271
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.
256273
If one needs existential type variables while a type parameter is not refined, the programmer would keep using
257274
the same variable name as in the declaration, for example:
258275
type 'state transition = Print : 'v term * 'state -> 'state transition | ...
@@ -269,11 +286,11 @@ let refined_param_pos_of_type_decl type_decl =
269286
let str_of_type ~with_path ~path ({ ptype_loc = loc } as type_decl) =
270287
let quoter = Ppx_deriving.create_quoter () in
271288
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
273290
let prettyprinter =
274291
match type_decl.ptype_kind, type_decl.ptype_manifest with
275292
| 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]]
277294
| Ptype_variant constrs, _ ->
278295
let cases =
279296
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) =
304321
(app (wrap_printer quoter printer) ([%expr fmt] :: args))
305322
| None, Pcstr_tuple(typs) ->
306323
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
308325
let printer =
309326
match args with
310327
| [] -> [%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) =
326343
labels |> List.map (fun ({ pld_name = { txt = n }; _ } as pld) ->
327344
[%expr
328345
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]
330347
[%e evar (argl n)];
331348
Ppx_deriving_runtime.Format.fprintf fmt "@]"
332349
])
@@ -348,7 +365,7 @@ let str_of_type ~with_path ~path ({ ptype_loc = loc } as type_decl) =
348365
let field_name = if i = 0 then expand_path ~with_path ~path name else name in
349366
[%expr
350367
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]
352369
[%e Exp.field (evar "x") (mknoloc (Lident name))];
353370
Ppx_deriving_runtime.Format.fprintf fmt "@]"
354371
])
@@ -434,7 +451,7 @@ let derive_extension =
434451
Ast_pattern.(ptyp __) (fun ~ctxt ->
435452
let loc = Expansion_context.Extension.extension_point_loc ctxt in
436453
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]))
438455
let derive_transformation =
439456
Driver.register_transformation
440457
deriver

0 commit comments

Comments
 (0)