Skip to content

OxCaml: support for parameterized libraries - #1464

Open
art-w wants to merge 11 commits into
ocaml:masterfrom
art-w:oxcaml-param
Open

art-w wants to merge 11 commits into
ocaml:masterfrom
art-w:oxcaml-param

Conversation

@art-w

@art-w art-w commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

This PR integrates OxCaml parameterized libs in Odoc, by adding the missing informations (is that library a description of a parameter? is that library parameterized and by what? does that library implement a parameter?) and fixing the broken references to instantiated parameterized libraries. The later is similar to a functor application, with the difference that arguments are nominal instead of positional: The OxCaml compiler internally uses the syntax Lib[Param:Impl], which we replicate (with individual links on Lib, Param and Impl).

See the cram test or dune's documentation on parameterized libs

Fixes #1390

Alizter added a commit to ocaml/dune that referenced this pull request Aug 25, 2026
The odoc generation was skipping all libraries with an `implements`
field (= assuming virtual modules), which meant that the documentation
of OxCaml parameterized libraries was missing important pages (see
ocaml/odoc#1464)

Everything builds and odoc generates documentation for all the libraries:

$ dune build @doc-private 2>&1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using @doc-private because otherwise dune skips the documentation of libraries with an implements (fixed in the next release of dune by ocaml/dune#16200 )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good hint, maybe worth writing that rationale in the test.

Also, come to think of it, it might be worth adding a constraint on dune versions in the OPAM file in the case of with-test (and maybe if we can filter on the oxcaml compiler, so we don't bump the minimal dune version for tests on OCaml)

@art-w

art-w commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Rebased for OxCaml minus39

@Leonidas-from-XIV Leonidas-from-XIV left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks overall very nice, I only have a few nitpicks.

I am a bit thrown by the spelling of "parameterisation" since I would've used "parametrization". I think it makes sense to adopt the spelling that OxCaml uses, however the docs never seem to mention it so I don't know what their preferred spelling is.


Everything builds and odoc generates documentation for all the libraries:

$ dune build @doc-private 2>&1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good hint, maybe worth writing that rationale in the test.

Also, come to think of it, it might be worth adding a constraint on dune versions in the OPAM file in the case of with-test (and maybe if we can filter on the oxcaml compiler, so we don't bump the minimal dune version for tests on OCaml)

Comment thread test/integration/parameterized.t/run.t Outdated
Comment thread test/integration/parameterized.t/run.t Outdated
Comment thread test/integration/parameterized.t/run.t Outdated
Comment thread src/xref2/link.ml Outdated
Comment thread src/loader/odoc_loader.ml Outdated
Comment thread src/loader/odoc_loader.ml Outdated
Comment thread src/loader/ident_env.ml Outdated
Comment thread src/loader/ident_env.ml
Comment thread src/document/generator.ml Outdated
@jonludlam

Copy link
Copy Markdown
Member

Thanks @art-w ! sorry it's taken me some time to get to this. I think the loader parts look good, and the rendering looks mostly fine (modulo the boolean tacked onto the Page.t).

I'm more hesitant about the resolution parts. I was expecting there to be more changes in tools.ml where we resolve paths, but you're essentially throwing an error there and trying to handle it in link.ml instead. Aside from being in a surprisingly different place, it also means that we don't resolve subpaths, like Lib[Param:Impl].Inner as when we reresolve in link.ml they don't match `ApplyParam. I'd like to see how it looks to handle everything in tools.ml - I've had a very rough attempt here though I'd suggest using that as a suggested direction rather than something to cherry pick.

For the boolean in Page.t, I think it might be better if we get a new kind variant in document/url.ml and then we can just amend make_name_from_path rather than prefixing.

@art-w

art-w commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks everyone for the reviews :) The PR has been rebased for minus39 and I believe most issues have been addressed. I cherry-picked your resolution commit @jonludlam but reverted the resolution of parameters to preserve the names of the interfaces (which would otherwise be replaced by their implementation, an information that is already displayed).

@jonludlam

Copy link
Copy Markdown
Member

I've been mulling this over for a bit, and it occurred to me that we can do a bit more at the type level to make this nicer. First we can give library parameters their own identifier - that way we can drop the is_parameter and we can drop the Url.is_equal.

The second thing is that there are quite a few restrictions on what can appear in the ApplyParam expressions - in particular we can't have submodule, aliases, canonical and the like. We can have nested ApplyParam expressions - e.g. when you've got multiple parameters for a library, or when an argument for the library is itself an applied parameterised library. So we can express this at the type level by saying:

type instance =
    [ `Identifier of Identifier.root_module
    | `ApplyParam of instance * Identifier.library_parameter * instance ]

and then altering our definition of the resolved module type:

type module_ =
     [ `Identifier of Identifier.path_module
...
     | `Apply of module_ * module_ 
-    | `ApplyParam of module_ * module_ * module_
+    | `ApplyParam of instance * Identifier.library_parameter * instance
     | `Alias of module_ * Path.module_
...

This simplifies the handling required in tools.ml a bit.

The unresolved instance is a little different as we don't have an identifier for the parameter at the point we read it in - so I've turned that into a very basic ModuleName.t.

I've pushed a branch with the changes: https://github.com/jonludlam/odoc/tree/oxcaml-param-ident - @art-w please take a look and see if they look sensible. I've also added in a test driving the compiler manually rather than with dune.

jonludlam and others added 3 commits October 5, 2026 18:53
Build the libraries with the compiler directly, to cover an instance as
an argument, a parameter passed through implicitly, and hidden units
named in an instance. FIXME: a hidden argument links to an expansion
that isn't generated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A parameter was a `Root plus an is_parameter flag, and only its own page
got the `LibraryParameter URL kind: links to it still had `Module, hence
Url.Path.equal. Add a `LibraryParameter identifier, like `Parameter for
functor parameters, and drop both.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The library, parameter and argument of Lib[P:A] are always compilation
units, but were resolved as arbitrary paths and picked up Hidden and
Canonical: Hlib__x[P:A] rendered as Hlib.X[P:A], and a hidden argument
broke links. Give instances their own type, of names when unresolved
and identifiers when resolved, so Cpath refers to them as `Gpath and
substitution leaves them alone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
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

Successfully merging this pull request may close these issues.

Add support for representing parameterized libraries

3 participants