-
Notifications
You must be signed in to change notification settings - Fork 2
Module coercions
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 firsta
to the argument, then pass it to the old functor, then applyb
to the result. -
Tcoerce_primitive
is used for turning anexternal
to aval
(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 atpath
and apply the coercionc
to it".
Given i
, the index of a field in A
, the i
th 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.
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" ]))