Skip to content

Commit c3e3546

Browse files
committed
Add support for the [@atomic] attribute on mutable fields
Add support to only the frontend for specifying the `[@atomic]` attribute on (only) mutable fields. This is a no-op currently, but is forwarded down through the ld_mutable on the label description in the typedtree. This is the first of many commits pulling in upstream support[0] for atomic record fields. I've slightly diverged from the design there, by adding atomic_flag to mutability only under Mutable rather than as a new ld_atomic field, since that feels like a better design (it avoids immutable atomic fields by construction, rather than having to assert that they never happen) [0] ocaml/ocaml#13404
1 parent dc67a4d commit c3e3546

File tree

15 files changed

+144
-51
lines changed

15 files changed

+144
-51
lines changed

chamelon/compat.jst.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,12 @@ type tpat_array_identifier = mutability * Jkind.sort
308308

309309
let mkTpat_array
310310
?id:(mut, arg_sort =
311-
(Mutable Alloc.Comonadic.Const.legacy, Jkind.Sort.value)) l =
311+
( Mutable
312+
{
313+
modal_upper_bound = Alloc.Comonadic.Const.legacy;
314+
atomic = Nonatomic;
315+
},
316+
Jkind.Sort.value )) l =
312317
Tpat_array (mut, arg_sort, l)
313318

314319
type tpat_tuple_identifier = string option list

parsing/asttypes.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ type private_flag = Private | Public
4040

4141
type mutable_flag = Immutable | Mutable
4242

43+
type atomic_flag = Nonatomic | Atomic
44+
4345
type virtual_flag = Virtual | Concrete
4446

4547
type override_flag = Override | Fresh

parsing/builtin_attributes.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ let warn_unused () =
6969
misplaced attribute warnings. *)
7070
let builtin_attrs =
7171
[ "inline"
72+
; "atomic"
7273
; "inlined"
7374
; "specialise"
7475
; "specialised"
@@ -1107,3 +1108,5 @@ let get_tracing_probe_payload (payload : Parsetree.payload) =
11071108
| _ -> Error ()
11081109
in
11091110
Ok { name; name_loc; enabled_at_init; arg }
1111+
1112+
let has_atomic attrs = has_attribute "atomic" attrs

parsing/builtin_attributes.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,5 @@ type tracing_probe =
345345
*)
346346
val get_tracing_probe_payload :
347347
Parsetree.payload -> (tracing_probe, unit) result
348+
349+
val has_atomic: Parsetree.attributes -> bool

testsuite/tests/compiler-libs/test_untypeast.ml

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,28 @@ let run s =
88
let pe = Parse.expression (Lexing.from_string s) in
99
let te = Typecore.type_expression (Lazy.force Env.initial) pe in
1010
let ute = Untypeast.untype_expression te in
11-
Format.asprintf "%a" Pprintast.expression ute
11+
Format.printf "%a@." Pprintast.expression ute
1212
;;
1313

1414
[%%expect{|
15-
val run : string -> string = <fun>
15+
val run : string -> unit = <fun>
1616
|}];;
1717

1818
run {| match None with Some (Some _) -> () | _ -> () |};;
1919

2020
[%%expect{|
21-
- : string = "match None with | Some (Some _) -> () | _ -> ()"
21+
match None with | Some (Some _) -> () | _ -> ()
22+
- : unit = ()
23+
|}];;
24+
25+
run {| let open struct type t = { mutable x : int [@atomic] } end in
26+
let _ = fun (v : t) -> v.x in () |};;
27+
28+
[%%expect{|
29+
let open struct type t = {
30+
mutable x: int [@atomic ]} end in
31+
let _ = fun (v : t) -> v.x in ()
32+
- : unit = ()
2233
|}];;
2334

2435
(***********************************)
@@ -28,20 +39,23 @@ run {| match None with Some (Some _) -> () | _ -> () |};;
2839
run {| fun x y z -> function w -> x y z w |};;
2940

3041
[%%expect{|
31-
- : string = "fun x y z -> function | w -> x y z w"
42+
fun x y z -> function | w -> x y z w
43+
- : unit = ()
3244
|}];;
3345

