Sarek_schemetype scheme = {quantified : int list;IDs of generalized (forall-bound) type variables
*)body : Sarek_types.typ;The type body with those variables
*)}A type scheme represents a polymorphic type with quantified type variables. For example, the identity function has scheme: forall a. a -> a
val mono : Sarek_types.typ -> schemeCreate a monomorphic scheme (no quantified variables)
val free_tvars : Sarek_types.typ -> int listCollect all free (unbound) type variable IDs in a type
val copy_for_scheme : int -> Sarek_types.typ -> Sarek_types.typ * int listDeep copy a type, creating fresh type variables with NEW ids for those that will be quantified. This ensures the scheme's body is completely independent of unification on the original or instantiated types.
CONSTRAINT PROPAGATION. Sarek_types keeps two registries keyed by tvar ID — "this tvar came from a bare float literal" and "this tvar stood where a numeric type was required, so it may never become float16". Minting a fresh id silently DROPS both, which turns generalization into a hole in the type system: the body of let[@sarek.module] twice (x : 'a) : 'a = x +. x records the original x as numeric-required, but its generalized copy did not, so a call site could unify the fresh variable with a float16 element and get half arithmetic past the guard.
Confirmed by construction: that exact helper applied to a float16 vector load produced NO Sarek diagnostic, while the identical shape at float32 compiled cleanly — i.e. the two differed only in the guard that should have fired and did not. Both registries are therefore carried onto every fresh variable here and in instantiate.
val generalize : int -> Sarek_types.typ -> schemeGeneralize a type at a given level. Type variables at levels greater than the given level are quantified.
val instantiate : scheme -> Sarek_types.typInstantiate a type scheme by replacing quantified variables with fresh ones.
Each fresh variable inherits the quantified variable's ID-keyed constraints (see copy_for_scheme); this is the second half of the propagation, and the one a CALL SITE depends on. Skipping it would let twice a_f16.(tid) unify the instance with float16 even though the helper's body required a numeric type.
val pp_scheme : Stdlib.Format.formatter -> scheme -> unitval scheme_to_string : scheme -> stringval is_mono : scheme -> boolCheck if a scheme is monomorphic (no quantified variables)
val is_poly : scheme -> boolCheck if a scheme is polymorphic (has quantified variables)
val function_arity : scheme -> int optionGet the arity of a function scheme