Skip to content

Commit 1e5c2ea

Browse files
committed
Add -as-argument-for parameter (#2177)
Add the ability to compile a module declaring that it is suitable to pass as the argument to a module taking a given parameter. Essentially the module is now checked against two different signatures (its own .mli and the parameter, which of course must be a supertype).
1 parent 70ec392 commit 1e5c2ea

29 files changed

+469
-72
lines changed

ocaml/driver/compile_common.ml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,7 @@ let typecheck_intf info ast =
6464
let tsg =
6565
ast
6666
|> Typemod.type_interface
67-
~sourcefile:info.source_file
68-
info.module_name
69-
info.env
67+
~sourcefile:info.source_file info.module_name info.env
7068
|> print_if info.ppf_dump Clflags.dump_typedtree Printtyped.interface
7169
in
7270
let sg = tsg.Typedtree.sig_type in
@@ -87,8 +85,14 @@ let emit_signature info ast tsg =
8785
let kind : Cmi_format.kind =
8886
if !Clflags.as_parameter then
8987
Parameter
90-
else
91-
Normal { cmi_impl = info.module_name }
88+
else begin
89+
let cmi_arg_for =
90+
match !Clflags.as_argument_for with
91+
| Some arg_type -> Some (Compilation_unit.Name.of_string arg_type)
92+
| None -> None
93+
in
94+
Normal { cmi_impl = info.module_name; cmi_arg_for }
95+
end
9296
in
9397
let alerts = Builtin_attributes.alerts_of_sig ast in
9498
Env.save_signature ~alerts tsg.Typedtree.sig_type

ocaml/driver/main_args.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,11 @@ let mk_as_parameter f =
659659
" Compiles the interface as a parameter for an open module."
660660
;;
661661

662+
let mk_as_argument_for f =
663+
"-as-argument-for", Arg.String f,
664+
"<module name> Compiles the module as an argument for the named parameter."
665+
;;
666+
662667
let mk_use_prims f =
663668
"-use-prims", Arg.String f, "<file> (undocumented)"
664669

@@ -965,6 +970,7 @@ end
965970
module type Compiler_options = sig
966971
val _a : unit -> unit
967972
val _annot : unit -> unit
973+
val _as_argument_for : string -> unit
968974
val _as_parameter : unit -> unit
969975
val _binannot : unit -> unit
970976
val _binannot_cms : unit -> unit
@@ -1165,6 +1171,7 @@ struct
11651171
mk_absname F._absname;
11661172
mk_no_absname F._no_absname;
11671173
mk_annot F._annot;
1174+
mk_as_argument_for F._as_argument_for;
11681175
mk_as_parameter F._as_parameter;
11691176
mk_binannot F._binannot;
11701177
mk_binannot_cms F._binannot_cms;
@@ -1383,6 +1390,7 @@ struct
13831390
mk_afl_instrument F._afl_instrument;
13841391
mk_afl_inst_ratio F._afl_inst_ratio;
13851392
mk_annot F._annot;
1393+
mk_as_argument_for F._as_argument_for;
13861394
mk_as_parameter F._as_parameter;
13871395
mk_binannot F._binannot;
13881396
mk_binannot_cms F._binannot_cms;
@@ -1970,6 +1978,7 @@ module Default = struct
19701978
let _annot = set annotations
19711979
let _args = Arg.read_arg
19721980
let _args0 = Arg.read_arg0
1981+
let _as_argument_for s = as_argument_for := Some s
19731982
let _as_parameter = set as_parameter
19741983
let _binannot = set binary_annotations
19751984
let _binannot_cms = set binary_annotations_cms

ocaml/driver/main_args.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ end
8888
module type Compiler_options = sig
8989
val _a : unit -> unit
9090
val _annot : unit -> unit
91+
val _as_argument_for : string -> unit
9192
val _as_parameter : unit -> unit
9293
val _binannot : unit -> unit
9394
val _binannot_cms : unit -> unit

ocaml/file_formats/cmi_format.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type pers_flags =
2323
type kind =
2424
| Normal of {
2525
cmi_impl : Compilation_unit.t;
26+
cmi_arg_for : Compilation_unit.Name.t option;
2627
}
2728
| Parameter
2829

ocaml/file_formats/cmi_format.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type pers_flags =
2323
type kind =
2424
| Normal of {
2525
cmi_impl : Compilation_unit.t;
26+
cmi_arg_for : Compilation_unit.Name.t option;
2627
}
2728
| Parameter
2829

ocaml/ocamldoc/odoc_analyse.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ let process_interface_file sourcefile =
122122
Pparse.file ~tool_name inputfile
123123
(no_docstring Parse.interface) Pparse.Signature
124124
in
125-
let sg = Typemod.type_interface ~sourcefile compilation_unit (initial_env()) ast in
125+
let sg =
126+
Typemod.type_interface ~sourcefile compilation_unit (initial_env()) ast
127+
in
126128
Warnings.check_fatal ();
127129
(ast, sg, inputfile)
128130

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type t = unit
2+
3+
let empty = ()
4+
let append () () = `Banana
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
File "bad_arg_impl.ml", line 1:
2+
Error: The argument module bad_arg_impl.ml
3+
does not match the parameter signature monoid.cmi:
4+
Values do not match:
5+
val append : unit -> unit -> [> `Banana ]
6+
is not included in
7+
val append : t -> t -> t
8+
The type unit -> unit -> [> `Banana ] is not compatible with the type
9+
t -> t -> t
10+
Type [> `Banana ] is not compatible with type t = unit
11+
File "monoid.mli", line 4, characters 0-24: Expected declaration
12+
File "bad_arg_impl.ml", line 4, characters 4-10: Actual declaration
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type t
2+
3+
val empty : t
4+
val append : t -> t -> [ `Banana ]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
File "bad_arg_intf.mli", line 1:
2+
Error: The argument module bad_arg_intf.mli
3+
does not match the parameter signature monoid.cmi:
4+
Values do not match:
5+
val append : t -> t -> [ `Banana ]
6+
is not included in
7+
val append : t -> t -> t
8+
The type t -> t -> [ `Banana ] is not compatible with the type
9+
t -> t -> t
10+
Type [ `Banana ] is not compatible with type t
11+
File "monoid.mli", line 4, characters 0-24: Expected declaration
12+
File "bad_arg_intf.mli", line 4, characters 0-34: Actual declaration
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type t = string
2+
3+
let empty = ""
4+
let append = (^)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
type t = string
2+
3+
val empty : t
4+
val append : t -> t -> t
Lines changed: 134 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,136 @@
11
(* TEST
2-
readonly_files = "bad_ref_direct.ml bad_ref_direct.reference monoid.mli ";
3-
setup-ocamlc.byte-build-env;
4-
flags = "-as-parameter";
5-
module = "monoid.mli";
6-
ocamlc.byte;
7-
module = "bad_ref_direct.ml";
8-
compiler_output = "bad_ref_direct.output";
9-
ocamlc_byte_exit_status = "2";
10-
ocamlc.byte;
11-
compiler_reference = "bad_ref_direct.reference";
12-
check-ocamlc.byte-output;
2+
readonly_files = "\
3+
bad_arg_impl.ml bad_arg_impl.reference \
4+
bad_arg_intf.mli bad_arg_intf.reference \
5+
bad_ref_direct.ml bad_ref_direct.reference \
6+
monoid.mli \
7+
string_monoid.ml string_monoid.mli \
8+
test_direct_access.ml test_direct_access.reference \
9+
";
10+
11+
{
12+
setup-ocamlc.byte-build-env;
13+
14+
flags = "-as-parameter";
15+
module = "monoid.mli";
16+
ocamlc.byte;
17+
{
18+
flags = "";
19+
module = "bad_ref_direct.ml";
20+
compiler_output = "bad_ref_direct.output";
21+
ocamlc_byte_exit_status = "2";
22+
ocamlc.byte;
23+
24+
compiler_reference = "bad_ref_direct.reference";
25+
check-ocamlc.byte-output;
26+
}{
27+
flags = "-as-argument-for Monoid";
28+
module = "bad_arg_impl.ml";
29+
compiler_output = "bad_arg_impl.output";
30+
ocamlc_byte_exit_status = "2";
31+
ocamlc.byte;
32+
33+
compiler_reference = "bad_arg_impl.reference";
34+
check-ocamlc.byte-output;
35+
}{
36+
flags = "-as-argument-for Monoid";
37+
module = "bad_arg_intf.mli";
38+
compiler_output = "bad_arg_intf.output";
39+
ocamlc_byte_exit_status = "2";
40+
ocamlc.byte;
41+
42+
compiler_reference = "bad_arg_intf.reference";
43+
check-ocamlc.byte-output;
44+
}{
45+
src = "string_monoid.ml";
46+
dst = "string_monoid_no_mli.ml";
47+
copy;
48+
49+
flags = "-as-argument-for Monoid";
50+
module = "string_monoid_no_mli.ml string_monoid.mli string_monoid.ml";
51+
ocamlc.byte;
52+
53+
flags = "";
54+
module = "test_direct_access.ml";
55+
ocamlc.byte;
56+
57+
flags = "";
58+
program = "${test_build_directory}/test_direct_access.bc";
59+
module = "";
60+
all_modules = "\
61+
string_monoid.cmo \
62+
string_monoid_no_mli.cmo \
63+
test_direct_access.cmo \
64+
";
65+
ocamlc.byte;
66+
67+
output = "test_direct_access.output";
68+
run;
69+
70+
reference = "test_direct_access.reference";
71+
check-program-output;
72+
}
73+
}{
74+
setup-ocamlopt.byte-build-env;
75+
76+
flags = "-as-parameter";
77+
module = "monoid.mli";
78+
ocamlopt.byte;
79+
{
80+
flags = "";
81+
module = "bad_ref_direct.ml";
82+
compiler_output = "bad_ref_direct.output";
83+
ocamlopt_byte_exit_status = "2";
84+
ocamlopt.byte;
85+
86+
compiler_reference = "bad_ref_direct.reference";
87+
check-ocamlopt.byte-output;
88+
}{
89+
flags = "-as-argument-for Monoid";
90+
module = "bad_arg_impl.ml";
91+
compiler_output = "bad_arg_impl.output";
92+
ocamlopt_byte_exit_status = "2";
93+
ocamlopt.byte;
94+
95+
compiler_reference = "bad_arg_impl.reference";
96+
check-ocamlopt.byte-output;
97+
}{
98+
flags = "-as-argument-for Monoid";
99+
module = "bad_arg_intf.mli";
100+
compiler_output = "bad_arg_intf.output";
101+
ocamlopt_byte_exit_status = "2";
102+
ocamlopt.byte;
103+
104+
compiler_reference = "bad_arg_intf.reference";
105+
check-ocamlopt.byte-output;
106+
}{
107+
src = "string_monoid.ml";
108+
dst = "string_monoid_no_mli.ml";
109+
copy;
110+
111+
flags = "-as-argument-for Monoid";
112+
module = "string_monoid_no_mli.ml string_monoid.mli string_monoid.ml";
113+
ocamlopt.byte;
114+
115+
flags = "";
116+
module = "test_direct_access.ml";
117+
ocamlopt.byte;
118+
119+
flags = "";
120+
program = "${test_build_directory}/test_direct_access.exe";
121+
module = "";
122+
all_modules = "\
123+
string_monoid.cmx \
124+
string_monoid_no_mli.cmx \
125+
test_direct_access.cmx \
126+
";
127+
ocamlopt.byte;
128+
129+
output = "test_direct_access.output";
130+
run;
131+
132+
reference = "test_direct_access.reference";
133+
check-program-output;
134+
}
135+
}
13136
*)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
let () =
2+
let open Printf in
3+
printf "With .mli: %s\n" (String_monoid.append "Hello " "world!");
4+
printf "Without .mli: %s\n" (String_monoid_no_mli.append "Hello " "world!");
5+
()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
With .mli: Hello world!
2+
Without .mli: Hello world!

ocaml/typing/env.ml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,10 @@ let register_import_as_opaque modname =
10151015
Persistent_env.register_import_as_opaque !persistent_env modname
10161016

10171017
let is_parameter_unit modname =
1018-
Persistent_env.is_registered_parameter_import !persistent_env modname
1018+
Persistent_env.is_parameter_import !persistent_env modname
1019+
1020+
let implemented_parameter modname =
1021+
Persistent_env.implemented_parameter !persistent_env modname
10191022

10201023
let reset_declaration_caches () =
10211024
Types.Uid.Tbl.clear !value_declarations;
@@ -2639,6 +2642,9 @@ let read_signature modname filename ~add_binding =
26392642
let mty = read_pers_mod modname filename ~add_binding in
26402643
Subst.Lazy.force_signature mty
26412644

2645+
let register_parameter_import import =
2646+
Persistent_env.register_parameter_import !persistent_env import
2647+
26422648
let is_identchar_latin1 = function
26432649
| 'A'..'Z' | 'a'..'z' | '_' | '\192'..'\214' | '\216'..'\246'
26442650
| '\248'..'\255' | '\'' | '0'..'9' -> true

ocaml/typing/env.mli

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,9 @@ val save_signature_with_imports:
477477
(* Arguments: signature, module name, module kind,
478478
file name, imported units with their CRCs. *)
479479

480+
(* Register a module as a parameter to this unit. *)
481+
val register_parameter_import: Compilation_unit.Name.t -> unit
482+
480483
(* Return the CRC of the interface of the given compilation unit *)
481484
val crc_of_unit: Compilation_unit.Name.t -> Digest.t
482485

@@ -496,6 +499,11 @@ val register_import_as_opaque: Compilation_unit.Name.t -> unit
496499
-as-parameter *)
497500
val is_parameter_unit: Compilation_unit.Name.t -> bool
498501

502+
(* [implemented_parameter md] is the argument given to -as-argument-for when
503+
[md] was compiled *)
504+
val implemented_parameter:
505+
Compilation_unit.Name.t -> Compilation_unit.Name.t option
506+
499507
(* Summaries -- compact representation of an environment, to be
500508
exported in debugging information. *)
501509

0 commit comments

Comments
 (0)