3446
(* 3-ary function returning a 1-ary function *)
3547
run {| fun x y z -> (function w -> x y z w) |};;
3648

3749
[%%expect{|
38-
- : string = "fun x y z -> (function | w -> x y z w)"
50+
fun x y z -> (function | w -> x y z w)
51+
- : unit = ()
3952
|}];;
4053

4154
run {| match None with Some (Some _) -> () | _ -> () |};;
4255

4356
[%%expect{|
44-
- : string = "match None with | Some (Some _) -> () | _ -> ()"
57+
match None with | Some (Some _) -> () | _ -> ()
58+
- : unit = ()
4559
|}];;
4660

4761
(***********************************)
@@ -51,14 +65,16 @@ run {| match None with Some (Some _) -> () | _ -> () |};;
5165
run {| fun x y z -> function w -> x y z w |};;
5266

5367
[%%expect{|
54-
- : string = "fun x y z -> function | w -> x y z w"
68+
fun x y z -> function | w -> x y z w
69+
- : unit = ()
5570
|}];;
5671

5772
(* 3-ary function returning a 1-ary function *)
5873
run {| fun x y z -> (function w -> x y z w) |};;
5974

6075
[%%expect{|
61-
- : string = "fun x y z -> (function | w -> x y z w)"
76+
fun x y z -> (function | w -> x y z w)
77+
- : unit = ()
6278
|}];;
6379

