Skip to content

Commit 865e207

Browse files
authored
Refactor new mode syntax (#3522)
1 parent 90f3332 commit 865e207

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1684
-1574
lines changed

Diff for: jane/doc/extensions/modes/syntax.md

+76-77
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
# Motivation
2-
Previously we have a fixed set of mode names in the parser. Everytime we want to
3-
add more modes we need to update the parser (and correspondingly ocamlformat).
4-
This is too costy in the long term.
5-
6-
We introduce a new mode syntax that allows mode names (and mode expressions in
7-
the future) to enjoy a dedicated name space. As a result, any identifier can be
8-
used as a mode name.
9-
101
# Modes and modalities
112
Currently a mode expression is simply a space-delimited list of modes.
123

@@ -23,112 +14,120 @@ local
2314
local unique
2415
```
2516

26-
Currently modalities have the same syntax as modes:
17+
Modes are in a dedicated namespace separated from variable names or type names,
18+
which means you can continue to use `local` or `unique` as variable or type
19+
names.
20+
21+
Currently a modality expression is simply a space-delimited list of modalities.
2722

2823
```
2924
modality := local | global | ..
3025
modalities := separated_nonempty_list(SPACE, modality)
3126
```
27+
Similarly, modalities are in a dedicated namespace.
3228

3329
# Where can they appear
3430

35-
Mode expressions and modalities can appear after either `@` or `@@`. The former
36-
is used in most cases, while the latter is used for disambiguition. For example,
37-
in `val f : a -> b @ global`, the `@ global` could be annotating either `b` or
38-
`f`. To avoid the ambiguity, we will write `val f : a -> b @ local @@ global`
39-
where `local` is the mode of `b` and `global` is the modality on `f`.
31+
To write a mode expression in program, it has to be prefixed by an `@` symbol.
32+
Similarly, a modality expression has to be prefixed by an `@@` symbol. They can
33+
appear in several places in a program as described below.
4034

41-
## Function parameter
42-
```ocaml
43-
let foo ?(label_let_pattern = default) = ..
44-
let foo ~(label_let_pattern) = ..
45-
let foo (x @ modes) = ..
46-
let foo (x : ty @@ modes) = ..
47-
```
48-
where `label_let_pattern` could be
35+
## Arrow types
4936
```ocaml
50-
x @ modes
51-
x : ty @@ modes
52-
x : a b c. a -> b -> c @@ modes
53-
```
54-
Patterns that are not directly function parameters can’t have modes. For
55-
example:
56-
```
57-
let foo ((x, y) @ modes) = .. (error)
37+
a * b @ modes -> b @ modes
38+
foo:a * b @ modes -> b @ modes
39+
?foo:a * b @ modes -> b @ modes
5840
```
5941

60-
## Let bindings
42+
One should be careful about the precedence of `@`. In the following example,
43+
`modes` annotates `c`.
6144
```ocaml
62-
let x @ modes = ..
63-
let x : ty @@ modes = ..
64-
let x : type a b. ty @@ modes = ..
45+
a -> b -> c @ modes
6546
```
6647

67-
## Functions and their return
48+
You can use parentheses to override precedence. In the
49+
following example, `modes` annotates `b -> c`.
6850
```ocaml
69-
let (foo @ modes) x y = ..
70-
let foo x y @ modes = ..
71-
let foo x y : ty @@ modes = ..
72-
fun foo x y @ modes -> ..
73-
fun foo x y : ty @@ modes -> ..
51+
a -> (b -> c) @ modes
7452
```
7553

76-
## Arrow types
54+
## Function parameter
55+
The rule of thumb is: wherever a type constraint `x : ty` is allowed, a similar
56+
mode constraint `x @ modes` or type-and-mode constraint `x : ty @ modes` will be
57+
allowed.
7758
```ocaml
78-
a * b @ modes -> b @ modes
79-
foo:a * b @ modes -> b @ modes
80-
?foo:a * b @ modes -> b @ modes
59+
let foo ?(x : int @ modes = default) = ..
60+
let foo ?x:((a, b) : int @ modes = default)
61+
let foo ~(x : int @ modes) = ..
62+
let foo ~x:((a, b) : int @ modes) = ..
63+
let foo ((a, b) : int @ modes) = ..
8164
```
82-
83-
## Record fields & Value descriptions
84-
The two are similar in both semantics and syntax, so we will consider them
85-
together.
65+
Patterns that are not directly function parameters can’t have modes. For
66+
example, the following is not allowed, because `x @ local` is not a function
67+
parameter (but the first component of one).
8668
```ocaml
87-
type r = {x : string @@ global}
88-
type r = {x : string @ local -> string @ local @@ global}
89-
90-
val foo : string -> string @ local @@ portable
69+
let foo ((x @ local), y) = ..
9170
```
9271

93-
## Expressions
72+
Again, one should pay attention to the precedences. In the following example, the first
73+
`modes` annotates `'b`, while the second annotates `x`.
9474
```ocaml
95-
(expression : _ @@ local)
75+
let foo (x : 'a -> 'b @ modes) = ..
76+
let foo (x : ('a -> 'b) @ modes) = ..
9677
```
9778

98-
# Future works
99-
## Unzipped syntax
100-
In the future we will support
101-
```ocaml
102-
type r = string -> string @@ local unique -> unique local
103-
```
104-
which corresponds to
79+
## Let bindings
80+
The rule of thumb is: wherever a type constraint `pat : ty` is allowed, a similar
81+
mode constraint `pat @ modes` and type-and-mode constraint `pat : ty @ modes` will be
82+
allowed.
10583
```ocaml
106-
type r = string @@ local unique -> string @@ unique local
84+
let a : int @ modes = 42 in
85+
let (a, b) : int @ once portable = 42 in
10786
```
108-
This gets more complex when modalities are involved:
87+
88+
## Functions and their body
89+
You can specify the mode of the function itself:
10990
```ocaml
110-
type r = { x : string -> string @@ (local -> unique) global}
91+
let (foo @ modes) x y = ..
11192
```
112-
which is equivalent to
93+
You can also specify the mode of the function body:
11394
```ocaml
114-
type r = {x : string @ local -> string @ unique @@ global}
95+
let foo x y @ modes = ..
96+
let foo x y : ty @ modes = ..
97+
fun foo x y @ modes -> ..
11598
```
116-
where `global` is a modality on the `x` field.
99+
We don't support `fun foo x y : ty @ modes -> 42` due to a limitation in the
100+
parser.
117101

118-
## Syntax sugar
119-
Similar to
102+
## Expressions
120103
```ocaml
121-
let foo x y : int = exp in
104+
(expression : ty @ local)
122105
```
123-
which unfolds to
106+
We don't support `(expression @ modes)` because `@` is already parsed as a binary operator.
107+
108+
## Record fields
109+
Record fields can have modalities, for example:
124110
```ocaml
125-
let foo x y = exp : int in
111+
type r = {x : string @@ modalities}
112+
type r = {x : string @ modes -> string @ modes @@ modalities}
126113
```
127-
We should allow
114+
115+
## Signature items
116+
Signature items such as values can have modalities; for example:
128117
```ocaml
129-
let foo x y @ local = exp in
118+
val foo : string @@ modalities
119+
val bar : string @ modes -> string @ modes @@ modalities
130120
```
131-
unfold to
121+
122+
A signature can have default modalities that each item can override; for example:
132123
```ocaml
133-
let foo x y = exp : _ @@ local in
124+
sig @@ portable
125+
val foo : string (* have portable modality *)
126+
val bar : string -> string @@ nonportable (* not have portable modality *)
127+
end
134128
```
129+
130+
## Modules
131+
Support for modules with modes is being worked on and not ready for company-wide adoption.
132+
For the few use sites, the syntax should be self-explanatory. More documentation will come
133+
as it becomes ready.

Diff for: otherlibs/stdlib_alpha/capsule.ml

+11-11
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ end = struct
107107

108108
type 'k t = A.t
109109

110-
let[@inline] unsafe_mk () : _ @@ local = A.make Id.uninitialized
110+
let[@inline] unsafe_mk () : _ @ local = A.make Id.uninitialized
111111
let[@inline] id t =
112112
(* Safe since [Password.t] is only ever accessible by 1 fiber. *)
113113
match A.get_unsync t with
@@ -131,7 +131,7 @@ end = struct
131131
| already_set_id -> already_set_id)
132132
| set_id -> set_id
133133

