this repo has no description

Paths#

There are various type declarations for values that allow us to specify items within an OCaml signature. These are Identifiers, Paths, Fragments and References.

Preamble for the following examples:

(* Prelude *)
#require "odoc.xref_test";;
open Odoc_xref2;;
open Odoc_xref_test;;
#install_printer Common.root_pp;;
#install_printer Odoc_model.Names.ValueName.fmt;;
#install_printer Odoc_model.Names.ModuleName.fmt;;
#install_printer Odoc_model.Names.ModuleTypeName.fmt;;
#install_printer Odoc_model.Names.TypeName.fmt;;
#install_printer Odoc_model.Names.PageName.fmt;;
let id = Common.id;;
let mod_sig =
    let open Common.LangUtils.Lens in
    Module.type_ |-~ Module.decl_moduletype |-~ ModuleType.expr_signature
let functor_sig =
    let open Common.LangUtils.Lens in
    Module.type_ |-~ Module.decl_moduletype |-~ ModuleType.expr_functor |-- snd |-~ ModuleType.expr_signature
let functor_arg_sig =
    let open Common.LangUtils.Lens in
    Module.type_ |-~ Module.decl_moduletype |-~ ModuleType.expr_functor |-- fst |-~ FunctorParameter.named |-- FunctorParameter.expr |-~ ModuleType.expr_signature

Identifiers#

Identifiers are the most basic way to describe a specific element in a signature. The type is split into specific subtypes for specific types of elements, and there is a union type to which all identifiers can be cast. For example, we have the type Identifier.type_ for a type declaration. This is:

type type_ = [
    | `Type of signature * TypeName.t
    | `CoreType of TypeName.t
]

so we either have named type declarations that are associated with a particular signature, or core types that aren't (e.g. int). The signature type is anything that can contain elements such as these type declarations:

type signature = [
    | `Root of Root.t * UnitName.t
    | `Module of signature * ModuleName.t
    | `Parameter of signature * ModuleName.t
    | `Result of signature
    | `ModuleType of signature * ModuleTypeName.t
]

A Root refers to a compilation unit (think 'mli' file) - these can clearly contain type declarations. The `Module and `ModuleType constructors are fairly obvious - these also have a parent signature and are named. The `Parameter constructor refers to the parameter of a functor, and the `Result constructor is used to refer to the definitions of the result of the functor. As an example:

let test_data = {|
module type S = sig
    type t
end
module M : sig
    type m_t = int
end
module F(X : sig type foo end) : sig
    open X
    type f_t = foo
end
|};;
let sg = Common.signature_of_mli_string test_data;;

Here we have:

  • S: `ModuleType (`Root root, "S");
# Common.LangUtils.Lens.(get (Signature.module_type "S" |-- ModuleType.id) sg);;
- : Odoc_model.Paths.Identifier.ModuleType.t =
{Odoc_model__Paths_types.iv =
  `ModuleType
    ({Odoc_model__Paths_types.iv =
       `Root
         (Some
           {Odoc_model__Paths_types.iv = `Page (None, None);
            ihash = 236059787; ikey = "p_None"},
          Root);
      ihash = 818126955; ikey = "r_Root.p_None"},
     S);
 ihash = 527535255; ikey = "mt_S.r_Root.p_None"}
  • M: `Module (`Root root, "M")
