Skip to content

Commit e87113c

Browse files
author
Valentin Gatien-Baron
committed
detect invalid deep substitutions involving recursive modules
1 parent 8ec77c9 commit e87113c

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

testsuite/tests/typing-sigsubst/sigsubst.ml

+6-4
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,7 @@ module type S2 =
264264
|}]
265265

266266
(* In the presence of recursive modules, the use of a module can come before its
267-
definition (in the typed tree), making the typer accepts an invalid
268-
substitution. *)
267+
definition (in the typed tree). *)
269268

270269
module Id(X : sig type t end) = struct type t = X.t end
271270
module type S3 = sig
@@ -274,8 +273,11 @@ module type S3 = sig
274273
end with type M2.t := int
275274
[%%expect {|
276275
module Id : functor (X : sig type t end) -> sig type t = X.t end
277-
module type S3 =
278-
sig module rec M : sig type t = A of Id(M2).t end and M2 : sig end end
276+
Line _, characters 17-120:
277+
Error: This `with' constraint on M2.t makes the applicative functor
278+
type Id(M2).t ill-typed in the constrained signature:
279+
Modules do not match: sig end is not included in sig type t end
280+
The type `t' is required but not provided
279281
|}]
280282

281283

typing/typemod.ml

+23-6
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ let iterator_with_env env =
183183
let super = Btype.type_iterators in
184184
env, { super with
185185
Btype.it_signature = (fun self sg ->
186+
(* add all items to the env before recursing down, to handle recursive
187+
definitions *)
186188
let env_before = !env in
187189
List.iter (fun i -> env := Env.add_item i !env) sg;
188190
super.Btype.it_signature self sg;
@@ -220,21 +222,26 @@ let retype_applicative_functor_type ~loc env funct arg =
220222
- aliases: module A = M still makes sense but it doesn't mean the same thing
221223
anymore, so it's forbidden until it's clear what we should do with it.
222224
This function would be called with M.N.t and N.t to check for these uses. *)
223-
let check_usage_of_path_of_substituted_item path env signature ~loc ~lid =
225+
let check_usage_of_path_of_substituted_item paths env signature ~loc ~lid =
224226
let iterator =
225227
let env, super = iterator_with_env env in
226228
{ super with
227229
Btype.it_signature_item = (fun self -> function
228230
| Sig_module (id, { md_type = Mty_alias (_, aliased_path); _ }, _)
229-
when path_is_strict_prefix path ~prefix:aliased_path ->
231+
when List.exists
232+
(fun path -> path_is_strict_prefix path ~prefix:aliased_path)
233+
paths
234+
->
230235
let e = With_changes_module_alias (lid.txt, id, aliased_path) in
231236
raise(Error(loc, !env, e))
232237
| sig_item ->
233238
super.Btype.it_signature_item self sig_item
234239
);
235240
Btype.it_path = (fun referenced_path ->
236241
iter_path_apply referenced_path ~f:(fun funct arg ->
237-
if path_is_strict_prefix path ~prefix:arg
242+
if List.exists
243+
(fun path -> path_is_strict_prefix path ~prefix:arg)
244+
paths
238245
then
239246
let env = !env in
240247
try retype_applicative_functor_type ~loc env funct arg
@@ -378,9 +385,6 @@ let merge_constraint initial_env loc sg constr =
378385
let path = path_concat id path in
379386
real_ids := path :: !real_ids;
380387
let item = Sig_module(id, {md with md_type=Mty_signature newsg}, rs) in
381-
if destructive_substitution then
382-
check_usage_of_path_of_substituted_item
383-
path (Env.add_item item env) rem ~loc ~lid;
384388
(path, lid, tcstr),
385389
item :: rem
386390
| (item :: rem, _, _) ->
@@ -391,6 +395,19 @@ let merge_constraint initial_env loc sg constr =
391395
try
392396
let names = Longident.flatten lid.txt in
393397
let (tcstr, sg) = merge initial_env sg names None in
398+
if destructive_substitution then (
399+
match List.rev !real_ids with
400+
| [] -> assert false
401+
| last :: rest ->
402+
(* The last item is the one that's removed. We don't need to check how
403+
it's used since it's replaced by a more specific type/module. *)
404+
assert (match last with Pident _ -> true | _ -> false);
405+
match rest with
406+
| [] -> ()
407+
| _ :: _ ->
408+
check_usage_of_path_of_substituted_item
409+
rest initial_env sg ~loc ~lid;
410+
);
394411
let sg =
395412
match tcstr with
396413
| (_, _, Twith_typesubst tdecl) ->

0 commit comments

Comments
 (0)