Skip to content

Commit 5cb27d8

Browse files
authored
Merge pull request ocaml#792 from sliquister/generalize-destr-subst2
Fixing the limitations on destructive substitutions
2 parents 1501bc9 + e87113c commit 5cb27d8

29 files changed

+752
-204
lines changed

Changes

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ Working version
1212
in class expressions and class type expressions.
1313
(Alain Frisch, reviews by Thomas Refis and Jacques Garrigue)
1414

15+
- GPR#792: fix limitations of destructive substitutions, by
16+
allowing "S with type t := type-expr",
17+
"S with type M.t := type-expr", "S with module M.N := path"
18+
(Valentin Gatien-Baron, review by Jacques Garrigue and Leo White)
19+
1520
- GPR#1142: Mark assertions nonexpansive, so that 'assert false'
1621
can be used as a placeholder for a polymorphic function.
1722
(Stephen Dolan)

manual/manual/refman/exten.etex

+9-8
Original file line numberDiff line numberDiff line change
@@ -844,22 +844,23 @@ it to represent sets internally in a different way.
844844
\ikwd{type\@\texttt{type}}
845845
\label{s:signature-substitution}
846846

847-
(Introduced in OCaml 3.12)
847+
(Introduced in OCaml 3.12, generalized in 4.06)
848848

849849
\begin{syntax}
850850
mod-constraint:
851851
...
852852
| 'type' [type-params] typeconstr-name ':=' typexpr
853-
| 'module' module-name ':=' extended-module-path
853+
| 'module' module-path ':=' extended-module-path
854854
\end{syntax}
855855

856-
``Destructive'' substitution (@'with' ... ':=' ...@) behaves essentially like
856+
A ``destructive'' substitution (@'with' ... ':=' ...@) behaves essentially like
857857
normal signature constraints (@'with' ... '=' ...@), but it additionally removes
858-
the redefined type or module from the signature. There are a number of
859-
restrictions: one can only remove types and modules at the outermost
860-
level (not inside submodules), and in the case of @'with type'@ the
861-
definition must be another type constructor with the same type
862-
parameters.
858+
the redefined type or module from the signature.
859+
860+
Prior to OCaml 4.06, there were a number of restrictions: one could only remove
861+
types and modules at the outermost level (not inside submodules), and in the
862+
case of @'with type'@ the definition had to be another type constructor with the
863+
same type parameters.
863864

864865
A natural application of destructive substitution is merging two
865866
signatures sharing a type name.

ocamldoc/odoc_name.ml

+1-5
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,4 @@ let to_path n =
219219

220220
let from_longident = Odoc_misc.string_of_longident
221221

222-
module Set = Set.Make (struct
223-
type z = t
224-
type t = z
225-
let compare = String.compare
226-
end)
222+
module Map = Map.Make(String)

ocamldoc/odoc_name.mli

+1-2
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,4 @@ val to_path : t -> Path.t
7070
(** Get a name from a [Longident.t].*)
7171
val from_longident : Longident.t -> t
7272

73-
(** Set of Name.t *)
74-
module Set : Set.S with type elt = t
73+
module Map : Map.S with type key = t

ocamldoc/odoc_sig.ml

+61-11
Original file line numberDiff line numberDiff line change
@@ -422,17 +422,57 @@ module Analyser =
422422
let comments = Record.(doc typedtree) pos_end l in
423423
Odoc_type.Cstr_record (List.map (record comments) l)
424424