# Common.LangUtils.Lens.(get (Signature.module_ "M" |-- Module.id) sg);;
- : Odoc_model.Paths.Identifier.Module.t =
{Odoc_model__Paths_types.iv =
  `Module
    ({Odoc_model__Paths_types.iv =
       `Root
         (Some
           {Odoc_model__Paths_types.iv = `Page (None, None);
            ihash = 236059787; ikey = "p_None"},
          Root);
      ihash = 818126955; ikey = "r_Root.p_None"},
     M);
 ihash = 716453475; ikey = "m_M.r_Root.p_None"}
  • F: `Module (`Root root, "F")
# Common.LangUtils.Lens.(get (Signature.module_ "F" |-- Module.id) sg);;
- : Odoc_model.Paths.Identifier.Module.t =
{Odoc_model__Paths_types.iv =
  `Module
    ({Odoc_model__Paths_types.iv =
       `Root
         (Some
           {Odoc_model__Paths_types.iv = `Page (None, None);
            ihash = 236059787; ikey = "p_None"},
          Root);
      ihash = 818126955; ikey = "r_Root.p_None"},
     F);
 ihash = 748202139; ikey = "m_F.r_Root.p_None"}
  • m_t: `Type ( `Module ( `Root root, "M"), "m_t" )
# Common.LangUtils.Lens.(get (Signature.module_ "M" |-- mod_sig |-- Signature.type_ "m_t" |-- TypeDecl.id) sg);;
- : Odoc_model.Paths.Identifier.Type.t =
{Odoc_model__Paths_types.iv =
  `Type
    ({Odoc_model__Paths_types.iv =
       `Module
         ({Odoc_model__Paths_types.iv =
            `Root
              (Some
                {Odoc_model__Paths_types.iv = `Page (None, None);
                 ihash = 236059787; ikey = "p_None"},
               Root);
           ihash = 818126955; ikey = "r_Root.p_None"},
          M);
      ihash = 716453475; ikey = "m_M.r_Root.p_None"},
     m_t);
 ihash = 493774927; ikey = "t_m_t.m_M.r_Root.p_None"}
  • f_t: `Type (`Result (`Module (`Root root, "F")), "f_t")
# Common.LangUtils.Lens.(get (Signature.module_ "F" |-- functor_sig |-- Signature.type_ "f_t" |-- TypeDecl.id) sg);;
- : Odoc_model.Paths.Identifier.Type.t =
{Odoc_model__Paths_types.iv =
  `Type
    ({Odoc_model__Paths_types.iv =
       `Result
         {Odoc_model__Paths_types.iv =
           `Module
             ({Odoc_model__Paths_types.iv =
                `Root
                  (Some
                    {Odoc_model__Paths_types.iv = `Page (None, None);
                     ihash = 236059787; ikey = "p_None"},
                   Root);
               ihash = 818126955; ikey = "r_Root.p_None"},
              F);
          ihash = 748202139; ikey = "m_F.r_Root.p_None"};
      ihash = 709672416; ikey = "___result__.m_F.r_Root.p_None"},
     f_t);
 ihash = 344808614; ikey = "t_f_t.___result__.m_F.r_Root.p_None"}
  • foo: `Type (`Parameter (`Module (`Root root, "F"), "X"), "foo")
# Common.LangUtils.Lens.(get (Signature.module_ "F" |-- functor_arg_sig |-- Signature.type_ "foo" |-- TypeDecl.id) sg);;
- : Odoc_model.Paths.Identifier.Type.t =
{Odoc_model__Paths_types.iv =
  `Type
    ({Odoc_model__Paths_types.iv =
       `Parameter
         ({Odoc_model__Paths_types.iv =
            `Module
              ({Odoc_model__Paths_types.iv =
                 `Root
                   (Some
                     {Odoc_model__Paths_types.iv = `Page (None, None);
                      ihash = 236059787; ikey = "p_None"},
                    Root);
                ihash = 818126955; ikey = "r_Root.p_None"},
               F);
           ihash = 748202139; ikey = "m_F.r_Root.p_None"},
          X);
      ihash = 930266402; ikey = "p_X.m_F.r_Root.p_None"},
     foo);
 ihash = 212207131; ikey = "t_foo.p_X.m_F.r_Root.p_None"}

There are many other types of Identifier: type, constructor, field, etc.

Paths#

A Path is a 'user visible' description of an identifier. Whenever a 'dot' is typed this is usually a path. Initially the compiler will specify exactly only the first element of the path, and the subsequent components of the path will just be strings. For example,

let example = {|
module M : sig
    module N : sig
        type t
        type x1 = t
    end
    type x2 = N.t
end
type x3 = M.N.t
|}
let sg = Common.signature_of_mli_string example;;

All three types x1, x2 and x3 are pointing at M.N.t. Here we define a lens to extract the manifest of a type:

let type_constr_path name =
  let open Common.LangUtils.Lens in
  Signature.type_ name |-- TypeDecl.equation |-- TypeDecl.Equation.manifest |-~ option |-~ TypeExpr.constr |-- fst

and now we can get the paths for all three type declarations:

# Common.LangUtils.Lens.(get (Signature.module_ "M" |-- mod_sig |-- Signature.module_ "N" |-- mod_sig |-- type_constr_path "x1") sg);;
- : Odoc_model.Paths.Path.Type.t =
`Identifier
  ({Odoc_model__Paths_types.iv =
     `Type
       ({Odoc_model__Paths_types.iv =
          `Module
            ({Odoc_model__Paths_types.iv =
               `Module
                 ({Odoc_model__Paths_types.iv =
                    `Root
                      (Some
                        {Odoc_model__Paths_types.iv = `Page (None, None);
                         ihash = 236059787; ikey = "p_None"},
                       Root);
                   ihash = 818126955; ikey = "r_Root.p_None"},
                  M);
              ihash = 716453475; ikey = "m_M.r_Root.p_None"},
             N);
         ihash = 1041581453; ikey = "m_N.m_M.r_Root.p_None"},
        t);
    ihash = 311238448; ikey = "t_t.m_N.m_M.r_Root.p_None"},
   false)
# Common.LangUtils.Lens.(get (Signature.module_ "M" |-- mod_sig |-- type_constr_path "x2") sg);;
- : Odoc_model.Paths.Path.Type.t =
`DotT
  (`Identifier
     ({Odoc_model__Paths_types.iv =
        `Module
          ({Odoc_model__Paths_types.iv =
             `Module
               ({Odoc_model__Paths_types.iv =
                  `Root
                    (Some
                      {Odoc_model__Paths_types.iv = `Page (None, None);
                       ihash = 236059787; ikey = "p_None"},
                     Root);
                 ihash = 818126955; ikey = "r_Root.p_None"},
                M);
            ihash = 716453475; ikey = "m_M.r_Root.p_None"},
           N);
       ihash = 1041581453; ikey = "m_N.m_M.r_Root.p_None"},
      false),
   t)
# Common.LangUtils.Lens.(get (type_constr_path "x3") sg);;
- : Odoc_model.Paths.Path.Type.t =
`DotT
  (`Dot
     (`Identifier
        ({Odoc_model__Paths_types.iv =
           `Module
             ({Odoc_model__Paths_types.iv =
                `Root
                  (Some
                    {Odoc_model__Paths_types.iv = `Page (None, None);
                     ihash = 236059787; ikey = "p_None"},
                   Root);
               ihash = 818126955; ikey = "r_Root.p_None"},
              M);
          ihash = 716453475; ikey = "m_M.r_Root.p_None"},
         false),
      N),
   t)

We can resolve the paths:

let sg' = Common.compile_signature sg;;

and now the paths are:

# Common.LangUtils.Lens.(get (Signature.module_ "M" |-- mod_sig |-- Signature.module_ "N" |-- mod_sig |-- type_constr_path "x1") sg');;
- : Odoc_model.Paths.Path.Type.t =
`Resolved
  (`Identifier
     {Odoc_model__Paths_types.iv =
       `Type
         ({Odoc_model__Paths_types.iv =
            `Module
              ({Odoc_model__Paths_types.iv =
                 `Module
                   ({Odoc_model__Paths_types.iv =
                      `Root
                        (Some
                          {Odoc_model__Paths_types.iv = `Page (None, None);
                           ihash = 236059787; ikey = "p_None"},
                         Root);
                     ihash = 818126955; ikey = "r_Root.p_None"},
                    M);
                ihash = 716453475; ikey = "m_M.r_Root.p_None"},
               N);
           ihash = 1041581453; ikey = "m_N.m_M.r_Root.p_None"},
          t);
      ihash = 311238448; ikey = "t_t.m_N.m_M.r_Root.p_None"})
# Common.LangUtils.Lens.(get (Signature.module_ "M" |-- mod_sig |-- type_constr_path "x2") sg');;
- : Odoc_model.Paths.Path.Type.t =
`Resolved
  (`Type
     (`Identifier
        {Odoc_model__Paths_types.iv =
          `Module
            ({Odoc_model__Paths_types.iv =
               `Module
                 ({Odoc_model__Paths_types.iv =
                    `Root
                      (Some
                        {Odoc_model__Paths_types.iv = `Page (None, None);
                         ihash = 236059787; ikey = "p_None"},
                       Root);
                   ihash = 818126955; ikey = "r_Root.p_None"},
                  M);
              ihash = 716453475; ikey = "m_M.r_Root.p_None"},
             N);
         ihash = 1041581453; ikey = "m_N.m_M.r_Root.p_None"},
      t))
# Common.LangUtils.Lens.(get (type_constr_path "x3") sg');;
- : Odoc_model.Paths.Path.Type.t =
`Resolved
  (`Type
     (`Module
        (`Identifier
           {Odoc_model__Paths_types.iv =
             `Module
               ({Odoc_model__Paths_types.iv =
                  `Root
                    (Some
                      {Odoc_model__Paths_types.iv = `Page (None, None);
                       ihash = 236059787; ikey = "p_None"},
                     Root);
                 ihash = 818126955; ikey = "r_Root.p_None"},
                M);
            ihash = 716453475; ikey = "m_M.r_Root.p_None"},
         N),
      t))

So the difference in the paths is essentially at what point we switch to the identifier.

We also encode other information into the path during the resolution process. This takes the form of additional constructors embedded into the path. These are:

Subst#

The `Subst construct is declared as:

| `Subst of module_type * module_

and is used in a quite specific place - when a functor argument contains a module type declaration, and the functor body contains a module that is contrained by that signature. For example:

let example = {|
module type ARG = sig
  module type S
end

module F : functor (X : ARG) -> sig
  module N : X.S 
end

module M : sig
  module type S = sig
    type t
  end
end

type t = F(M).N.t
|};;
# let sg = Common.compile_signature (Common.signature_of_mli_string example) ;;
val sg : Odoc_model.Lang.Signature.t =
  {Odoc_model.Lang.Signature.items =
    [Odoc_model.Lang.Signature.ModuleType
      {Odoc_model.Lang.ModuleType.id =
        {Odoc_model__Paths_types.iv =
          `ModuleType
            ({Odoc_model__Paths_types.iv =
               `Root
                 (Some
                   {Odoc_model__Paths_types.iv = `Page (None, None);
                    ihash = 236059787; ikey = "p_None"},
                  Root);
              ihash = 818126955; ikey = "r_Root.p_None"},
             ARG);
         ihash = 379411454; ikey = "mt_ARG.r_Root.p_None"};
       source_loc = None;
       doc = {Odoc_model__.Comment.elements = []; warnings_tag = None};
       canonical = None;
       expr =
        Some
         (Odoc_model.Lang.ModuleType.Signature
           {Odoc_model.Lang.Signature.items =
             [Odoc_model.Lang.Signature.ModuleType
               {Odoc_model.Lang.ModuleType.id =
                 {Odoc_model__Paths_types.iv =
                   `ModuleType
                     ({Odoc_model__Paths_types.iv =
                        `ModuleType
                          ({Odoc_model__Paths_types.iv =
                             `Root
                               (Some
                                 {Odoc_model__Paths_types.iv =
                                   `Page (None, None);
                                  ihash = 236059787; ikey = "p_None"},
                                Root);
                            ihash = 818126955; ikey = "r_Root.p_None"},
                           ARG);
                       ihash = 379411454; ikey = "mt_ARG.r_Root.p_None"},
                      S);
                  ihash = 208722936; ikey = "mt_S.mt_ARG.r_Root.p_None"};
                source_loc = None;
                doc =
                 {Odoc_model__.Comment.elements = []; warnings_tag = None};
                canonical = None; expr = None}];
            compiled = true; removed = [];
            doc = {Odoc_model__.Comment.elements = []; warnings_tag = None}})};
     Odoc_model.Lang.Signature.Module (Odoc_model.Lang.Signature.Ordinary,
      {Odoc_model.Lang.Module.id =
        {Odoc_model__Paths_types.iv =
          `Module
            ({Odoc_model__Paths_types.iv =
               `Root
                 (Some
                   {Odoc_model__Paths_types.iv = `Page (None, None);
                    ihash = 236059787; ikey = "p_None"},
                  Root);
              ihash = 818126955; ikey = "r_Root.p_None"},
             F);
         ihash = 748202139; ikey = "m_F.r_Root.p_None"};
       source_loc = None;
       doc = {Odoc_model__.Comment.elements = []; warnings_tag = None};
       type_ =
        Odoc_model.Lang.Module.ModuleType
         (Odoc_model.Lang.ModuleType.Functor
           (Odoc_model.Lang.FunctorParameter.Named
             {Odoc_model.Lang.FunctorParameter.id =
               {Odoc_model__Paths_types.iv =
                 `Parameter
                   ({Odoc_model__Paths_types.iv =
                      `Module
                        ({Odoc_model__Paths_types.iv =
                           `Root
                             (Some
                               {Odoc_model__Paths_types.iv =
                                 `Page (None, None);
                                ihash = 236059787; ikey = "p_None"},
                              Root);
                          ihash = 818126955; ikey = "r_Root.p_None"},
                         F);
                     ihash = 748202139; ikey = "m_F.r_Root.p_None"},
                    X);
                ihash = 930266402; ikey = "p_X.m_F.r_Root.p_None"};
              expr =
               Odoc_model.Lang.ModuleType.Path
                {Odoc_model.Lang.ModuleType.p_expansion =
                  Some
                   (Odoc_model.Lang.ModuleType.Signature
                     {Odoc_model.Lang.Signature.items =
                       [Odoc_model.Lang.Signature.ModuleType
                         {Odoc_model.Lang.ModuleType.id =
                           {Odoc_model__Paths_types.iv =
                             `ModuleType
                               ({Odoc_model__Paths_types.iv =
                                  `Parameter
                                    ({Odoc_model__Paths_types.iv =
                                       `Module
                                         ({Odoc_model__Paths_types.iv =
                                            `Root
                                              (Some
                                                {Odoc_model__Paths_types.iv =
                                                  `Page (None, None);
                                                 ihash = 236059787;
                                                 ikey = "p_None"},
                                               Root);
                                           ihash = 818126955;
                                           ikey = "r_Root.p_None"},
                                          F);
                                      ihash = 748202139;
                                      ikey = "m_F.r_Root.p_None"},
                                     X);
                                 ihash = 930266402;
                                 ikey = "p_X.m_F.r_Root.p_None"},
                                S);
                            ihash = 313393860;
                            ikey = "mt_S.p_X.m_F.r_Root.p_None"};
                          source_loc = None;
                          doc =
                           {Odoc_model__.Comment.elements = [];
                            warnings_tag = None};
                          canonical = None; expr = None}];
                      compiled = true; removed = [];
                      doc =
                       {Odoc_model__.Comment.elements = [];
                        warnings_tag = None}});
                 p_path =
                  `Resolved
                    (`Identifier
                       {Odoc_model__Paths_types.iv =
                         `ModuleType
                           ({Odoc_model__Paths_types.iv =
                              `Root
                                (Some
                                  {Odoc_model__Paths_types.iv =
                                    `Page (None, None);
                                   ihash = 236059787; ikey = "p_None"},
                                 Root);
                             ihash = 818126955; ikey = "r_Root.p_None"},
                            ARG);
                        ihash = 379411454; ikey = "mt_ARG.r_Root.p_None"})}},
           Odoc_model.Lang.ModuleType.Signature
            {Odoc_model.Lang.Signature.items =
              [Odoc_model.Lang.Signature.Module
                (Odoc_model.Lang.Signature.Ordinary,
                {Odoc_model.Lang.Module.id =
                  {Odoc_model__Paths_types.iv =
                    `Module
                      ({Odoc_model__Paths_types.iv =
                         `Result
                           {Odoc_model__Paths_types.iv =
                             `Module
                               ({Odoc_model__Paths_types.iv =
                                  `Root
                                    (Some
                                      {Odoc_model__Paths_types.iv =
                                        `Page (None, None);
                                       ihash = 236059787; ikey = "p_None"},
                                     Root);
                                 ihash = 818126955;
                                 ikey =
                                  "r_Root.p"... (* string length 13; truncated *)},
                                F);
                            ihash = 748202139;
                            ikey =
                             "m_F.r_Ro"... (* string length 17; truncated *)};
                        ihash = 709672416;
                        ikey =
                         "___resul"... (* string length 29; truncated *)},
                       N);
                   ihash = ...; ikey = ...};
                 source_loc = ...; doc = ...; type_ = ...; canonical = ...;
                 hidden = ...});
               ...];
             compiled = ...; removed = ...; doc = ...}));
       canonical = ...; hidden = ...});
     ...];
   compiled = ...; removed = ...; doc = ...}

The problem here is that odoc will not generate a page for the module F(M). Normally links into the body of the functor would simply link to the declaration of the functor itself, but in this case there is no type N.t there. What we have to do instead is link to the signature that contains the type - in this case M.S. Since we necessarily need to have located the definition of t during the resolution process we embed it into the returned resolved path as this `Subst constructor:

# Common.LangUtils.Lens.(get (type_constr_path "t") sg) ;;
- : Odoc_model.Paths.Path.Type.t =
`Resolved
  (`Type
     (`Subst
        (`ModuleType
           (`Substituted
              (`Identifier
                 {Odoc_model__Paths_types.iv =
                   `Module
                     ({Odoc_model__Paths_types.iv =
                        `Root
                          (Some
                            {Odoc_model__Paths_types.iv = `Page (None, None);
                             ihash = 236059787; ikey = "p_None"},
                           Root);
                       ihash = 818126955; ikey = "r_Root.p_None"},
                      M);
                  ihash = 716453475; ikey = "m_M.r_Root.p_None"}),
            S),
         `Module
           (`Apply
              (`Identifier
                 {Odoc_model__Paths_types.iv =
                   `Module
                     ({Odoc_model__Paths_types.iv =
                        `Root
                          (Some
                            {Odoc_model__Paths_types.iv = `Page (None, None);
                             ihash = 236059787; ikey = "p_None"},
                           Root);
                       ihash = 818126955; ikey = "r_Root.p_None"},
                      F);
                  ihash = 748202139; ikey = "m_F.r_Root.p_None"},
               `Identifier
                 {Odoc_model__Paths_types.iv =
                   `Module
                     ({Odoc_model__Paths_types.iv =
                        `Root
                          (Some
                            {Odoc_model__Paths_types.iv = `Page (None, None);
                             ihash = 236059787; ikey = "p_None"},
                           Root);
                       ihash = 818126955; ikey = "r_Root.p_None"},
                      M);
                  ihash = 716453475; ikey = "m_M.r_Root.p_None"}),
            N)),
      t))

This way we can render the path as F(M).N.t but actually link to M.S.t in the html.

SubstAlias#