Module Subst

Substitutions

Substitutions are used to translate a type from one context to another. This requires substituting paths for identifiers, and possibly also lowering the level of non-generic variables so that they are inferior to the maximum level of the new context.

Substitutions can also be used to create a "clean" copy of a type. Indeed, non-variable node of a type are duplicated, with their levels set to generic level. That way, the resulting type is well-formed (decreasing levels), even if the original one was not.

In the presence of local substitutions for module types, a substitution for a type expression may fail to produce a well-formed type. In order to confine this issue to local substitutions, the type of substitutions is split into a safe and unsafe variant. Only unsafe substitutions may expand a module type path into a generic module type.

type +'k subst

Type familly for substitutions

type safe = [
  1. | `Safe
]
type unsafe = [
  1. | `Unsafe
]
type t = safe subst

Standard substitution

val identity : 'a subst
val unsafe : t -> unsafe subst
val add_type : Ident.t -> Path.t -> 'k subst -> 'k subst
val add_module : Ident.t -> Path.t -> 'k subst -> 'k subst
val add_modtype : Ident.t -> Path.t -> 'k subst -> 'k subst
val for_saving : t -> t
val reset_for_saving : unit -> unit
val change_locs : 'k subst -> Location.t -> 'k subst
val module_path : t -> Path.t -> Path.t
val type_path : t -> Path.t -> Path.t
val modtype_path : t -> Path.t -> Path.t
val type_expr : t -> Types.type_expr -> Types.type_expr
val class_type : t -> Types.class_type -> Types.class_type
val value_description : t -> Types.value_description -> Types.value_description
val type_declaration : t -> Types.type_declaration -> Types.type_declaration
val class_declaration : t -> Types.class_declaration -> Types.class_declaration

When applied to a signature item, a substitution not only modifies the types present in its declaration, but also refreshes the identifier of the item. Effectively this creates new declarations, and so one should decide what the scope of this new declaration should be.

This is decided by the scoping argument passed to the following functions.

type scoping =
  1. | Keep
  2. | Make_local
  3. | Rescope of int
val signature : scoping -> t -> Types.signature -> Types.signature
val signature_item : scoping -> t -> Types.signature_item -> Types.signature_item
val compose : t -> t -> t

Composition of substitutions: apply (compose s1 s2) x = apply s2 (apply s1 x) *

module Unsafe : sig ... end
module Lazy : sig ... end