Skip to content

Commit c3026db

Browse files
committed
improve modality comments
1 parent 39b40ad commit c3026db

File tree

2 files changed

+77
-20
lines changed

2 files changed

+77
-20
lines changed

typing/mode.ml

+71-19
Original file line numberDiff line numberDiff line change
@@ -2597,6 +2597,62 @@ module Modality = struct
25972597
| Atom (ax, Meet_with c) ->
25982598
Format.fprintf ppf "meet_with(%a)" (C.print (Value.proj_obj ax)) c
25992599

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+
26002656
module Monadic = struct
26012657
module Mode = Value.Monadic
26022658

@@ -2655,20 +2711,9 @@ module Modality = struct
26552711
| Join_const c -> Format.fprintf ppf "join_const(%a)" Mode.Const.print c
26562712
end
26572713

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-
26682714
type t =
26692715
| 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 *)
26722717
| Undefined
26732718

26742719
let sub_log left right ~log : (unit, error) Result.t =
@@ -2817,17 +2862,19 @@ module Modality = struct
28172862
type t =
28182863
| Const of Const.t
28192864
| 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 *)
28222866

28232867
let sub_log left right ~log : (unit, error) Result.t =
28242868
match left, right with
28252869
| Const c0, Const c1 -> Const.sub c0 c1
28262870
| 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]. *)
28312878
match Mode.submode_log m (Mode.of_const c) ~log with
28322879
| Ok () -> Ok ()
28332880
| Error (Error (ax, { left; _ })) ->
@@ -2856,7 +2903,12 @@ module Modality = struct
28562903
| Const c -> Const.apply c x |> Mode.disallow_right
28572904
| Undefined ->
28582905
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
28602912

28612913
let print ppf = function
28622914
| Const c -> Const.print ppf c

typing/mode_intf.mli

+6-1
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,12 @@ module type S = sig
630630
(** The undefined modality. *)
631631
val undefined : t
632632

633-
(** Apply a modality on a left mode. *)
633+
(* CR zqian: note that currently, [apply] and [sub] and [zap] are NOT
634+
coherent for comonadic axes. That is, we do NOT have
635+
[apply t m = Const.apply (zap t) m]. This is probably fine. *)
636+
637+
(** Apply a modality on a left mode. The calller should ensure that [apply
638+
t m] is only called for [m >= md_mode] for inferred modalities. *)
634639
val apply : t -> (allowed * 'r) Value.t -> Value.l
635640

636641
(** [sub t0 t1] checks that [t0 <= t1].

0 commit comments

Comments
 (0)