Skip to content

Commit f56e3b7

Browse files
committed
Implement inference and add tests
1 parent 458d293 commit f56e3b7

File tree

22 files changed

+889
-194
lines changed

22 files changed

+889
-194
lines changed

chamelon/compat.jst.ml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ let mkTexp_ident ?id:(ident_kind, uu = (Id_value, shared_many_use))
1919
type nonrec apply_arg = apply_arg
2020

2121
type texp_apply_identifier =
22-
apply_position * Locality.l * Zero_alloc_utils.Assume_info.t
22+
apply_position * Locality.l * Builtin_attributes.zero_alloc_attribute
2323

2424
let mkTexp_apply
2525
?id:(pos, mode, za =
2626
( Default,
2727
Locality.disallow_right Locality.legacy,
28-
Zero_alloc_utils.Assume_info.none )) (exp, args) =
28+
Builtin_attributes.Default_zero_alloc )) (exp, args) =
2929
let args =
3030
List.map (fun (label, x) -> (Typetexp.transl_label label None, x)) args
3131
in
@@ -92,7 +92,7 @@ type texp_function_identifier = {
9292
ret_sort : Jkind.sort;
9393
region : bool;
9494
ret_mode : Alloc.l;
95-
zero_alloc : Builtin_attributes.zero_alloc_attribute;
95+
zero_alloc : Zero_alloc.t;
9696
}
9797

9898
let texp_function_cases_identifier_defaults =
@@ -119,7 +119,7 @@ let texp_function_defaults =
119119
ret_sort = Jkind.Sort.value;
120120
ret_mode = Alloc.disallow_right Alloc.legacy;
121121
region = false;
122-
zero_alloc = Builtin_attributes.Default_zero_alloc;
122+
zero_alloc = Zero_alloc.default;
123123
}
124124

125125
let mkTexp_function ?(id = texp_function_defaults)
@@ -403,7 +403,7 @@ let mk_value_description ~val_type ~val_kind ~val_attributes =
403403
val_modalities = Mode.Modality.Value.id;
404404
val_attributes;
405405
val_uid = Uid.internal_not_actually_unique;
406-
val_zero_alloc = Default_zero_alloc;
406+
val_zero_alloc = Zero_alloc.default;
407407
}
408408

409409
let mkTtyp_any = Ttyp_var (None, None)

native_toplevel/opttoploop.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ let name_expression ~loc ~attrs sort exp =
344344
val_kind = Val_reg;
345345
val_loc = loc;
346346
val_attributes = attrs;
347-
val_zero_alloc = Default_zero_alloc;
347+
val_zero_alloc = Zero_alloc.default;
348348
val_modalities = Mode.Modality.Value.id;
349349
val_uid = Uid.internal_not_actually_unique; }
350350
in