134-
let unsafe_mk () : _ @@ local unyielding = A.make Id.uninitialized
134+
let unsafe_mk () : _ @ local unyielding = A.make Id.uninitialized
135135
end
136136

137137
let[@inline] shared t = t
@@ -585,10 +585,10 @@ module Mutex = struct
585585

586586
let[@inline] with_lock :
587587
type k.
588-
k t
588+
(k t
589589
-> (k Password.t @ local -> 'a) @ local
590-
-> 'a
591-
@@ portable
590+
-> 'a)
591+
@ portable
592592
= fun t f ->
593593
M.lock t.mutex;
594594
match t.poisoned with
@@ -647,10 +647,10 @@ module Rwlock = struct
647647

648648
let[@inline] with_write_lock :
649649
type k.
650-
k t
650+
(k t
651651
-> (k Password.t @ local -> 'a) @ local
652-
-> 'a
653-
@@ portable
652+
-> 'a)
653+
@ portable
654654
= fun t f ->
655655
Rw.lock_write t.rwlock;
656656
match t.state with
@@ -679,10 +679,10 @@ module Rwlock = struct
679679

680680
let[@inline] with_read_lock :
681681
type k.
682-
k t
682+
(k t
683683
-> (k Password.Shared.t @ local unyielding -> 'a) @ local
684-
-> 'a
685-
@@ portable
684+
-> 'a)
685+
@ portable
686686
= fun t f ->
687687
Rw.lock_read t.rwlock;
688688
match t.state with

Diff for: otherlibs/stdlib_alpha/effect.ml

+9-9
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ type last_fiber : immediate
390390
type (-'a, +'b) cont
391391

392392
(* CR borrowing: implement [borrow] without magic. *)
393-
let borrow (f : ('a, 'b) cont @ local -> 'c @ unique) (k : ('a, 'b) cont @@ unique)
394-
: 'c * ('a, 'b) cont @@ unique = f k, Obj.magic_unique k
393+
let borrow (f : ('a, 'b) cont @ local -> 'c @ unique) (k : ('a, 'b) cont @ unique)
394+
: 'c * ('a, 'b) cont @ unique = f k, Obj.magic_unique k
395395

396396
external get_cont_callstack :
397397
('a, 'b) cont @ local -> int -> Printexc.raw_backtrace @@ portable =
@@ -456,11 +456,11 @@ external reperform :
456456
let alloc_cont
457457
(type a b h e es)
458458
(module H : Handler.Create with type e = e and type es = es)
459-
(f : local_ h -> a -> b @@ once)
459+
(f : (local_ h -> a -> b) @ once)
460460
(h : h) : (a, (b, e * es) r) cont =
461461
let exception Ready__ of (a, (b, e * es) r) cont in
462462
let effc (type o eh) ((op, h) as perf : (o, eh) perform)
463-
(k : (o, (b, e * es) r) cont) last_fiber : _ @@ unique =
463+
(k : (o, (b, e * es) r) cont) last_fiber : _ @ unique =
464464
match h with
465465
| H.C h ->
466466
Op(op, h, k, last_fiber)
@@ -483,7 +483,7 @@ let alloc_cont
483483
let run_stack
484484
(type a h e es)
485485
(module H : Handler.Create with type e = e and type es = es)
486-
(f : local_ h -> a @@ once) (h : h) : (a, e * es) r =
486+
(f : (local_ h -> a) @ once) (h : h) : (a, e * es) r =
487487
let effc ((op, h) as perf) k last_fiber =
488488
match h with
489489
| H.C h ->
@@ -541,7 +541,7 @@ let discontinue_with_backtrace k e bt (local_ hs) =
541541
resume k (fun e -> Printexc.raise_with_backtrace e bt) e hs
542542

543543
let fiber (type a b e)
544-
(f : local_ e Handler.t -> a -> b @@ once)=
544+
(f : (local_ e Handler.t -> a -> b) @ once)=
545545
let module H = (val (Handler.create ()) :
546546
Handler.Create with type e = e and type es = unit)
547547
in
@@ -552,7 +552,7 @@ let fiber (type a b e)
552552
Cont { cont; mapping }
553553

554554
let fiber_with (type a b e es) (local_ l : es Handler.List.Length.t)
555-
(f : local_ (e * es) Handler.List.t -> a -> b @@ once) =
555+
(f : (local_ (e * es) Handler.List.t -> a -> b) @ once) =
556556
let module H = (val (Handler.create ()) :
557557
Handler.Create with type e = e and type es = es)
558558
in
@@ -564,7 +564,7 @@ let fiber_with (type a b e es) (local_ l : es Handler.List.Length.t)
564564
let cont = alloc_cont (module H) f handlers in
565565
Cont { cont; mapping }
566566

567-
let run (type a e) (f : local_ e Handler.t -> a @@ once) =
567+
let run (type a e) (f : (local_ e Handler.t -> a) @ once) =
568568
let module H = (val (Handler.create ()) :
569569
Handler.Create with type e = e and type es = unit)
570570
in
@@ -574,7 +574,7 @@ let run (type a e) (f : local_ e Handler.t -> a @@ once) =
574574
handle (Mapping.empty ()) res
575575

576576
let run_with (type a e es) (local_ hs : es Handler.List.t)
577-
(f : local_ (e * es) Handler.List.t -> a @@ once) =
577+
(f : (local_ (e * es) Handler.List.t -> a) @ once) =
578578
let module H = (val (Handler.create ()) :
579579
Handler.Create with type e = e and type es = es)
580580
in

0 commit comments

Comments
 (0)