@@ -2597,6 +2597,62 @@ module Modality = struct
2597
2597
| Atom (ax , Meet_with c ) ->
2598
2598
Format. fprintf ppf " meet_with(%a)" (C. print (Value. proj_obj ax)) c
2599
2599
2600
+ (* Inferred modalities
2601
+
2602
+ Similar to constant modalities, an inferred modality maps the mode of a
2603
+ record/structure to the mode of a value therein. An inferred modality [f]
2604
+ is inferred from the structure/record mode [mm] and the value mode [m]. It
2605
+ will only be applied on some [x >= mm]: That is, it will only be applied
2606
+ on the original module.
2607
+
2608
+ It should satisfy the following conditions:
2609
+
2610
+ Zapping: [f] should be of the form [join_c] for monadic axes, or [meet_c]
2611
+ for comonadic axes.
2612
+
2613
+ Soundness: You should not get a value from a record/structure at a mode
2614
+ strictly stronger than how it was put in. That is, for any [x >= mm], [f x
2615
+ >= m].
2616
+
2617
+ Completeness: Ideally we also want [f mm <= m].
2618
+
2619
+ Monadic axes
2620
+
2621
+ Soundness condition says [join_c x >= m] for any [x >= mm]. Equivalently,
2622
+ [join_c mm >= m]. By adjunction, [c >= subtract_mm m]. We take the lower
2623
+ bound [c := subtract_mm m]. Note that this is equivalent to taking [c := m
2624
+ >= subtract_mm m]. Proof:
2625
+
2626
+ - [join_m x >= join_(subtract_mm m) x] is trivial since [m >= subtract_mm
2627
+ m].
2628
+ - [join_m x <= join_(subtract_mm m) x], or equivalently [m <=
2629
+ join_(subtract_mm m) x], or equivalently [subtract_x m <= subtract_mm m],
2630
+ which is trivial since [x >= mm].
2631
+
2632
+ Taking [c := subtract_mm m] is better for zapping since it's lower and
2633
+ thus closer to identity modality. Taking [c := m] is easier for [apply]
2634
+ and [sub].
2635
+
2636
+ Comonadic axes
2637
+
2638
+ Soundness condition says [meet_c x >= m] for any [x >= mm]. Equivalently,
2639
+ [meet_c mm >= m]. By def. of [meet], we have both [c >= m] and [mm >= m].
2640
+ The latter is guaranteed by the user of [infer]. We guarantee the former
2641
+ by taking [c := imply_mm m >= m]. One might worry that this is too relaxed
2642
+ and will be "less complete" than taking [c := m]; however, note that
2643
+ [imply_mm m <= imply_mm m] and thus by adjunction [meet_(imply_mm m) mm <=
2644
+ m], which means the chosen [c] is complete.
2645
+
2646
+ Taking [c := m] is easier for [apply] and [sub]. Taking [c := imply_mm m]
2647
+ is better for zapping since it's higher and thus closer to identity
2648
+ modality. However, note that we DON'T have [meet_m x = meet_(imply_mm m)
2649
+ x], which means [apply/sub] and [zap] might behave in a confusing (albeit
2650
+ sound) manner.
2651
+
2652
+ CR zqian: once we support binary mode solver, we will stick to
2653
+ [c := imply_mm m].
2654
+ *)
2655
+
2600
2656
module Monadic = struct
2601
2657
module Mode = Value. Monadic
2602
2658
@@ -2655,20 +2711,9 @@ module Modality = struct
2655
2711
| Join_const c -> Format. fprintf ppf " join_const(%a)" Mode.Const. print c
2656
2712
end
2657
2713
2658
- (* Similar to constant modalities, an inferred modality maps the mode of a
2659
- record/structure to the mode of a value therein. An inferred modality [f] is
2660
- inferred from the structure/record mode [mm] and the value mode [m].
2661
-
2662
- Soundness: You should not get a value from a record/structure at a mode strictly
2663
- stronger than how it was put in. That is, [f mm >= m].
2664
-
2665
- Completeness: You should be able to get a value from a record/structure at a mode
2666
- not strictly weaker than how it was put in. That is, [f mm <= m]. *)
2667
-
2668
2714
type t =
2669
2715
| Const of Const .t
2670
- | Diff of Mode .lr * Mode .lr
2671
- (* * inferred modality. See [apply] for its behavior. *)
2716
+ | Diff of Mode .lr * Mode .lr (* * See "Inferred modalities" comments *)
2672
2717
| Undefined
2673
2718
2674
2719
let sub_log left right ~log : (unit , error ) Result. t =
@@ -2817,17 +2862,19 @@ module Modality = struct
2817
2862
type t =
2818
2863
| Const of Const .t
2819
2864
| Undefined
2820
- | Exactly of Mode .lr * Mode .lr
2821
- (* * inferred modality. See [apply] for its behavior. *)
2865
+ | Exactly of Mode .lr * Mode .lr (* * See "Inferred modalities" comments *)
2822
2866
2823
2867
let sub_log left right ~log : (unit , error ) Result. t =
2824
2868
match left, right with
2825
2869
| Const c0 , Const c1 -> Const. sub c0 c1
2826
2870
| Exactly (_mm , m ), Const (Meet_const c ) -> (
2827
- (* Check for all x >= mm, m <= meet x c. Equivalent to check [m <= meet
2828
- mm c]. By definition of meet, equivalent to check [m <= mm] and [m <=
2829
- c]. The former is the precondition of [Exactly]. So we only check the
2830
- latter. *)
2871
+ (* Check for all [x >= mm], [meet_(imply_mm m) x <= meet_c x], or
2872
+ equivalently [meet_(imply_mm m) x <= c], or equivalently [meet_(imply_mm
2873
+ m) max <= c], or equivalently [imply_mm m <= c]. We can't check this
2874
+ without binary mode solver.
2875
+
2876
+ So instead we check [meet_m x <= meet_c x] (See "Inferred modalities"
2877
+ comments), which amounts to [m <= c]. *)
2831
2878
match Mode. submode_log m (Mode. of_const c) ~log with
2832
2879
| Ok () -> Ok ()
2833
2880
| Error (Error (ax , { left; _ } )) ->
@@ -2856,7 +2903,12 @@ module Modality = struct
2856
2903
| Const c -> Const. apply c x |> Mode. disallow_right
2857
2904
| Undefined ->
2858
2905
Misc. fatal_error " modality Undefined should not be applied."
2859
- | Exactly (_mm , m ) -> Mode. disallow_right m
2906
+ | Exactly (_mm , m ) ->
2907
+ (* Ideally want to return [meet_(imply_mm m) x], which we can't do
2908
+ without binary mode solver, so instead we return [meet_m x] (See
2909
+ "Inferred modalities" comments), which because of [x >= mm >= m] is
2910
+ equal to [m]. *)
2911
+ Mode. disallow_right m
2860
2912
2861
2913
let print ppf = function
2862
2914
| Const c -> Const. print ppf c
0 commit comments