Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

odoc sometimes force-inlines includes #1162

Open
dlesbre opened this issue Jul 12, 2024 · 5 comments
Open

odoc sometimes force-inlines includes #1162

dlesbre opened this issue Jul 12, 2024 · 5 comments

Comments

@dlesbre
Copy link

dlesbre commented Jul 12, 2024

I've run into an issue where odoc force inlines my includes in the generated doc. Its quite brittle, so I'm not sure what exactly causes it, but here is a minimal example.

Lets say i have a library Lib with the following files:

  • sigs.ml (no mli needed, but adding it does not seem to change the behavior)
    (** some doc *)
    module type TYPE = sig
      type t
      (** Doc of t*)
    end
    
    (** A supermodule of {!TYPE}, with partial ordering *)
    module type PARTIAL_ORDERED_TYPE = sig
      include TYPE (** @closed *)
    
      val partial_compare : t -> t -> int option
      (** order of t *)
    end
  • A library interface file Lib.ml and Lib.mli, I'll just put the mli here:
    (** This doesn't render correctly *)
    module Err1 : Sigs.PARTIAL_ORDERED_TYPE
    
    open Sigs
    
    (** Neither does this *)
    module Err2 : PARTIAL_ORDERED_TYPE
    
    include module type of Sigs
    
    (** This does though *)
    module Ok : PARTIAL_ORDERED_TYPE

Then for some reason Ok and Err1 / Err2 are rendered very differently. Ok is rendered with the correct signature and the closed include shows up correctly in its documentation, whereas the Errs are rendered as sig ... end and the include has been inlined in their documentation.

Is there any way around this? I would really like to use one of the Err style signature (in the full example, my modules aren't actually defined in the top library file lib.ml, they are in another file modules.ml, in which I would like to just open Sigs, not have to include it, and then include both Sigs and Modules in Lib).

@dlesbre
Copy link
Author

dlesbre commented Jul 12, 2024

Maybe related to #878 or #160

@jonludlam
Copy link
Member

jonludlam commented Jul 16, 2024

You mention "library interface files" Lib.ml and Lib.mli - are you building with dune and is your library by any chance named lib?

If so, try naming the library something different (ie, keep Lib.ml and Lib.mli but name the library foo, so they don't match)

@dlesbre
Copy link
Author

dlesbre commented Jul 16, 2024

Yes precisely, I'm using the same names for the library and file on purpose:

  • It avoids breaking the interface. The library used to be one file, but has growing larger so I've split it in multiple files, but I want it to keep the same interface from the user's perspective
  • It allows hiding some components, which aren't needed by the user but used in multiple library files

I understand why this double interface would cause problems though. I'm declaring a module whose type isn't exported directly, it is only exported through a separate include. Unifying these could prove challenging, but I believe it is a common enough pattern to be worth looking into.

@jonludlam
Copy link
Member

OK, so that explains why you're seeing that behaviour. Odoc will inline includes if doesn't know of a non-hidden path to the module/type being included. In this case there's no link to TYPE that's available so it just inlines it. One way to fix this is to expose the Sigs module - ie, something like:

module Sigs = Sigs

(** This doesn't render correctly *)
module Err1 : Sigs.PARTIAL_ORDERED_TYPE

open Sigs

(** Neither does this *)
module Err2 : PARTIAL_ORDERED_TYPE

include module type of Sigs

(** This does though *)
module Ok : PARTIAL_ORDERED_TYPE

and that should fix all the expansions to be what you're expecting.

dlesbre added a commit to codex-semantics-library/patricia-tree that referenced this issue Jul 17, 2024
dlesbre added a commit to codex-semantics-library/patricia-tree that referenced this issue Jul 18, 2024
@dlesbre
Copy link
Author

dlesbre commented Jul 18, 2024

A solution mentioned by @jonludlam in codex-semantics-library/patricia-tree#10 is to use @canonical tags to point odoc to the instance of the module type it should use:

For the toy example here, just add the tags to the module type in sigs.ml

(** some doc
    @canonical Lib.TYPE *)
module type TYPE = sig
  type t
  (** Doc of t*)
end

(** A supermodule of {!TYPE}, with partial ordering
    @canonical Lib.PARTIAL_ORDERED_TYPE *)
module type PARTIAL_ORDERED_TYPE = sig
  include TYPE (** @closed *)

  val partial_compare : t -> t -> int option
  (** order of t *)
end

And make sure those module types are available in Lib.ml/Lib.mli either by copying them one by one or through an include:

module Err1 : Sigs.PARTIAL_ORDERED_TYPE 
(** This now renders as expected, hurray! *)

open Sigs

module Err2 : PARTIAL_ORDERED_TYPE
(** Same for this one *)

include module type of Sigs
(** including the actual signatures is still required obviously, but @canonical tags allow changing their names *)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants