Skip to content

Commit 2a90741

Browse files
authored
flambda-backend: Add -as-parameter option (#1751)
* Add `-as-parameter` option This allows compiling an .mli as a _parameter module_ rather than a normal compilation unit. A parameter module defines a module _type_ rather than a module, so it cannot be referred to directly from another module. A forthcoming PR will add the `-parameter P` option which adds the parameter module `P` as a parameter to the current module, which then allows references to `P` in the module. Further PRs will deal with how to actually use a module that takes parameters. For the moment, `-parameter` is unimplemented, so any reference to a parameter module is an error. * Add checks for misuse of `-as-parameter` * Raise error on combination of `-as-parameter` and `-for-pack` * Add test for check for compiling `.ml` of parameter `.mli` I've disabled the check on the output, since currently we get the wrong error message (and the one we get is confusing). This will be much easier to fix when PR #1764 is fixed to avoid unhelpful checks on `.mli` files that are loaded directly rather than as part of name resolution. * Add test of check for `-as-parameter` on implementation * Implement `register_parameter_import` and `is_registered_parameter_import` * Code review * Code review * Fix error message and re-enable test
1 parent 2099475 commit 2a90741

29 files changed

+269
-32
lines changed

boot/ocamlc

5.26 KB
Binary file not shown.

boot/ocamllex

12 Bytes
Binary file not shown.

driver/compile_common.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ let typecheck_intf info ast =
6363
Profile.(record_call typing) @@ fun () ->
6464
let tsg =
6565
ast
66-
|> Typemod.type_interface info.env
66+
|> Typemod.type_interface info.module_name info.env
6767
|> print_if info.ppf_dump Clflags.dump_typedtree Printtyped.interface
6868
in
6969
let sg = tsg.Typedtree.sig_type in
@@ -80,9 +80,15 @@ let typecheck_intf info ast =
8080

8181
let emit_signature info ast tsg =
8282
let sg =
83+
let kind : Cmi_format.kind =
84+
if !Clflags.as_parameter then
85+
Parameter
86+
else
87+
Normal
88+
in
8389
let alerts = Builtin_attributes.alerts_of_sig ast in
8490
Env.save_signature ~alerts tsg.Typedtree.sig_type
85-
info.module_name (info.output_prefix ^ ".cmi")
91+
info.module_name kind (info.output_prefix ^ ".cmi")
8692
in
8793
Typemod.save_signature info.module_name tsg
8894
info.output_prefix info.source_file info.env sg

driver/main_args.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,11 @@ let mk_match_context_rows f =
631631
Printf.sprintf
632632
"<n> (advanced, see manual section %d.%d.)" chapter section
633633

634+
let mk_as_parameter f =
635+
"-as-parameter", Arg.Unit f,
636+
"<module name> Compiles the interface as a parameter for an open module."
637+
;;
638+
634639
let mk_use_prims f =
635640
"-use-prims", Arg.String f, "<file> (undocumented)"
636641

@@ -918,6 +923,7 @@ end
918923
module type Compiler_options = sig
919924
val _a : unit -> unit
920925
val _annot : unit -> unit
926+
val _as_parameter : unit -> unit
921927
val _binannot : unit -> unit
922928
val _binannot_cms : unit -> unit
923929
val _c : unit -> unit
@@ -1116,6 +1122,7 @@ struct
11161122
mk_absname F._absname;
11171123
mk_no_absname F._no_absname;
11181124
mk_annot F._annot;
1125+
mk_as_parameter F._as_parameter;
11191126
mk_binannot F._binannot;
11201127
mk_binannot_cms F._binannot_cms;
11211128
mk_c F._c;
@@ -1324,6 +1331,7 @@ struct
13241331
mk_afl_instrument F._afl_instrument;
13251332
mk_afl_inst_ratio F._afl_inst_ratio;
13261333
mk_annot F._annot;
1334+
mk_as_parameter F._as_parameter;
13271335
mk_binannot F._binannot;
13281336
mk_binannot_cms F._binannot_cms;
13291337
mk_inline_branch_factor F._inline_branch_factor;
@@ -1880,6 +1888,7 @@ module Default = struct
18801888
let _annot = set annotations
18811889
let _args = Arg.read_arg
18821890
let _args0 = Arg.read_arg0
1891+
let _as_parameter = set as_parameter
18831892
let _binannot = set binary_annotations
18841893
let _binannot_cms = set binary_annotations_cms
18851894
let _c = set compile_only

driver/main_args.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ end
8484
module type Compiler_options = sig
8585
val _a : unit -> unit
8686
val _annot : unit -> unit
87+
val _as_parameter : unit -> unit
8788
val _binannot : unit -> unit
8889
val _binannot_cms : unit -> unit
8990
val _c : unit -> unit

file_formats/cmi_format.ml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ type pers_flags =
2020
| Alerts of alerts
2121
| Opaque
2222

23+
type kind =
24+
| Normal
25+
| Parameter
26+
2327
type error =
2428
| Not_an_interface of filepath
2529
| Wrong_version_interface of filepath * string
@@ -53,10 +57,15 @@ module Serialized = Types.Make_wrapped(struct type 'a t = int end)
5357
input_value and output_value usage. *)
5458
type crcs = Import_info.t array (* smaller on disk than using a list *)
5559
type flags = pers_flags list
56-
type header = Compilation_unit.t * Serialized.signature
60+
type header = {
61+
header_name : Compilation_unit.t;
62+
header_kind : kind;
63+
header_sign : Serialized.signature;
64+
}
5765

5866
type 'sg cmi_infos_generic = {
5967
cmi_name : Compilation_unit.t;
68+
cmi_kind : kind;
6069
cmi_sign : 'sg;
6170
cmi_crcs : crcs;
6271
cmi_flags : flags;
@@ -108,11 +117,16 @@ let input_cmi_lazy ic =
108117
in
109118
let data_len = Bytes.get_int64_ne (read_bytes 8) 0 |> Int64.to_int in
110119
let data = read_bytes data_len in
111-
let (name, sign) = (input_value ic : header) in
120+
let {
121+
header_name = name;
122+
header_kind = kind;
123+
header_sign = sign;
124+
} = (input_value ic : header) in
112125
let crcs = (input_value ic : crcs) in
113126
let flags = (input_value ic : flags) in
114127
{
115128
cmi_name = name;
129+
cmi_kind = kind;
116130
cmi_sign = deserialize data sign;
117131
cmi_crcs = crcs;
118132
cmi_flags = flags;
@@ -169,7 +183,12 @@ let output_cmi filename oc cmi =
169183
(* BACKPORT BEGIN *)
170184
(* CR ocaml 5 compressed-marshal mshinwell:
171185
upstream uses [Compression] here *)
172-
output_value oc ((cmi.cmi_name, sign) : header);
186+
output_value oc
187+
{
188+
header_name = cmi.cmi_name;
189+
header_kind = cmi.cmi_kind;
190+
header_sign = sign;
191+
};
173192
(* BACKPORT END *)
174193
flush oc;
175194
let crc = Digest.file filename in

file_formats/cmi_format.mli

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@ type pers_flags =
2020
| Alerts of alerts
2121
| Opaque
2222

23+
type kind =
24+
| Normal
25+
| Parameter
26+
2327
type 'sg cmi_infos_generic = {
2428
cmi_name : Compilation_unit.t;
29+
cmi_kind : kind;
2530
cmi_sign : 'sg;
2631
cmi_crcs : Import_info.t array;
2732
cmi_flags : pers_flags list;

ocamldoc/odoc_analyse.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ 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 (initial_env()) ast in
125+
let sg = Typemod.type_interface compilation_unit (initial_env()) ast in
126126
Warnings.check_fatal ();
127127
(ast, sg, inputfile)
128128

testsuite/tests/self-contained-toplevel/main.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ let () =
2626
Persistent_signature.load := (fun ~allow_hidden ~unit_name ->
2727
match unit_name |> Compilation_unit.Name.to_string with
2828
| "Foo" ->
29-
let {Cmi_format.cmi_name; cmi_sign; cmi_crcs; cmi_flags} =
29+
let {Cmi_format.cmi_name; cmi_kind; cmi_sign; cmi_crcs; cmi_flags} =
3030
Marshal.from_string Cached_cmi.foo 0
3131
in
3232
let cmi =
3333
{ Cmi_format.cmi_name;
34+
cmi_kind;
3435
cmi_sign = Subst.Lazy.of_signature cmi_sign;
3536
cmi_crcs;
3637
cmi_flags
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
(* TEST
2+
3+
readonly_files = "bad_impl_as_param.reference"
4+
5+
* setup-ocamlc.byte-build-env
6+
** ocamlc.byte
7+
flags = "-as-parameter"
8+
modules = "bad_impl_as_param.ml"
9+
ocamlc_byte_exit_status = "2"
10+
compiler_output = "bad_impl_as_param.output"
11+
*** check-ocamlc.byte-output
12+
compiler_reference = "bad_impl_as_param.reference" *)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
File "bad_impl_as_param.ml", line 1:
2+
Error: Cannot compile an implementation with -as-parameter.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(* TEST
2+
3+
readonly_files = "bad_param_impl.mli bad_param_impl.reference"
4+
5+
* setup-ocamlc.byte-build-env
6+
** ocamlc.byte
7+
flags = "-as-parameter"
8+
module = "bad_param_impl.mli"
9+
*** ocamlc.byte
10+
flags = ""
11+
module = "bad_param_impl.ml"
12+
ocamlc_byte_exit_status = "2"
13+
compiler_output = "bad_param_impl.output"
14+
**** check-ocamlc.byte-output
15+
compiler_reference = "bad_param_impl.reference"
16+
*)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(* To be compiled with [-as-parameter] *)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
File "bad_param_impl.ml", line 1:
2+
Error: The interface for Bad_param_impl was compiled with -as-parameter.
3+
It cannot be implemented directly.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(* TEST
2+
3+
readonly_files = "bad_param_packed.reference"
4+
5+
* setup-ocamlc.byte-build-env
6+
** ocamlc.byte
7+
flags = "-as-parameter -for-pack Pack"
8+
module = "bad_param_packed.mli"
9+
compiler_output = "bad_param_packed.output"
10+
ocamlc_byte_exit_status = "2"
11+
*** check-ocamlc.byte-output
12+
compiler_reference = "bad_param_packed.reference"
13+
*)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
File "_none_", line 1:
2+
Error: Cannot compile a parameter with -for-pack.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(* [Monoid] is not a parameter *)
2+
3+
let empty = Monoid.id
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
File "bad_ref_direct.ml", line 1:
2+
Error: The file monoid.cmi contains the interface of a parameter.
3+
Monoid is not declared as a parameter for the current unit (-parameter Monoid).
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 -> t
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
(* TEST
2+
3+
readonly_files = "\
4+
bad_ref_direct.ml bad_ref_direct.reference \
5+
monoid.mli \
6+
"
7+
8+
* setup-ocamlc.byte-build-env
9+
** ocamlc.byte
10+
flags = "-as-parameter"
11+
module = "monoid.mli"
12+
*** ocamlc.byte
13+
module = "bad_ref_direct.ml"
14+
compiler_output = "bad_ref_direct.output"
15+
ocamlc_byte_exit_status = "2"
16+
**** check-ocamlc.byte-output
17+
compiler_reference = "bad_ref_direct.reference"
18+
*)

tools/objinfo.ml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,15 @@ let print_cma_infos (lib : Cmo_format.library) =
9393
printf "\n";
9494
List.iter print_cmo_infos lib.lib_units
9595

96-
let print_cmi_infos name crcs =
96+
let print_cmi_infos name crcs kind =
97+
let open Cmi_format in
9798
printf "Unit name: %a\n" Compilation_unit.output name;
99+
let is_param =
100+
match kind with
101+
| Normal -> false
102+
| Parameter -> true
103+
in
104+
printf "Is parameter: %s\n" (if is_param then "YES" else "no");
98105
printf "Interfaces imported:\n";
99106
Array.iter print_intf_import crcs
100107

@@ -340,6 +347,7 @@ let dump_obj_by_kind filename ic obj_kind =
340347
| None -> ()
341348
| Some cmi ->
342349
print_cmi_infos cmi.Cmi_format.cmi_name cmi.Cmi_format.cmi_crcs
350+
cmi.Cmi_format.cmi_kind
343351
end;
344352
begin match cmt with
345353
| None -> ()

typing/env.ml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,9 @@ let is_imported_opaque modname =
10371037
let register_import_as_opaque modname =
10381038
Persistent_env.register_import_as_opaque !persistent_env modname
10391039

1040+
let is_parameter_unit modname =
1041+
Persistent_env.is_registered_parameter_import !persistent_env modname
1042+
10401043
let reset_declaration_caches () =
10411044
Types.Uid.Tbl.clear !value_declarations;
10421045
Types.Uid.Tbl.clear !type_declarations;
@@ -2685,30 +2688,29 @@ let persistent_structures_of_dir dir =
26852688
|> String.Set.of_seq
26862689

26872690
(* Save a signature to a file *)
2688-
let save_signature_with_transform cmi_transform ~alerts sg modname filename =
2691+
let save_signature_with_transform cmi_transform ~alerts sg modname kind
2692+
filename =
26892693
Btype.cleanup_abbrev ();
26902694
Subst.reset_additional_action_type_id ();
26912695
let sg = Subst.Lazy.of_signature sg
26922696
|> Subst.Lazy.signature Make_local
26932697
(Subst.with_additional_action Prepare_for_saving Subst.identity)
26942698
in
26952699
let cmi =
2696-
Persistent_env.make_cmi !persistent_env modname sg alerts
2700+
Persistent_env.make_cmi !persistent_env modname kind sg alerts
26972701
|> cmi_transform in
26982702
let pers_sig =
26992703
Persistent_env.Persistent_signature.{ filename; cmi; visibility = Visible }
27002704
in
27012705
Persistent_env.save_cmi !persistent_env pers_sig;
27022706
cmi
27032707

2704-
let save_signature ~alerts sg modname filename =
2705-
save_signature_with_transform (fun cmi -> cmi)
2706-
~alerts sg modname filename
2708+
let save_signature ~alerts sg modname cu filename =
2709+
save_signature_with_transform (fun cmi -> cmi) ~alerts sg modname cu filename
27072710

2708-
let save_signature_with_imports ~alerts sg modname filename imports =
2711+
let save_signature_with_imports ~alerts sg modname cu filename imports =
27092712
let with_imports cmi = { cmi with cmi_crcs = imports } in
2710-
save_signature_with_transform with_imports
2711-
~alerts sg modname filename
2713+
save_signature_with_transform with_imports ~alerts sg modname cu filename
27122714

27132715
(* Make the initial environment, without language extensions *)
27142716
let initial =

typing/env.mli

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -474,15 +474,14 @@ val read_signature:
474474
Results: signature. If [add_binding] is true, creates an entry for
475475
the module in the environment. *)
476476
val save_signature:
477-
alerts:alerts -> signature -> Compilation_unit.t -> filepath
478-
-> Cmi_format.cmi_infos_lazy
479-
(* Arguments: signature, module name, file name. *)
477+
alerts:alerts -> signature -> Compilation_unit.t -> Cmi_format.kind
478+
-> filepath -> Cmi_format.cmi_infos_lazy
479+
(* Arguments: signature, module name, module kind, file name. *)
480480
val save_signature_with_imports:
481-
alerts:alerts -> signature -> Compilation_unit.t -> filepath
482-
-> Import_info.t array
483-
-> Cmi_format.cmi_infos_lazy
484-
(* Arguments: signature, module name, file name,
485-
imported units with their CRCs. *)
481+
alerts:alerts -> signature -> Compilation_unit.t -> Cmi_format.kind
482+
-> filepath -> Import_info.t array -> Cmi_format.cmi_infos_lazy
483+
(* Arguments: signature, module name, module kind,
484+
file name, imported units with their CRCs. *)
486485

487486
(* Return the CRC of the interface of the given compilation unit *)
488487
val crc_of_unit: Compilation_unit.Name.t -> Digest.t
@@ -499,6 +498,10 @@ val is_imported_opaque: Compilation_unit.Name.t -> bool
499498
(* [register_import_as_opaque md] registers [md] as an opaque imported module *)
500499
val register_import_as_opaque: Compilation_unit.Name.t -> unit
501500

501+
(* [is_parameter_unit md] returns true if [md] was compiled with
502+
-as-parameter *)
503+
val is_parameter_unit: Compilation_unit.Name.t -> bool
504+
502505
(* Summaries -- compact representation of an environment, to be
503506
exported in debugging information. *)
504507

0 commit comments

Comments
 (0)