Source file typemode.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
open Location
open Mode
open Jkind_axis
module Jkind = Btype.Jkind0
type 'a modes =
{ mode_modes : 'a;
mode_desc : Mode.Alloc.atom Location.loc list
}
type modalities =
{ moda_modalities : Mode.Modality.Const.t;
moda_desc : Mode.Modality.atom Location.loc list
}
type 'ax annot_type =
| Modifier : 'a Axis.t annot_type
| Mode : 'a Alloc.Axis.t annot_type
| Modality : 'a Modality.Axis.t annot_type
let print_annot_type (type a) ppf (annot_type : a annot_type) =
match annot_type with
| Modifier -> Format_doc.fprintf ppf "modifier"
| Mode -> Format_doc.fprintf ppf "mode"
| Modality -> Format_doc.fprintf ppf "modality"
let print_annot_axis (type a) (annot_type : a annot_type) ppf (ax : a) =
match annot_type with
| Modifier -> Format_doc.fprintf ppf "%s" (Axis.name ax)
| Mode -> Alloc.Axis.print ppf ax
| Modality ->
let (P ax) = Modality.Axis.to_value (P ax) in
Value.Axis.print ppf ax
type forbidden_modality_kind =
| Global_and_unique
(** [@@ global unique] must be forbidden, with [global] implying
[aliased]. Otherwise, borrowing would be unsound:
{v
type 'a t = { x : 'a @@ global unique }
let clone (x @ unique) =
borrow {x} ~f:(fun (t @ local) -> t.x : 'a @ global) (* leak *)
v} *)
type error =
| Forbidden_modality : 'a annot_type * forbidden_modality_kind -> error
| Duplicated_axis : 'a annot_type * 'a -> error
| Unrecognized_modifier : 'a annot_type * string -> error
exception Error of Location.t * error
module Mode_axis_pair = struct
type t = Mode.Alloc.atom
type t_value = Mode.Value.atom
let to_value (Atom (ax, a) : t) : t_value =
match Const.Axis.is_areality ax with
| Left Refl -> Atom (Comonadic Areality, Const.locality_as_regionality a)
| Right ax -> Atom (ax, a)
let of_string s : t =
let comonadic (type a) (ax : a Alloc.Comonadic.Axis.t) (a : a) : t =
Atom (Comonadic ax, a)
in
let monadic (type a) (ax : a Alloc.Monadic.Axis.t) (a : a) : t =
Atom (Monadic ax, a)
in
match[@warning "-18"] s with
| "local" -> comonadic Areality Local
| "global" -> comonadic Areality Global
| "unique" -> monadic Uniqueness Unique
| "aliased" -> monadic Uniqueness Aliased
| "once" -> comonadic Linearity Once
| "many" -> comonadic Linearity Many
| "nonportable" -> comonadic Portability Nonportable
| "corruptible" -> comonadic Portability Corruptible
| "shareable" -> comonadic Portability Shareable
| "portable" -> comonadic Portability Portable
| "contended" -> monadic Contention Contended
| "corrupted" -> monadic Contention Corrupted
| "shared" -> monadic Contention Shared
| "uncontended" -> monadic Contention Uncontended
| "unforkable" -> comonadic Forkable Unforkable
| "forkable" -> comonadic Forkable Forkable
| "yielding" -> comonadic Yielding Yielding
| "unyielding" -> comonadic Yielding Unyielding
| "stateless" -> comonadic Statefulness Stateless
| "reading" -> comonadic Statefulness Reading
| "writing" -> comonadic Statefulness Writing
| "stateful" -> comonadic Statefulness Stateful
| "immutable" -> monadic Visibility Immutable
| "read" -> monadic Visibility Read
| "write" -> monadic Visibility Write
| "read_write" -> monadic Visibility Read_write
| "static" -> monadic Staticity Static
| "dynamic" -> monadic Staticity Dynamic
| _ -> raise Not_found
end
module Modality_axis_pair = struct
type t = Modality.atom
let of_string s : t =
match[@warning "-18"]
Mode_axis_pair.to_value (Mode_axis_pair.of_string s)
with
| Atom (Monadic ax, mode) -> Atom (Monadic ax, Join_const mode)
| Atom (Comonadic ax, mode) -> Atom (Comonadic ax, Meet_const mode)
end
module Modifier_axis_pair = struct
type t = P : 'a Axis.t * 'a -> t
let of_string s : t =
match[@warning "-18"] Modality_axis_pair.of_string s with
| Atom (Monadic ax, m) -> P (Modal (Monadic ax), Modality m)
| Atom (Comonadic ax, m) -> P (Modal (Comonadic ax), Modality m)
| exception Not_found -> (
let nonmodal (type a) (ax : a Axis.Nonmodal.t) (a : a) : t =
P (Nonmodal ax, a)
in
match s with
| "internal" -> nonmodal Externality Internal
| "external64" -> nonmodal Externality External64
| "external_" -> nonmodal Externality External
| _ -> raise Not_found)
end
module Transled_modifiers = struct
module Monadic = Mode.Crossing.Monadic
module Comonadic = Mode.Crossing.Comonadic
type t =
{ areality : Mode.Regionality.Const.t Comonadic.Atom.t Location.loc option;
linearity : Mode.Linearity.Const.t Comonadic.Atom.t Location.loc option;
uniqueness : Mode.Uniqueness.Const.t Monadic.Atom.t Location.loc option;
portability :
Mode.Portability.Const.t Comonadic.Atom.t Location.loc option;
contention : Mode.Contention.Const.t Monadic.Atom.t Location.loc option;
forkable : Mode.Forkable.Const.t Comonadic.Atom.t Location.loc option;
yielding : Mode.Yielding.Const.t Comonadic.Atom.t Location.loc option;
statefulness :
Mode.Statefulness.Const.t Comonadic.Atom.t Location.loc option;
visibility : Mode.Visibility.Const.t Monadic.Atom.t Location.loc option;
staticity : Mode.Staticity.Const.t Monadic.Atom.t Location.loc option;
externality : Jkind_axis.Externality.t Location.loc option;
nullability : Jkind_axis.Nullability.t Location.loc option;
separability : Jkind_axis.Separability.t Location.loc option
}
let empty =
{ areality = None;
linearity = None;
uniqueness = None;
portability = None;
contention = None;
forkable = None;
yielding = None;
statefulness = None;
visibility = None;
externality = None;
nullability = None;
separability = None;
staticity = None
}
let get (type a) ~(axis : a Axis.t) (t : t) : a Location.loc option =
match axis with
| Modal (Comonadic Areality) -> t.areality
| Modal (Comonadic Linearity) -> t.linearity
| Modal (Monadic Uniqueness) -> t.uniqueness
| Modal (Comonadic Portability) -> t.portability
| Modal (Monadic Contention) -> t.contention
| Modal (Comonadic Forkable) -> t.forkable
| Modal (Comonadic Yielding) -> t.yielding
| Modal (Comonadic Statefulness) -> t.statefulness
| Modal (Monadic Visibility) -> t.visibility
| Modal (Monadic Staticity) -> t.staticity
| Nonmodal Externality -> t.externality
let set (type a) ~(axis : a Axis.t) (t : t) (value : a Location.loc option) :
t =
match axis with
| Modal (Comonadic Areality) -> { t with areality = value }
| Modal (Comonadic Linearity) -> { t with linearity = value }
| Modal (Monadic Uniqueness) -> { t with uniqueness = value }
| Modal (Comonadic Portability) -> { t with portability = value }
| Modal (Monadic Contention) -> { t with contention = value }
| Modal (Comonadic Forkable) -> { t with forkable = value }
| Modal (Comonadic Yielding) -> { t with yielding = value }
| Modal (Comonadic Statefulness) -> { t with statefulness = value }
| Modal (Monadic Visibility) -> { t with visibility = value }
| Modal (Monadic Staticity) -> { t with staticity = value }
| Nonmodal Externality -> { t with externality = value }
let meet_nullability t (nullability : Nullability.t loc) =
match t.nullability with
| Some existing when Nullability.le existing.txt nullability.txt -> t
| _ -> { t with nullability = Some nullability }
let meet_separability t separability =
match t.separability with
| Some existing when Separability.le existing.txt separability.txt -> t
| _ -> { t with separability = Some separability }
end
let implied_modalities (Atom (ax, a) : Modality.atom) : Modality.atom list =
match[@warning "-18"] ax, a with
| Comonadic Areality, Meet_const a ->
let f, y, u =
match a with
| Global ->
( Forkable.Const.Forkable,
Yielding.Const.Unyielding,
[Uniqueness.Const.Aliased] )
| Local -> Forkable.Const.Unforkable, Yielding.Const.Yielding, []
| Regional -> assert false
in
[ Modality.Atom (Comonadic Forkable, Meet_const f);
Atom (Comonadic Yielding, Meet_const y) ]
@ List.map (fun x -> Modality.Atom (Monadic Uniqueness, Join_const x)) u
| Monadic Visibility, Join_const a ->
let b : Contention.Const.t =
match a with
| Immutable -> Contended
| Read -> Shared
| Write -> Corrupted
| Read_write -> Uncontended
in
[Atom (Monadic Contention, Join_const b)]
| Comonadic Statefulness, Meet_const a ->
let b : Portability.Const.t =
match a with
| Stateless -> Portable
| Reading -> Shareable
| Writing -> Corruptible
| Stateful -> Nonportable
in
[Atom (Comonadic Portability, Meet_const b)]
| _ -> []
let enforce_forbidden_modalities ~loc annot_type m =
match
( Modality.Const.proj (Comonadic Areality) m,
Modality.Const.proj (Monadic Uniqueness) m )
with
| ( Meet_const Global,
Modality.Monadic.Atom.Join_const Mode.Uniqueness.Const.Unique ) ->
raise (Error (loc, Forbidden_modality (annot_type, Global_and_unique)))
| _ -> ()
let transl_mod_bounds annots =
let bounds_loc =
match List.map (fun { loc; _ } -> loc) annots with
| [] -> Location.none
| _ :: _ as locs -> Location.merge locs
in
let step bounds_so_far { txt = Parsetree.Mode txt; loc } =
match Modifier_axis_pair.of_string txt with
| P (type a) ((axis, mode) : a Axis.t * a) ->
let is_top = Per_axis.(le axis (max axis) mode) in
if is_top
then
();
let is_dup =
Option.is_some (Transled_modifiers.get ~axis bounds_so_far)
in
if is_dup then raise (Error (loc, Duplicated_axis (Modifier, axis)));
Transled_modifiers.set ~axis bounds_so_far (Some { txt = mode; loc })
| exception Not_found -> (
match txt with
| "non_pointer" ->
Transled_modifiers.meet_separability bounds_so_far
{ txt = Non_pointer; loc }
| "non_pointer64" ->
Transled_modifiers.meet_separability bounds_so_far
{ txt = Non_pointer64; loc }
| "non_float" ->
Transled_modifiers.meet_separability bounds_so_far
{ txt = Non_float; loc }
| "separable" ->
Transled_modifiers.meet_separability bounds_so_far
{ txt = Separable; loc }
| "maybe_separable" ->
Transled_modifiers.meet_separability bounds_so_far
{ txt = Maybe_separable; loc }
| "non_null" ->
Transled_modifiers.meet_nullability bounds_so_far
{ txt = Non_null; loc }
| "maybe_null" ->
Transled_modifiers.meet_nullability bounds_so_far
{ txt = Maybe_null; loc }
| "everything" ->
Transled_modifiers.
{ areality =
Some { txt = Per_axis.min (Modal (Comonadic Areality)); loc };
linearity =
Some { txt = Per_axis.min (Modal (Comonadic Linearity)); loc };
uniqueness =
Some { txt = Per_axis.min (Modal (Monadic Uniqueness)); loc };
portability =
Some { txt = Per_axis.min (Modal (Comonadic Portability)); loc };
contention =
Some { txt = Per_axis.min (Modal (Monadic Contention)); loc };
forkable =
Some { txt = Per_axis.min (Modal (Comonadic Forkable)); loc };
yielding =
Some { txt = Per_axis.min (Modal (Comonadic Yielding)); loc };
externality = Some { txt = Externality.min; loc };
statefulness =
Some { txt = Per_axis.min (Modal (Comonadic Statefulness)); loc };
visibility =
Some { txt = Per_axis.min (Modal (Monadic Visibility)); loc };
staticity = None;
nullability = bounds_so_far.nullability;
separability = bounds_so_far.separability
}
| _ -> raise (Error (loc, Unrecognized_modifier (Modifier, txt))))
in
let raw_modifiers = List.fold_left step Transled_modifiers.empty annots in
let modality =
let open Modality in
let has_explicit axis =
let (P axis) = Crossing.Axis.of_modality (P axis) in
Option.is_some (Transled_modifiers.get ~axis:(Modal axis) raw_modifiers)
in
let add_implied axis value acc =
List.fold_left
(fun acc (Atom (axis', value')) ->
if has_explicit axis' then acc else Const.set axis' value' acc)
acc
(implied_modalities (Atom (axis, value)))
in
let add_comonadic acc axis =
match
Transled_modifiers.get ~axis:(Modal (Comonadic axis)) raw_modifiers
with
| None -> acc
| Some { txt = Modality value; _ } ->
let acc = Const.set (Comonadic axis) value acc in
add_implied (Comonadic axis) value acc
in
let add_monadic acc axis =
match
Transled_modifiers.get ~axis:(Modal (Monadic axis)) raw_modifiers
with
| None -> acc
| Some { txt = Modality value; _ } ->
let acc = Const.set (Monadic axis) value acc in
add_implied (Monadic axis) value acc
in
let add acc = function
| Value.Axis.P (Comonadic axis) -> add_comonadic acc axis
| Value.Axis.P (Monadic axis) -> add_monadic acc axis
in
List.fold_left add Const.id Value.Axis.all
in
enforce_forbidden_modalities Modifier ~loc:bounds_loc modality;
let open Jkind.Mod_bounds in
let externality =
Option.fold ~some:Location.get_txt ~none:Externality.max
raw_modifiers.externality
in
let crossing = Crossing.modality modality Crossing.max in
( create crossing ~externality,
(raw_modifiers.nullability, raw_modifiers.separability) )
let default_mode_annots (annots : Alloc.Const.Option.t) =
let forkable =
match annots.forkable, annots.areality with
| (Some _ as y), _ | y, None -> y
| None, Some Locality.Const.Global -> Some Forkable.Const.Forkable
| None, Some Locality.Const.Local -> Some Forkable.Const.Unforkable
in
let yielding =
match annots.yielding, annots.areality with
| (Some _ as y), _ | y, None -> y
| None, Some Locality.Const.Global -> Some Yielding.Const.Unyielding
| None, Some Locality.Const.Local -> Some Yielding.Const.Yielding
in
let contention =
match annots.contention, annots.visibility with
| (Some _ as c), _ | c, None -> c
| None, Some Visibility.Const.Immutable -> Some Contention.Const.Contended
| None, Some Visibility.Const.Read -> Some Contention.Const.Shared
| None, Some Visibility.Const.Write -> Some Contention.Const.Corrupted
| None, Some Visibility.Const.Read_write ->
Some Contention.Const.Uncontended
in
let portability =
match annots.portability, annots.statefulness with
| (Some _ as p), _ | p, None -> p
| None, Some Statefulness.Const.Stateless -> Some Portability.Const.Portable
| None, Some Statefulness.Const.Reading -> Some Portability.Const.Shareable
| None, Some Statefulness.Const.Writing ->
Some Portability.Const.Corruptible
| None, Some Statefulness.Const.Stateful ->
Some Portability.Const.Nonportable
in
{ annots with forkable; yielding; contention; portability }
let transl_mode_annots annots =
let annots =
List.map
(fun { txt = Parsetree.Mode txt; loc } ->
Language_extension.assert_enabled ~loc Mode Language_extension.Stable;
try { txt = Mode_axis_pair.of_string txt; loc }
with Not_found ->
raise (Error (loc, Unrecognized_modifier (Mode, txt))))
annots
in
let step modes_so_far { txt = (Atom (ax, mode) : Mode_axis_pair.t); loc } =
if Option.is_some (Alloc.Const.Option.proj ax modes_so_far)
then raise (Error (loc, Duplicated_axis (Mode, ax)))
else Alloc.Const.Option.set ax (Some mode) modes_so_far
in
let modes =
List.fold_left step Alloc.Const.Option.none annots |> default_mode_annots
in
{ mode_modes = modes; mode_desc = annots }
let untransl_mode modes =
let untransl_annot =
Location.map (fun (Atom (ax, mode) : Mode.Alloc.atom) : Parsetree.mode ->
Mode (Format_doc.asprintf "%a" (Mode.Alloc.Const.print_axis ax) mode))
in
List.map untransl_annot modes.mode_desc
let mode_annot_to_modality_annot mode_annot =
Location.map
(fun mode : Modality.atom ->
let (Atom (ax, mode)) = Mode_axis_pair.to_value mode in
match[@warning "-18"] ax with
| Comonadic ax -> Atom (Comonadic ax, Meet_const mode)
| Monadic ax -> Atom (Monadic ax, Join_const mode))
mode_annot
let transl_modality ~maturity { txt = Parsetree.Modality modality; loc } =
Language_extension.assert_enabled ~loc Mode maturity;
let mode =
try Mode_axis_pair.(of_string modality)
with Not_found ->
raise (Error (loc, Unrecognized_modifier (Modality, modality)))
in
let mode_annot = { txt = mode; loc } in
mode_annot_to_modality_annot mode_annot
let untransl_modality =
Location.map (fun (Atom (ax, t) : Modality.atom) : Parsetree.modality ->
Modality (Format_doc.asprintf "%a" (Modality.Per_axis.print ax) t))
let[@warning "-18"] mutable_implied_modalities ~for_mutable_variable mut =
let comonadic : Modality.atom list =
[ Atom (Comonadic Areality, Meet_const Regionality.Const.legacy);
Atom (Comonadic Linearity, Meet_const Linearity.Const.legacy);
Atom (Comonadic Forkable, Meet_const Forkable.Const.legacy);
Atom (Comonadic Yielding, Meet_const Yielding.Const.legacy) ]
in
let monadic : Modality.atom list =
[ Atom (Monadic Uniqueness, Join_const Uniqueness.Const.legacy);
Atom (Monadic Contention, Join_const Contention.Const.legacy);
Atom (Monadic Visibility, Join_const Visibility.Const.legacy);
Atom (Monadic Staticity, Join_const Staticity.Const.legacy) ]
in
if mut
then if for_mutable_variable then monadic else monadic @ comonadic
else []
let mutable_implied_modalities ~for_mutable_variable mut =
let l = mutable_implied_modalities ~for_mutable_variable mut in
List.fold_left
(fun t (Modality.Atom (ax, a)) -> Modality.Const.set ax a t)
Modality.Const.id l
let idx_expected_modalities ~(mut : bool) =
let modality_of_list l =
List.fold_left
(fun t (Modality.Atom (ax, a)) -> Modality.Const.set ax a t)
Modality.Const.id l
in
let expected1 = mutable_implied_modalities mut ~for_mutable_variable:false in
let expected2 =
if mut
then
modality_of_list
[ Atom (Comonadic Areality, Meet_const Regionality.Const.legacy);
Atom (Comonadic Linearity, Meet_const Linearity.Const.legacy);
Atom (Comonadic Forkable, Meet_const Forkable.Const.legacy);
Atom (Comonadic Yielding, Meet_const Yielding.Const.legacy);
Atom (Monadic Uniqueness, Join_const Uniqueness.Const.legacy);
Atom (Monadic Staticity, Join_const Staticity.Const.legacy) ]
[@warning "-18"]
else Mode.Modality.Const.id
in
match Mode.Modality.Const.equate expected1 expected2 with
| Ok () -> expected1
| Error _ ->
Misc.fatal_error
"Typemode.idx_expected_modalities: mismatch with mutable implied \
modalities"
let least_modalities ~include_implied ~mut (t : Modality.Const.t) =
let baseline =
mutable_implied_modalities ~for_mutable_variable:false
(Types.is_mutable mut)
in
let annotated = Modality.Const.(diff baseline t) in
let implied = List.concat_map implied_modalities annotated in
let exclude_implied =
List.filter (fun x -> not @@ List.mem x implied) annotated
in
let overridden =
List.filter_map
(fun (Modality.Atom (ax, m_implied)) ->
let m_projected = Modality.Const.proj ax t in
if m_projected <> m_implied || include_implied
then Some (Modality.Atom (ax, m_projected))
else None)
implied
in
exclude_implied @ overridden
let untransl_mod_bounds ?(verbose = false) (bounds : Jkind.Mod_bounds.t) :
Parsetree.modes =
let crossing = Jkind.Mod_bounds.crossing bounds in
let modality = Crossing.to_modality crossing in
let least_modalities =
least_modalities ~include_implied:verbose ~mut:Immutable modality
in
let modality_annots =
List.map
(fun (Atom (ax, m) : Modality.atom) ->
let s = Format_doc.asprintf "%a" (Modality.Per_axis.print ax) m in
{ Location.txt = Parsetree.Mode s; loc = Location.none })
least_modalities
in
let top_modality_annots () =
List.filter_map
(fun ax ->
let (P ax) = Modality.Axis.of_value ax in
let included_in_nonverbose =
List.exists
(fun (Atom (ax2, _) : Modality.atom) ->
Modality.Axis.P ax = Modality.Axis.P ax2)
least_modalities
in
match included_in_nonverbose with
| true -> None
| false ->
let s =
Format_doc.asprintf "%a"
(Modality.Per_axis.print ax)
(Modality.Const.proj ax modality)
in
Some { Location.txt = Parsetree.Mode s; loc = Location.none })
Value.Axis.all
in
let nonmodal_annots, top_nonmodal_annots =
let open Jkind.Mod_bounds in
let mk_annot top print value =
let only_when_verbose = value = top in
let s = Format_doc.asprintf "%a" print value in
( { Location.txt = Parsetree.Mode s; loc = Location.none },
only_when_verbose )
in
[mk_annot Externality.max Externality.print (externality bounds)]
|> List.partition_map (fun (annot, only_when_verbose) ->
match only_when_verbose with false -> Left annot | true -> Right annot)
in
let verbose_annots =
match verbose with
| true -> top_modality_annots () @ top_nonmodal_annots
| false -> []
in
modality_annots @ nonmodal_annots @ verbose_annots
let sort_dedup_modalities ~warn l =
let open Modality in
let compare { txt = Atom (ax0, _); loc = _ } { txt = Atom (ax1, _); loc = _ }
=
let (P ax0) = Axis.to_value (P ax0) in
let (P ax1) = Axis.to_value (P ax1) in
Mode.Value.Axis.compare ax0 ax1
in
let dedup ~on_dup =
let rec loop x = function
| [] -> [x]
| y :: xs ->
if compare x y = 0
then (
on_dup x y;
loop y xs)
else x :: loop y xs
in
function [] -> [] | x :: xs -> loop x xs
in
let on_dup { txt = Atom (ax0, _); loc = loc0 }
{ txt = Atom (ax1, a1); loc = _ } =
if warn
then
let (P ax0) = Axis.to_value (P ax0) in
let axis = Format_doc.asprintf "%a" Mode.Value.Axis.print ax0 in
let overriden_by =
Format_doc.asprintf "%a" (Modality.Per_axis.print ax1) a1
in
Location.prerr_warning loc0
(Warnings.Modal_axis_specified_twice { axis; overriden_by })
in
l |> List.stable_sort compare |> dedup ~on_dup |> List.map (fun x -> x.txt)
let transl_modalities_with_default ~maturity ~default annots =
let modalities_loc =
match List.map (fun { loc; _ } -> loc) annots with
| [] -> Location.none
| _ :: _ as locs -> Location.merge locs
in
let annots = List.map (transl_modality ~maturity) annots in
let modalities = sort_dedup_modalities ~warn:true annots in
let open Modality in
let modalities =
List.fold_left
(fun m (Atom (ax, a) as t) ->
let m = Const.set ax a m in
List.fold_left
(fun m (Atom (ax, a)) -> Const.set ax a m)
m (implied_modalities t))
default modalities
in
enforce_forbidden_modalities Modality ~loc:modalities_loc modalities;
{ moda_modalities = modalities; moda_desc = annots }
let mutable_modalities mut =
mutable_implied_modalities (Types.is_mutable mut) ~for_mutable_variable:false
let transl_modalities ~maturity mut annots =
let default = mutable_modalities mut in
transl_modalities_with_default ~maturity ~default annots
let let_mutable_modalities =
mutable_implied_modalities true ~for_mutable_variable:true
let atomic_mutable_modalities =
mutable_implied_modalities true ~for_mutable_variable:false
let sort_dedup_modalities modalities =
List.map (fun x -> { txt = x; loc = Location.none }) modalities
|> sort_dedup_modalities ~warn:false
let untransl_modalities t = List.map untransl_modality t.moda_desc
let transl_with_bound_modifiers annots =
let modal_annots, externality =
List.fold_left
(fun (modal_annots, externality)
({ txt = Parsetree.Modality modality; loc } as annot) ->
match Modifier_axis_pair.of_string modality with
| P (Modal _, _) -> annot :: modal_annots, externality
| P (Nonmodal Externality, (value : Externality.t)) ->
modal_annots, Some value
| exception Not_found ->
raise (Error (loc, Unrecognized_modifier (Modality, modality))))
([], None) annots
in
let modality =
(transl_modalities ~maturity:Stable Immutable (List.rev modal_annots))
.moda_modalities
in
modality, externality
let transl_alloc_mode annots =
let { mode_modes = opt_modes; mode_desc = annots } =
transl_mode_annots annots
in
let modes = Alloc.Const.Option.value opt_modes ~default:Alloc.Const.legacy in
{ mode_modes = modes; mode_desc = annots }
let report_error ppf =
let open Format_doc in
function
| Duplicated_axis (annot_type, axis) ->
fprintf ppf "The %a axis has already been specified."
(print_annot_axis annot_type)
axis
| Forbidden_modality (annot_type, Global_and_unique) ->
fprintf ppf "The %a %a can't be used together with %a" print_annot_type
annot_type Misc.Style.inline_code "global" Misc.Style.inline_code "unique"
| Unrecognized_modifier (annot_type, modifier) ->
fprintf ppf "Unrecognized %a %s." print_annot_type annot_type modifier
let () =
Location.register_error_of_exn (function
| Error (loc, err) -> Some (Location.error_of_printer ~loc report_error err)
| _ -> None)