6480
(***********************************)
@@ -67,27 +83,30 @@ run {| fun x y z -> (function w -> x y z w) |};;
6783
run {| let foo : 'a. 'a -> 'a = fun x -> x in foo |}
6884

6985
[%%expect{|
70-
- : string = "let foo : ('a : value) . 'a -> 'a = fun x -> x in foo"
86+
let foo : ('a : value) . 'a -> 'a = fun x -> x in foo
87+
- : unit = ()
7188
|}];;
7289

7390
run {| let foo : type a . a -> a = fun x -> x in foo |}
7491

7592
[%%expect{|
76-
- : string =
77-
"let foo : ('a : value) . 'a -> 'a = fun (type a) -> ( (fun x -> x : a -> a)) in\nfoo"
93+
let foo : ('a : value) . 'a -> 'a = fun (type a) -> ( (fun x -> x : a -> a)) in
94+
foo
95+
- : unit = ()
7896
|}];;
7997

8098
(* CR: untypeast/pprintast are totally busted on programs with modes in value
8199
bindings. Fix this. *)
82100
run {| let foo : ('a -> 'a) @ portable = fun x -> x in foo |}
83101

84102
[%%expect{|
85-
- : string =
86-
"let (foo : 'a -> 'a) = ((fun x -> x : 'a -> 'a) : _ @ portable) in foo"
103+
let (foo : 'a -> 'a) = ((fun x -> x : 'a -> 'a) : _ @ portable) in foo
104+
- : unit = ()
87105
|}];;
88106

89107
run {| let foo : 'a . ('a -> 'a) @ portable = fun x -> x in foo |}
90108

91109
[%%expect{|
92-
- : string = "let foo : ('a : value) . 'a -> 'a = fun x -> x in foo"
110+
let foo : ('a : value) . 'a -> 'a = fun x -> x in foo
111+
- : unit = ()
93112
|}];;

typing/includecore.ml

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ let value_descriptions ~loc env name
154154
let ty2, mode_l2, mode_y2, _ = Ctype.instance_prim p2 vd2.val_type in
155155
Option.iter (Mode.Locality.equate_exn loc) mode_l2;
156156
Option.iter (Mode.Yielding.equate_exn yield) mode_y2;
157-
try
157+
try
158158
Ctype.moregeneral env true ty1 ty2
159-
with Ctype.Moregen err ->
159+
with Ctype.Moregen err ->
160160
raise (Dont_match (Type err))
161161
) yielding
162162
) locality;
@@ -239,6 +239,7 @@ type kind_mismatch = type_kind * type_kind
239239
type label_mismatch =
240240
| Type of Errortrace.equality_error
241241
| Mutability of position
242+
| Atomicity of position
242243
| Modality of Modality.Value.equate_error
243244

244245
type record_change =
@@ -402,6 +403,10 @@ let report_label_mismatch first second env ppf err =
402403
Format.fprintf ppf "%s is mutable and %s is not."
403404
(String.capitalize_ascii (choose ord first second))
404405
(choose_other ord first second)
406+
| Atomicity ord ->
407+
Format.fprintf ppf "%s is atomic and %s is not."
408+
(String.capitalize_ascii (choose ord first second))
409+
(choose_other ord first second)
405410
| Modality err_ -> report_modality_equate_error first second ppf err_
406411

407412
let pp_record_diff first second prefix decl env ppf (x : record_change) =
@@ -685,21 +690,27 @@ module Record_diffing = struct
685690
let compare_labels env params1 params2
686691
(ld1 : Types.label_declaration)
687692
(ld2 : Types.label_declaration) =
688-
let mut =
693+
let err =
689694
match ld1.ld_mutable, ld2.ld_mutable with
690695
| Immutable, Immutable -> None
691-
| Mutable _, Immutable -> Some First
692-
| Immutable, Mutable _ -> Some Second
693-
| Mutable m1, Mutable m2 ->
694-
let open Mode.Alloc.Comonadic.Const in
695-
(if not (Misc.Le_result.equal ~le m1 legacy) then
696-
Misc.fatal_errorf "Unexpected mutable(%a)" print m1);
697-
(if not (Misc.Le_result.equal ~le m2 legacy) then
698-
Misc.fatal_errorf "Unexpected mutable(%a)" print m2);
699-
None
696+
| Mutable _, Immutable -> Some (Mutability First)
697+
| Immutable, Mutable _ -> Some (Mutability Second)
698+
| Mutable { modal_upper_bound = m1; atomic = atomic1 },
699+
Mutable { modal_upper_bound = m2; atomic = atomic2 } ->
700+
begin match atomic1, atomic2 with
701+
| Atomic, Nonatomic -> Some (Atomicity First)
702+
| Nonatomic, Atomic -> Some (Atomicity Second)
703+
| Atomic, Atomic | Nonatomic, Nonatomic ->
704+
let open Mode.Alloc.Comonadic.Const in
705+
(if not (Misc.Le_result.equal ~le m1 legacy) then
706+
Misc.fatal_errorf "Unexpected mutable(%a)" print m1);
707+
(if not (Misc.Le_result.equal ~le m2 legacy) then
708+
Misc.fatal_errorf "Unexpected mutable(%a)" print m2);
709+
None
710+
end
700711
in
701-
begin match mut with
702-
| Some mut -> Some (Mutability mut)
712+
begin match err with
713+
| Some err -> Some err
703714
| None ->
704715
match
705716
Modality.Value.Const.equate ld1.ld_modalities ld2.ld_modalities

typing/includecore.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type kind_mismatch = type_kind * type_kind
6363
type label_mismatch =
6464
| Type of Errortrace.equality_error
6565
| Mutability of position
66+
| Atomicity of position
6667
| Modality of Mode.Modality.Value.equate_error
6768

6869
type record_change =

typing/printtyp.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,10 +1838,10 @@ let param_jkind ty =
18381838
let tree_of_label l =
18391839
let mut =
18401840
match l.ld_mutable with
1841-
| Mutable m ->
1841+
| Mutable { modal_upper_bound; _ } ->
18421842
let mut =
18431843
let open Alloc.Comonadic.Const in
1844-
if Misc.Le_result.equal ~le m legacy then
1844+
if Misc.Le_result.equal ~le modal_upper_bound legacy then
18451845
Om_mutable None
18461846
else
18471847
Om_mutable (Some "<non-legacy>")

typing/printtyped.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ let fmt_mutable_flag f x =
9191
let fmt_mutable_mode_flag f (x : Types.mutability) =
9292
match x with
9393
| Immutable -> fprintf f "Immutable"
94-
| Mutable m ->
95-
fprintf f "Mutable(%a)" Mode.Alloc.Comonadic.Const.print m
94+
| Mutable { modal_upper_bound; atomic = Nonatomic } ->
95+
fprintf f "Mutable(%a)" Mode.Alloc.Comonadic.Const.print modal_upper_bound
96+
| Mutable { modal_upper_bound; atomic = Atomic } ->
97+
fprintf f "Atomic(%a)" Mode.Alloc.Comonadic.Const.print modal_upper_bound
9698

9799
let fmt_virtual_flag f x =
98100
match x with

typing/typecore.ml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ let mutable_mode m0 =
10181018
let check_construct_mutability ~loc ~env mutability ty ?modalities block_mode =
10191019
match mutability with
10201020
| Immutable -> ()
1021-
| Mutable m0 ->
1021+
| Mutable { modal_upper_bound = m0; _ } ->
10221022
let m0 = mutable_mode m0 in
10231023
let m0 = cross_left env ty ?modalities m0 in
10241024
submode ~loc ~env m0 block_mode
@@ -3034,7 +3034,11 @@ and type_pat_aux
30343034
| Ppat_array (mut, spl) ->
30353035
let mut =
30363036
match mut with
3037-
| Mutable -> Mutable Alloc.Comonadic.Const.legacy
3037+
| Mutable -> Mutable {
3038+
modal_upper_bound = Alloc.Comonadic.Const.legacy;
3039+
(* CR aspsmith: Revisit once we support atomic arrays *)
3040+
atomic = Nonatomic
3041+
}
30383042
| Immutable ->
30393043
Language_extension.assert_enabled ~loc Immutable_arrays ();
30403044
Immutable
@@ -6193,7 +6197,8 @@ and type_expect_
61936197
in
61946198
let (label_loc, label, newval) =
61956199
match label.lbl_mut with
6196-
| Mutable m0 ->
6200+
| Mutable { modal_upper_bound = m0; atomic } ->
6201+
ignore atomic; (* CR aspsmith: TODO *)
61976202
submode ~loc:record.exp_loc ~env rmode mode_mutate_mutable;
61986203
let mode = mutable_mode m0 |> mode_default in
61996204
let mode = mode_modality label.lbl_modalities mode in
@@ -6215,7 +6220,11 @@ and type_expect_
62156220
| Pexp_array(mut, sargl) ->
62166221
let mutability =
62176222
match mut with
6218-
| Mutable -> Mutable Alloc.Comonadic.Const.legacy
6223+
| Mutable -> Mutable {
6224+
modal_upper_bound = Alloc.Comonadic.Const.legacy;
6225+
(* CR aspsmith: Revisit once we support atomic record fields *)
6226+
atomic = Nonatomic;
6227+
}
62196228
| Immutable ->
62206229
Language_extension.assert_enabled ~loc Immutable_arrays ();
62216230
Immutable
@@ -9802,10 +9811,15 @@ and type_comprehension_expr ~loc ~env ~ty_expected ~attributes cexpr =
98029811
Predef.list_argument_jkind
98039812
| Pcomp_array_comprehension (amut, comp) ->
98049813
let container_type, mut = match amut with
9805-
| Mutable -> Predef.type_array, Mutable Alloc.Comonadic.Const.legacy
9806-
| Immutable ->
9807-
Language_extension.assert_enabled ~loc Immutable_arrays ();
9808-
Predef.type_iarray, Immutable
9814+
| Mutable ->
9815+
Predef.type_array, Mutable {
9816+
modal_upper_bound = Alloc.Comonadic.Const.legacy;
9817+
(* CR aspsmith: Revisit once we support atomic arrays *)
9818+
atomic = Nonatomic
9819+
}
9820+
| Immutable ->
9821+
Language_extension.assert_enabled ~loc Immutable_arrays ();
9822+
Predef.type_iarray, Immutable
98099823
in
98109824
(Array_comprehension mut : comprehension_type),
98119825
container_type,

0 commit comments

Comments
 (0)