ocaml/lambda/translcore.ml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -353,14 +353,14 @@ let can_apply_primitive p pmode pos args =
353353
let zero_alloc_of_application
354354
~num_args (annotation : Builtin_attributes.zero_alloc_attribute) funct =
355355
let zero_alloc =
356-
match annotation with
357-
| Assume _ ->
356+
match annotation, funct.exp_desc with
357+
| Assume _, _ ->
358358
(* The user wrote a zero_alloc attribute on the application - keep it. *)
359359
annotation
360-
| Ignore_assert_all | Check _ ->
360+
| (Ignore_assert_all | Check _), _ ->
361361
(* These are rejected in typecore *)
362362
Misc.fatal_error "Translcore.zero_alloc_of_application: illegal attr"
363-
| Default_zero_alloc ->
363+
| Default_zero_alloc, Texp_ident (_, _, { val_zero_alloc; _ }, _, _) ->
364364
(* We assume the call is zero_alloc if the function is known to be
365365
zero_alloc. If the function is zero_alloc opt, then we need to be sure
366366
that the opt checks were run to license this assumption. We judge
@@ -371,18 +371,19 @@ let zero_alloc_of_application
371371
| Check_default | No_check -> false
372372
| Check_all | Check_opt_only -> true
373373
in
374-
match funct.exp_desc with
375-
| Texp_ident (_, _, { val_zero_alloc = (Check c); _ }, _, _)
376-
when c.arity = num_args && (use_opt || not c.opt) ->
374+
begin match Zero_alloc.get val_zero_alloc with
375+
| Check c when c.arity = num_args && (use_opt || not c.opt) ->
377376
Builtin_attributes.Assume {
378377
strict = c.strict;
379378
never_returns_normally = false;
380379
never_raises = false;
381380
arity = c.arity;
382381
loc = c.loc
383382
}
384-
| _ -> Builtin_attributes.Default_zero_alloc
385-
383+
| Check _ | Default_zero_alloc | Ignore_assert_all | Assume _ ->
384+
Builtin_attributes.Default_zero_alloc
385+
end
386+
| Default_zero_alloc, _ -> Builtin_attributes.Default_zero_alloc
386387
in
387388
Builtin_attributes.assume_zero_alloc zero_alloc
388389

@@ -1619,6 +1620,7 @@ and transl_function ~in_new_scope ~scopes e params body
16191620
~zero_alloc =
16201621
let attrs = e.exp_attributes in
16211622
let mode = transl_alloc_mode_r alloc_mode in
1623+
let zero_alloc = Zero_alloc.get zero_alloc in
16221624
let assume_zero_alloc = Builtin_attributes.assume_zero_alloc zero_alloc in
16231625
let scopes =
16241626
if in_new_scope then
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
(* TEST
2+
readonly_files = "cmi_test_lib.ml";
3+
setup-ocamlc.byte-build-env;
4+
module = "cmi_test_lib.ml";
5+
ocamlc.byte;
6+
flags += "-I ocamlc.byte";
7+
expect;
8+
*)
9+
10+
(* Here we show the signatures of [cmi_test_a] and the modules within it do not
11+
have zero_alloc variables - we can't add further zero_alloc constraints. *)
12+
module M1 : sig
13+
val[@zero_alloc] f_unconstrained_variable : int -> int
14+
end = Cmi_test_lib
15+
[%%expect{|
16+
Line 3, characters 6-18:
17+
3 | end = Cmi_test_lib
18+
^^^^^^^^^^^^
19+
Error: Signature mismatch:
20+
Modules do not match:
21+
sig
22+
val f_unconstrained_variable : int -> int
23+
module M_constrained_variable =
24+
Cmi_test_lib.M_constrained_variable
25+
module M_no_variable = Cmi_test_lib.M_no_variable
26+
end
27+
is not included in
28+
sig val f_unconstrained_variable : int -> int [@@zero_alloc] end
29+
Values do not match:
30+
val f_unconstrained_variable : int -> int
31+
is not included in
32+
val f_unconstrained_variable : int -> int [@@zero_alloc]
33+
The former provides a weaker "zero_alloc" guarantee than the latter.
34+
Hint: Add a "zero_alloc" attribute to the implementation.
35+
File "cmi_test_lib.ml", line 4, characters 4-28: Actual declaration
36+
|}]
37+
38+
module M2 : sig
39+
val[@zero_alloc strict] f : int -> int
40+
end = Cmi_test_lib.M_constrained_variable
41+
[%%expect{|
42+
Line 3, characters 6-41:
43+
3 | end = Cmi_test_lib.M_constrained_variable
44+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45+
Error: Signature mismatch:
46+
Modules do not match:
47+
sig val f : int -> int [@@zero_alloc] end
48+
is not included in
49+
sig val f : int -> int [@@zero_alloc strict] end
50+
Values do not match:
51+
val f : int -> int [@@zero_alloc]
52+
is not included in
53+
val f : int -> int [@@zero_alloc strict]
54+
The former provides a weaker "zero_alloc" guarantee than the latter.
55+
File "cmi_test_lib.ml", line 7, characters 6-7: Actual declaration
56+
|}]
57+
58+
module M3 : sig
59+
val[@zero_alloc] f : int -> int
60+
end = Cmi_test_lib.M_no_variable
61+
[%%expect{|
62+
Line 3, characters 6-32:
63+
3 | end = Cmi_test_lib.M_no_variable
64+
^^^^^^^^^^^^^^^^^^^^^^^^^^
65+
Error: Signature mismatch:
66+
Modules do not match:
67+
sig val f : int -> int end
68+
is not included in
69+
sig val f : int -> int [@@zero_alloc] end
70+
Values do not match:
71+
val f : int -> int
72+
is not included in
73+
val f : int -> int [@@zero_alloc]
74+
The former provides a weaker "zero_alloc" guarantee than the latter.
75+
Hint: Add a "zero_alloc" attribute to the implementation.
76+
File "cmi_test_lib.ml", line 13, characters 2-20: Actual declaration
77+
|}]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(* This file is part of a test that zero_alloc variables don't remain in
2+
cmis. *)
3+
4+
let f_unconstrained_variable x = x+1
5+
6+
module M_constrained_variable = struct
7+
let f x = x+2
8+
end
9+
10+
module _ : sig val[@zero_alloc] f : int -> int end = M_constrained_variable
11+
12+
module M_no_variable : sig
13+
val f : int -> int
14+
end = struct
15+
let f x = x+3
16+
end

0 commit comments

Comments
 (0)