Skip to content

Commit 4488fde

Browse files
committed
Integrate changes from upstream review.
1 parent eaa9412 commit 4488fde

File tree

2 files changed

+146
-93
lines changed

2 files changed

+146
-93
lines changed

ocaml/testsuite/tests/typing-modules/package_constraint.ml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,88 @@ Error: This type string should be an instance of type ('a : immediate)
245245
But the layout of string must be a sublayout of immediate, because
246246
of the definition of t at line 5, characters 0-39.
247247
|}];;
248+
249+
(* Checking such a constraint may require expanding definitions from the module
250+
being updated. *)
251+
module type S = sig
252+
module type S1 = sig
253+
type t
254+
end
255+
module M : S1
256+
end
257+
258+
type t = (module S with type M.t = int)
259+
[%%expect{|
260+
module type S = sig module type S1 = sig type t end module M : S1 end
261+
type t = (module S with type M.t = int)
262+
|}];;
263+
264+
(* Ghosts haunted type definitions *)
265+
module type Private_row = sig
266+
type a
267+
and t = private [< `A | `B ]
268+
and b
269+
and d = private [< `C ]
270+
end
271+
272+
(* This is fine, the ghost type `t#row` is removed silently *)
273+
module type Test = Private_row with type t = [ `A ]
274+
275+
(* This fails currently. If we ever allow it, make sure the ghost type is
276+
removed as above. *)
277+
type fail = (module Private_row with type t = [ `A ] )
278+
279+
[%%expect{|
280+
module type Private_row =
281+
sig type a and t = private [< `A | `B ] and b and d = private [< `C ] end
282+
module type Test =
283+
sig type a and t = [ `A ] and b and d = private [< `C ] end
284+
Line 13, characters 12-54:
285+
13 | type fail = (module Private_row with type t = [ `A ] )
286+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
287+
Error: In the constrained signature, type t is defined to be [< `A | `B ].
288+
Package `with' constraints may only be used on abstract types.
289+
|}]
290+
291+
(* More row type examples to consider, if we ever start allowing package type
292+
constraints to replace compatible manifests. *)
293+
module type Private_row = sig
294+
type t = private [< `A ]
295+
end
296+
297+
type t1 = (module Private_row with type t = [ `A ])
298+
[%%expect{|
299+
module type Private_row = sig type t = private [< `A ] end
300+
Line 5, characters 10-51:
301+
5 | type t1 = (module Private_row with type t = [ `A ])
302+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
303+
Error: In the constrained signature, type t is defined to be [< `A ].
304+
Package `with' constraints may only be used on abstract types.
305+
|}]
306+
307+
type t2 = (module Private_row with type t = [< `A ])
308+
[%%expect{|
309+
Line 1, characters 10-52:
310+
1 | type t2 = (module Private_row with type t = [< `A ])
311+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
312+
Error: In the constrained signature, type t is defined to be [< `A ].
313+
Package `with' constraints may only be used on abstract types.
314+
|}]
315+
316+
type 'a t3 = (module Private_row with type t = [< `A ]) as 'a
317+
[%%expect{|
318+
Line 1, characters 13-55:
319+
1 | type 'a t3 = (module Private_row with type t = [< `A ]) as 'a
320+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
321+
Error: In the constrained signature, type t is defined to be [< `A ].
322+
Package `with' constraints may only be used on abstract types.
323+
|}]
324+
325+
type 'a t4 = (module Private_row with type t = [< `A ] as 'a)
326+
[%%expect{|
327+
Line 1, characters 13-61:
328+
1 | type 'a t4 = (module Private_row with type t = [< `A ] as 'a)
329+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
330+
Error: In the constrained signature, type t is defined to be [< `A ].
331+
Package `with' constraints may only be used on abstract types.
332+
|}]

ocaml/typing/typemod.ml

Lines changed: 61 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -552,11 +552,15 @@ type with_info =
552552
| With_modsubst of Longident.t loc * Path.t * Types.module_declaration
553553
| With_modtype of Typedtree.module_type
554554
| With_modtypesubst of Typedtree.module_type
555+
| With_type_package of Typedtree.core_type
556+
(* Package with type constraints only use this last case. Normal module
557+
with constraints never use it. *)
555558

556559
let merge_constraint initial_env loc sg lid constr =
557560
let destructive_substitution =
558561
match constr with
559-
| With_type _ | With_module _ | With_modtype _ -> false
562+
| With_type _ | With_type_package _ | With_module _
563+
| With_modtype _ -> false
560564
| With_typesubst _ | With_modsubst _ | With_modtypesubst _ -> true
561565
in
562566
let real_ids = ref [] in
@@ -634,7 +638,7 @@ let merge_constraint initial_env loc sg lid constr =
634638
in
635639
return ~ghosts
636640
~replace_by:(Some (Sig_type(id, newdecl, rs, priv)))
637-
(Pident id, lid, Twith_type tdecl)
641+
(Pident id, lid, Some (Twith_type tdecl))
638642
| Sig_type(id, sig_decl, rs, priv) , [s],
639643
(With_type sdecl | With_typesubst sdecl as constr)
640644
when Ident.name id = s ->
@@ -651,12 +655,47 @@ let merge_constraint initial_env loc sg lid constr =
651655
With_type _ ->
652656
return ~ghosts
653657
~replace_by:(Some(Sig_type(id, newdecl, rs, priv)))
654-
(Pident id, lid, Twith_type tdecl)
658+
(Pident id, lid, Some (Twith_type tdecl))
655659
| (* With_typesubst *) _ ->
656660
real_ids := [Pident id];
657661
return ~ghosts ~replace_by:None
658-
(Pident id, lid, Twith_typesubst tdecl)
662+
(Pident id, lid, Some (Twith_typesubst tdecl))
659663
end
664+
| Sig_type(id, sig_decl, rs, priv), [s], With_type_package cty
665+
when Ident.name id = s ->
666+
begin match sig_decl.type_manifest with
667+
| None -> ()
668+
| Some ty ->
669+
raise (Error(loc, outer_sig_env, With_package_manifest (lid.txt, ty)))
670+
end;
671+
let tdecl =
672+
Typedecl.transl_package_constraint ~loc cty.ctyp_type
673+
in
674+
(* Here we constrain the jkind of "with type" manifest by the jkind from
675+
the declaration from the original signature. Note that this is also
676+
checked in [check_type_decl], but there it is check, not constrain,
677+
which we need here to deal with type variables in package constraints
678+
(see tests in [typing-modules/package_constraint.ml]). *)
679+
begin match
680+
Ctype.constrain_decl_jkind initial_env tdecl sig_decl.type_jkind
681+
with
682+
| Ok _-> ()
683+
| Error v ->
684+
(* This is morally part of the below [check_type_decl], so we give the
685+
same error that would be given there for good error messages. *)
686+
let err =
687+
Includemod.Error.In_Type_declaration(
688+
id, Type_declarations
689+
{got=tdecl;
690+
expected=sig_decl;
691+
symptom=Includecore.Jkind v})
692+
in
693+
raise Includemod.(Error(initial_env, err))
694+
end;
695+
check_type_decl outer_sig_env sg_for_env loc id None tdecl sig_decl;
696+
let tdecl = { tdecl with type_manifest = None } in
697+
return ~ghosts ~replace_by:(Some(Sig_type(id, tdecl, rs, priv)))
698+
(Pident id, lid, None)
660699
| Sig_modtype(id, mtd, priv), [s],
661700
(With_modtype mty | With_modtypesubst mty)
662701
when Ident.name id = s ->
@@ -678,15 +717,16 @@ let merge_constraint initial_env loc sg lid constr =
678717
in
679718
return
680719
~replace_by:(Some(Sig_modtype(id, mtd', priv)))
681-
(Pident id, lid, Twith_modtype mty)
720+
(Pident id, lid, Some (Twith_modtype mty))
682721
else begin
683722
let path = Pident id in
684723
real_ids := [path];
685724
begin match mty.mty_type with
686725
| Mty_ident _ -> ()
687726
| mty -> unpackable_modtype := Some mty
688727
end;
689-
return ~replace_by:None (Pident id, lid, Twith_modtypesubst mty)
728+
return ~replace_by:None
729+
(Pident id, lid, Some (Twith_modtypesubst mty))
690730
end
691731
| Sig_module(id, pres, md, rs, priv), [s],
692732
With_module {lid=lid'; md=md'; path; remove_aliases}
@@ -700,7 +740,7 @@ let merge_constraint initial_env loc sg lid constr =
700740
newmd.md_type md.md_type);
701741
return
702742
~replace_by:(Some(Sig_module(id, pres, newmd, rs, priv)))
703-
(Pident id, lid, Twith_module (path, lid'))
743+
(Pident id, lid, Some (Twith_module (path, lid')))
704744
| Sig_module(id, _, md, _rs, _), [s], With_modsubst (lid',path,md')
705745
when Ident.name id = s ->
706746
let sig_env = Env.add_signature sg_for_env outer_sig_env in
@@ -709,7 +749,8 @@ let merge_constraint initial_env loc sg lid constr =
709749
(Includemod.strengthened_module_decl ~loc ~mark:Mark_both
710750
~aliasable sig_env md' path md);
711751
real_ids := [Pident id];
712-
return ~replace_by:None (Pident id, lid, Twith_modsubst (path, lid'))
752+
return ~replace_by:None
753+
(Pident id, lid, Some (Twith_modsubst (path, lid')))
713754
| Sig_module(id, _, md, rs, priv) as item, s :: namelist, constr
714755
when Ident.name id = s ->
715756
let sig_env = Env.add_signature sg_for_env outer_sig_env in
@@ -743,7 +784,7 @@ let merge_constraint initial_env loc sg lid constr =
743784
check_usage_after_substitution ~loc ~lid initial_env !real_ids
744785
!unpackable_modtype sg;
745786
let sub = match tcstr with
746-
| (_, _, Twith_typesubst tdecl) ->
787+
| (_, _, Some (Twith_typesubst tdecl)) ->
747788
let how_to_extend_subst =
748789
let sdecl =
749790
match constr with
@@ -768,7 +809,7 @@ let merge_constraint initial_env loc sg lid constr =
768809
let sub = Subst.change_locs Subst.identity loc in
769810
let sub = List.fold_left how_to_extend_subst sub !real_ids in
770811
Some sub
771-
| (_, _, Twith_modsubst (real_path, _)) ->
812+
| (_, _, Some (Twith_modsubst (real_path, _))) ->
772813
let sub = Subst.change_locs Subst.identity loc in
773814
let sub =
774815
List.fold_left
@@ -777,7 +818,7 @@ let merge_constraint initial_env loc sg lid constr =
777818
!real_ids
778819
in
779820
Some sub
780-
| (_, _, Twith_modtypesubst tmty) ->
821+
| (_, _, Some (Twith_modtypesubst tmty)) ->
781822
let add s p = Subst.add_modtype_path p tmty.mty_type s in
782823
let sub = Subst.change_locs Subst.identity loc in
783824
let sub = List.fold_left add sub !real_ids in
@@ -805,90 +846,15 @@ let merge_constraint initial_env loc sg lid constr =
805846
with Includemod.Error explanation ->
806847
raise(Error(loc, initial_env, With_mismatch(lid.txt, explanation)))
807848

808-
(* A simplified version of [merge_constraint] for the case of packages. Package
809-
constraints are much simpler - they must be "with type" constraints for types
810-
with no parameters and can only update abstract types. *)
811849
let merge_package_constraint initial_env loc sg lid cty =
812-
let rec patch_item namelist outer_sig_env sg_for_env ~ghosts item =
813-
let return replace_by =
814-
Some ((), {Signature_group.ghosts; replace_by})
815-
in
816-
match item, namelist with
817-
| Sig_type(id, sig_decl, rs, priv) , [s]
818-
when Ident.name id = s ->
819-
begin match sig_decl.type_manifest with
820-
| None -> ()
821-
| Some ty ->
822-
raise (Error(loc, outer_sig_env, With_package_manifest (lid.txt, ty)))
823-
end;
824-
let new_sig_decl =
825-
Typedecl.transl_package_constraint ~loc cty.ctyp_type
826-
in
827-
(* Here we constrain the jkind of "with type" manifest by the jkind from
828-
the declaration from the original signature. Note that this is also
829-
checked in [check_type_decl], but there it is check, not constrain,
830-
which we need here to deal with type variables in package constraints
831-
(see tests in [typing-modules/package_constraint.ml]). *)
832-
begin match
833-
Ctype.constrain_decl_jkind initial_env new_sig_decl
834-
sig_decl.type_jkind
835-
with
836-
| Ok _-> ()
837-
| Error v ->
838-
(* This is morally part of the below [check_type_decl], so we give the
839-
same error that would be given there for good error messages. *)
840-
let err =
841-
Includemod.Error.In_Type_declaration(id,
842-
Type_declarations
843-
{got=new_sig_decl;
844-
expected=sig_decl;
845-
symptom=Includecore.Jkind v})
846-
in
847-
raise Includemod.(Error(initial_env, err))
848-
end;
849-
check_type_decl outer_sig_env sg_for_env loc id None
850-
new_sig_decl sig_decl;
851-
let new_sig_decl = { new_sig_decl with type_manifest = None } in
852-
return (Some(Sig_type(id, new_sig_decl, rs, priv)))
853-
| Sig_module(id, _, md, rs, priv) as item, s :: namelist
854-
when Ident.name id = s ->
855-
let sig_env = Env.add_signature sg_for_env outer_sig_env in
856-
let sg = extract_sig sig_env loc md.md_type in
857-
let ((), newsg) = merge_signature sig_env sg namelist in
858-
let item =
859-
match md.md_type with
860-
Mty_alias _ ->
861-
(* A module alias cannot be refined, so keep it
862-
and just check that the constraint is correct *)
863-
item
864-
| _ ->
865-
let newmd = {md with md_type = Mty_signature newsg} in
866-
Sig_module(id, Mp_present, newmd, rs, priv)
867-
in
868-
return (Some item)
869-
| _ -> None
870-
and merge_signature env sg namelist =
871-
match
872-
Signature_group.replace_in_place (patch_item namelist env sg) sg
873-
with
874-
| Some (x,sg) -> x, sg
875-
| None -> raise(Error(loc, env, With_no_component lid.txt))
876-
in
877-
try
878-
let names = Longident.flatten lid.txt in
879-
let (tcstr, sg) = merge_signature initial_env sg names in
880-
check_well_formed_module initial_env loc "this instantiated signature"
881-
(Mty_signature sg);
882-
(tcstr, sg)
883-
with Includemod.Error explanation ->
884-
raise(Error(loc, initial_env, With_mismatch(lid.txt, explanation)))
850+
let _, s = merge_constraint initial_env loc sg lid (With_type_package cty) in
851+
s
885852

886853
let check_package_with_type_constraints loc env mty constraints =
887854
let sg = extract_sig env loc mty in
888855
let sg =
889856
List.fold_left
890-
(fun sg (lid, cty) ->
891-
snd (merge_package_constraint env loc sg lid cty))
857+
(fun sg (lid, cty) -> merge_package_constraint env loc sg lid cty)
892858
sg constraints
893859
in
894860
let scope = Ctype.create_scope () in
@@ -1602,8 +1568,10 @@ and transl_with ~loc env remove_aliases (rev_tcstrs,sg) constr =
16021568
let mty = transl_modtype env smty in
16031569
l, With_modtypesubst mty
16041570
in
1605-
let (tcstr, sg) = merge_constraint env loc sg lid with_info in
1606-
(tcstr :: rev_tcstrs, sg)
1571+
let ((path, lid, tcstr), sg) = merge_constraint env loc sg lid with_info in
1572+
(* Only package with constraints result in None here. *)
1573+
let tcstr = Option.get tcstr in
1574+
((path, lid, tcstr) :: rev_tcstrs, sg)
16071575

16081576

16091577

@@ -3782,8 +3750,8 @@ let report_error ~loc _env = function
37823750
(Path.name p) Printtyp.modtype mty
37833751
| With_package_manifest (lid, ty) ->
37843752
Location.errorf ~loc
3785-
"@[In the constrained signature, type %a is defined to be %a.@ \
3786-
Package `with' constraints may only be used on abstract types.@]"
3753+
"In the constrained signature, type %a is defined to be %a.@ \
3754+
Package `with' constraints may only be used on abstract types."
37873755
longident lid
37883756
Printtyp.type_expr ty
37893757
| Repeated_name(kind, name) ->

0 commit comments

Comments
 (0)