Skip to content
Olivier Nicole edited this page Nov 29, 2016 · 2 revisions

If a module A is included in another module B, a module coercion describes how construct A in terms of B.

The module_coercion type is defined in Typedtree:

(* ... *)
and module_coercion =
    Tcoerce_none
  | Tcoerce_structure of (int * module_coercion) list *
                         (Ident.t * int * module_coercion) list
  | Tcoerce_functor of module_coercion * module_coercion
  | Tcoerce_primitive of primitive_coercion
  | Tcoerce_alias of Path.t * module_coercion
  • Tcoerce_none means that all the fields that are present in both A and B have the same positions in A and B, hence B can be used as if it was A.
  • Tcoerce_structure (pos_cc_list, id_pos_list) is a mapping from access paths to elements of A to access paths to elements of B (more details below).
  • Tcoerce_functor (a, b) describes how to construct one functor from another. The new functor should apply the first a to the argument, then pass it to the old functor, then apply b to the result.
  • Tcoerce_primitive is used for turning an external to a val (so in this case the coercion represents how to construct a value definition rather than a module).
  • Tcoerce_alias (path, c) means "fetch the module at path and apply the coercion c to it".

Structure coercions: pos_cc_list

Given i, the index of a field in A, the ith element of pos_cc_list is a pair (i', cc), where i' is the index of the corresponding field in B, and cc the coercion to be applied to it.

For val fields, cc will be Tcoerce_none. But it might be a Tcoerce_structure for sub-modules, Tcoerce_primitive for primitives, and so on.

Structure coercions: id_pos_list

id_pos_list aims at solving a corner case arising when aliases in a module M refer to a submodule of that same module M.

Consider:

module Outer : S
module Mod : sig
 module Inner : S
 module Outer_alias = Outer
 module Inner_alias = Inner
end
module N = (Mod : sig module Outer_alias : S module Inner_alias : S end)

cc_pos_list for the coercion on Mod in the last line will look like:

[ 1, Tcoerce_alias(Outer, Tcoerce_none);
 2, Tcoerce_alias(Inner, Tcoerce_none) ]

Which will result in lambda code looking like:

Lprim(Pmakeblock, [ transl_path "Outer"; transl_path "Inner" ])

Outer is in scope, but transl_path "Inner" won't work. id_pos_list requires to add bindings of all internal modules, so that transl_path produces valid code. (The unused bindings are then removed by Simplif). As a result, the translation looks like:

Llet("Inner", Lprim(Pfield 0,  "Mod"),
 Lprim(Pmakeblock, [ transl_path "Outer"; transl_path "Inner" ]))
Clone this wiki locally