425+
(* Given a constraint "with type M.N.t := foo", this function adds "M" ->
426+
"with type N.t := foo" to acc, ie it build the constraint to put on the
427+
first element of the path being modified.
428+
When filter_out_erased_items_from_signature finds "M", it applies the
429+
constraint on its module type. *)
430+
let constraint_for_subitem =
431+
let split_longident p =
432+
match Longident.flatten p with
433+
| [] -> assert false
434+
| hd :: tl -> hd, Longident.unflatten tl
435+
in
436+
fun acc s rebuild_constraint ->
437+
match split_longident s.txt with
438+
| hd, None -> Name.Map.add hd `Removed acc
439+
| hd, Some p ->
440+
let constraint_ = rebuild_constraint { s with txt = p } in
441+
match Name.Map.find hd acc with
442+
| exception Not_found ->
443+
Name.Map.add hd (`Constrained [constraint_]) acc
444+
| `Constrained old ->
445+
Name.Map.add hd (`Constrained (constraint_ :: old)) acc
446+
| `Removed -> acc
447+
425448
let erased_names_of_constraints constraints acc =
426449
List.fold_right (fun constraint_ acc ->
427450
match constraint_ with
428451
| Parsetree.Pwith_type _ | Parsetree.Pwith_module _ -> acc
429-
| Parsetree.Pwith_typesubst {Parsetree.ptype_name=s}
430-
| Parsetree.Pwith_modsubst (s, _) ->
431-
Name.Set.add s.txt acc)
452+
| Parsetree.Pwith_typesubst (s, typedecl) ->
453+
constraint_for_subitem acc s (fun s -> Parsetree.Pwith_typesubst (s, typedecl))
454+
| Parsetree.Pwith_modsubst (s, modpath) ->
455+
constraint_for_subitem acc s (fun s -> Parsetree.Pwith_modsubst (s, modpath)))
432456
constraints acc
433457

458+
let is_erased ident map =
459+
match Name.Map.find ident map with
460+
| exception Not_found -> false
461+
| `Removed -> true
462+
| `Constrained _ -> false
463+
464+
let apply_constraint module_type constraints =
465+
match module_type.Parsetree.pmty_desc with
466+
| Parsetree.Pmty_alias _ -> module_type
467+
| _ ->
468+
{ Parsetree.
469+
pmty_desc = Parsetree.Pmty_with (module_type, List.rev constraints);
470+
pmty_loc = module_type.Parsetree.pmty_loc;
471+
pmty_attributes = []
472+
}
473+
434474
let filter_out_erased_items_from_signature erased signature =
435-
if Name.Set.is_empty erased then signature
475+
if Name.Map.is_empty erased then signature
436476
else List.fold_right (fun sig_item acc ->
437477
let take_item psig_desc = { sig_item with Parsetree.psig_desc } :: acc in
438478
match sig_item.Parsetree.psig_desc with
@@ -446,14 +486,24 @@ module Analyser =
446486
| Parsetree.Psig_class _
447487
| Parsetree.Psig_class_type _ as tp -> take_item tp
448488
| Parsetree.Psig_type (rf, types) ->
449-
(match List.filter (fun td -> not (Name.Set.mem td.Parsetree.ptype_name.txt erased)) types with
489+
(match List.filter (fun td -> not (is_erased td.Parsetree.ptype_name.txt erased)) types with
450490
| [] -> acc
451491
| types -> take_item (Parsetree.Psig_type (rf, types)))
452-
| Parsetree.Psig_module {Parsetree.pmd_name=name}
492+
| Parsetree.Psig_module ({Parsetree.pmd_name=name;
493+
pmd_type=module_type} as r) as m ->
494+
begin match Name.Map.find name.txt erased with
495+
| exception Not_found -> take_item m
496+
| `Removed -> acc
497+
| `Constrained constraints ->
498+
take_item
499+
(Parsetree.Psig_module
500+
{ r with Parsetree.pmd_type =
501+
apply_constraint module_type constraints })
502+
end
453503
| Parsetree.Psig_modtype {Parsetree.pmtd_name=name} as m ->
454-
if Name.Set.mem name.txt erased then acc else take_item m
504+
if is_erased name.txt erased then acc else take_item m
455505
| Parsetree.Psig_recmodule mods ->
456-
(match List.filter (fun pmd -> not (Name.Set.mem pmd.Parsetree.pmd_name.txt erased)) mods with
506+
(match List.filter (fun pmd -> not (is_erased pmd.Parsetree.pmd_name.txt erased)) mods with
457507
| [] -> acc
458508
| mods -> take_item (Parsetree.Psig_recmodule mods)))
459509
signature []
@@ -1336,7 +1386,7 @@ module Analyser =
13361386

13371387
(** Return a module_type_kind from a Parsetree.module_type and a Types.module_type *)
13381388
and analyse_module_type_kind
1339-
?(erased = Name.Set.empty) env current_module_name module_type sig_module_type =
1389+
?(erased = Name.Map.empty) env current_module_name module_type sig_module_type =
13401390
match module_type.Parsetree.pmty_desc with
13411391
Parsetree.Pmty_ident longident ->
13421392
let name =
@@ -1432,7 +1482,7 @@ module Analyser =
14321482

14331483
(** analyse of a Parsetree.module_type and a Types.module_type.*)
14341484
and analyse_module_kind
1435-
?(erased = Name.Set.empty) env current_module_name module_type sig_module_type =
1485+
?(erased = Name.Map.empty) env current_module_name module_type sig_module_type =
14361486
match module_type.Parsetree.pmty_desc with
14371487
| Parsetree.Pmty_ident _longident ->
14381488
let k = analyse_module_type_kind env current_module_name module_type sig_module_type in
@@ -1502,7 +1552,7 @@ module Analyser =
15021552
raise (Failure "Parsetree.Pmty_functor _ but not Types.Mty_functor _")
15031553
)
15041554
| Parsetree.Pmty_with (module_type2, constraints) ->
1505-
(*of module_type * (Longident.t * with_constraint) list*)
1555+
(* of module_type * (Longident.t * with_constraint) list*)
15061556
(
15071557
let loc_start = Loc.end_ module_type2.Parsetree.pmty_loc in
15081558
let loc_end = Loc.end_ module_type.Parsetree.pmty_loc in

ocamldoc/odoc_sig.mli

+3-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,9 @@ module Analyser :
180180

181181
(** Return a module_type_kind from a Parsetree.module_type and a Types.module_type *)
182182
val analyse_module_type_kind :
183-
?erased:Odoc_name.Set.t -> Odoc_env.env -> Odoc_name.t ->
183+
?erased:[ `Constrained of Parsetree.with_constraint list
184+
| `Removed ] Odoc_name.Map.t
185+
-> Odoc_env.env -> Odoc_name.t ->
184186
Parsetree.module_type -> Types.module_type ->
185187
Odoc_module.module_type_kind
186188

parsing/ast_iterator.ml

+2-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ module MT = struct
232232
iter_loc sub lid; sub.type_declaration sub d
233233
| Pwith_module (lid, lid2) ->
234234
iter_loc sub lid; iter_loc sub lid2
235-
| Pwith_typesubst d -> sub.type_declaration sub d
235+
| Pwith_typesubst (lid, d) ->
236+
iter_loc sub lid; sub.type_declaration sub d
236237
| Pwith_modsubst (s, lid) ->
237238
iter_loc sub s; iter_loc sub lid
238239

parsing/ast_mapper.ml

+2-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ module MT = struct
246246
Pwith_type (map_loc sub lid, sub.type_declaration sub d)
247247
| Pwith_module (lid, lid2) ->
248248
Pwith_module (map_loc sub lid, map_loc sub lid2)
249-
| Pwith_typesubst d -> Pwith_typesubst (sub.type_declaration sub d)
249+
| Pwith_typesubst (lid, d) ->
250+
Pwith_typesubst (map_loc sub lid, sub.type_declaration sub d)
250251
| Pwith_modsubst (s, lid) ->
251252
Pwith_modsubst (map_loc sub s, map_loc sub lid)
252253

parsing/depend.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ and add_modtype bv mty =
307307
(function
308308
| Pwith_type (_, td) -> add_type_declaration bv td
309309
| Pwith_module (_, lid) -> addmodule bv lid
310-
| Pwith_typesubst td -> add_type_declaration bv td
310+
| Pwith_typesubst (_, td) -> add_type_declaration bv td
311311
| Pwith_modsubst (_, lid) -> addmodule bv lid
312312
)
313313
cstrl

parsing/longident.ml

+9-4
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ let rec split_at_dots s pos =
3737
with Not_found ->
3838
[String.sub s pos (String.length s - pos)]
3939

40+
let unflatten l =
41+
match l with
42+
| [] -> None
43+
| hd :: tl -> Some (List.fold_left (fun p s -> Ldot(p, s)) (Lident hd) tl)
44+
4045
let parse s =
41-
match split_at_dots s 0 with
42-
[] -> Lident "" (* should not happen, but don't put assert false
43-
so as not to crash the toplevel (see Genprintval) *)
44-
| hd :: tl -> List.fold_left (fun p s -> Ldot(p, s)) (Lident hd) tl
46+
match unflatten (split_at_dots s 0) with
47+
| None -> Lident "" (* should not happen, but don't put assert false
48+
so as not to crash the toplevel (see Genprintval) *)
49+
| Some v -> v

parsing/longident.mli

+1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ type t =
2121
| Lapply of t * t
2222

2323
val flatten: t -> string list
24+
val unflatten: string list -> t option
2425
val last: t -> string
2526
val parse: string -> t

parsing/parser.mly

+5-4
Original file line numberDiff line numberDiff line change
@@ -2135,15 +2135,16 @@ with_constraint:
21352135
~loc:(symbol_rloc()))) }
21362136
/* used label_longident instead of type_longident to disallow
21372137
functor applications in type path */
2138-
| TYPE type_parameters label COLONEQUAL core_type_no_attr
2138+
| TYPE type_parameters label_longident COLONEQUAL core_type_no_attr
21392139
{ Pwith_typesubst
2140-
(Type.mk (mkrhs $3 3)
2140+
(mkrhs $3 3,
2141+
(Type.mk (mkrhs (Longident.last $3) 3)
21412142
~params:$2
21422143
~manifest:$5
2143-
~loc:(symbol_rloc())) }
2144+
~loc:(symbol_rloc()))) }
21442145
| MODULE mod_longident EQUAL mod_ext_longident
21452146
{ Pwith_module (mkrhs $2 2, mkrhs $4 4) }
2146-
| MODULE UIDENT COLONEQUAL mod_ext_longident
2147+
| MODULE mod_longident COLONEQUAL mod_ext_longident
21472148
{ Pwith_modsubst (mkrhs $2 2, mkrhs $4 4) }
21482149
;
21492150
with_type_binder:

parsing/parsetree.mli

+4-4
Original file line numberDiff line numberDiff line change
@@ -767,10 +767,10 @@ and with_constraint =
767767
the name of the type_declaration. *)
768768
| Pwith_module of Longident.t loc * Longident.t loc
769769
(* with module X.Y = Z *)
770-
| Pwith_typesubst of type_declaration
771-
(* with type t := ... *)
772-
| Pwith_modsubst of string loc * Longident.t loc
773-
(* with module X := Z *)
770+
| Pwith_typesubst of Longident.t loc * type_declaration
771+
(* with type X.t := ..., same format as [Pwith_type] *)
772+
| Pwith_modsubst of Longident.t loc * Longident.t loc
773+
(* with module X.Y := Z *)
774774

775775
(* Value expressions for the module language *)
776776

parsing/pprintast.ml

+5-5
Original file line numberDiff line numberDiff line change
@@ -952,14 +952,14 @@ and module_type ctxt f x =
952952
ls longident_loc li (type_declaration ctxt) td
953953
| Pwith_module (li, li2) ->
954954
pp f "module %a =@ %a" longident_loc li longident_loc li2;
955-
| Pwith_typesubst ({ptype_params=ls;_} as td) ->
955+
| Pwith_typesubst (li, ({ptype_params=ls;_} as td)) ->
956956
let ls = List.map fst ls in
957-
pp f "type@ %a %s :=@ %a"
957+
pp f "type@ %a %a :=@ %a"
958958
(list (core_type ctxt) ~sep:"," ~first:"(" ~last:")")
959-
ls td.ptype_name.txt
959+
ls longident_loc li
960960
(type_declaration ctxt) td
961-
| Pwith_modsubst (s, li2) ->
962-
pp f "module %s :=@ %a" s.txt longident_loc li2 in
961+
| Pwith_modsubst (li, li2) ->
962+
pp f "module %a :=@ %a" longident_loc li longident_loc li2 in
963963
(match l with
964964
| [] -> pp f "@[<hov2>%a@]" (module_type ctxt) mt
965965
| _ -> pp f "@[<hov2>(%a@ with@ %a)@]"

parsing/printast.ml

+5-5
Original file line numberDiff line numberDiff line change
@@ -722,17 +722,17 @@ and with_constraint i ppf x =
722722
| Pwith_type (lid, td) ->
723723
line i ppf "Pwith_type %a\n" fmt_longident_loc lid;
724724
type_declaration (i+1) ppf td;
725-
| Pwith_typesubst (td) ->
726-
line i ppf "Pwith_typesubst\n";
725+
| Pwith_typesubst (lid, td) ->
726+
line i ppf "Pwith_typesubst %a\n" fmt_longident_loc lid;
727727
type_declaration (i+1) ppf td;
728728
| Pwith_module (lid1, lid2) ->
729729
line i ppf "Pwith_module %a = %a\n"
730730
fmt_longident_loc lid1
731731
fmt_longident_loc lid2;
732-
| Pwith_modsubst (s, li) ->
732+
| Pwith_modsubst (lid1, lid2) ->
733733
line i ppf "Pwith_modsubst %a = %a\n"
734-
fmt_string_loc s
735-
fmt_longident_loc li;
734+
fmt_longident_loc lid1
735+
fmt_longident_loc lid2;
736736

737737
and module_expr i ppf x =
738738
line i ppf "module_expr %a\n" fmt_location x.pmod_loc;

testsuite/tests/parsing/attributes.ml.reference

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@
125125
[]
126126
Pmod_ident "M" (attributes.ml[26,254+27]..[26,254+28])
127127
[
128-
Pwith_typesubst
128+
Pwith_typesubst "t" (attributes.ml[26,254+53]..[26,254+54])
129129
type_declaration "t" (attributes.ml[26,254+53]..[26,254+54]) (attributes.ml[26,254+48]..[26,254+61])
130130
ptype_params =
131131
[]

testsuite/tests/typing-sigsubst/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
#**************************************************************************
1515

1616
BASEDIR=../..
17-
include $(BASEDIR)/makefiles/Makefile.toplevel
17+
include $(BASEDIR)/makefiles/Makefile.expect
1818
include $(BASEDIR)/makefiles/Makefile.common

0 commit comments

Comments
 (0)