Mlsem_types.GTyGradual types.
A gradual type is an interval of static types: a lower bound lb (what is statically guaranteed) and an upper bound ub (what a runtime check might still allow), with lb ≤ ub. A static type is the degenerate interval [t,t], and dyn is the widest one, [empty,any]. Operations are applied pointwise to the bounds, so a computation on gradual types tracks in parallel the pessimistic and the optimistic reading of the program.
val empty : tval any : tval dyn : tThe unknown type, i.e. the interval [empty,any].
val fv : t -> Mlsem_types__.Tvar.MVarSet.tThese lift an operation on Ty.t to gradual types by applying it to both bounds; the operation must be monotonic (anti-monotonic for map'), so that the result is still a well-formed interval.
The op family additionally guards the operation with a domain check. The check is applied to the lower bounds only: this is the optimistic reading required by gradual typing, under which the check always succeeds on dyn (whose lower bound is empty) and the responsibility is deferred to a runtime cast. None is returned when the check fails.
Like map, for an anti-monotonic operation (the bounds are swapped).
These are the definite readings: they hold for every static type in the interval, not merely for some.
val is_empty : t -> boolWhether the whole interval is empty, i.e. whether ub is.
val is_any : t -> boolWhether the whole interval is any, i.e. whether lb is.
Bound-wise inclusion: both lb and ub must be smaller. This is stricter than consistent subtyping, which only requires the intervals to overlap.
val non_gradual : t -> boolWhether the interval is a single static type, i.e. lb and ub are equivalent.
val pp : Stdlib.Format.formatter -> t -> unitval pp' : Mlsem_types__.Tvar.Subst.t -> Stdlib.Format.formatter -> t -> unitpp' s prints the type after applying the substitution s, which is how variables get short display names.
module Builder : sig ... end