Skip to content

Support 5.5 with ppx#47

Merged
mlasson merged 8 commits into
LexiFi:masterfrom
brandonzstride:support-5.5
Jun 17, 2026
Merged

Support 5.5 with ppx#47
mlasson merged 8 commits into
LexiFi:masterfrom
brandonzstride:support-5.5

Conversation

@brandonzstride

Copy link
Copy Markdown
Contributor

Summary

This PR adds ppx support for the new language features in OCaml 5.5.

Polymorphic function parameters and modular explicits in OCaml 5.5 both require type annotations, so the eta-expansion done by the ppx is now nontrivial; it must preserve type annotations. With type annotations come optional arguments with default values, which contain expressions that may depend on previous arguments, so previous arguments should not be renamed in order for type annotations to work. Thankfully, as far as I can tell, polymorphic parameters cannot be optional, and there is no syntax for optional or labelled modular explicits. Hence, neither needs to be handled.

The code in this PR does not depend on OCaml 5.5, and it works for previous versions with only one small regression: unpacked module arguments cannot shadow each other, which seems like a silly programming pattern anyways.

(* Since module names are kept during unpacking, shadowing is now an error. *)
let[@landmark] shadow ((module M) : (module S)) ((module M) : (module S)) =
  ()

Reviewing

This PR is implemented in four commits, the first two of which are not actually required for 5.5 support and are just general upgrades. This PR seems best reviewed commit-by-commit.

  1. Add tests corresponding to the examples in Update for ppxlib 0.36.0 compatibility #45
  2. Maximally eta-expand functions so that the timing of a function does not happen until it is fully applied. The previous behavior used a function called max_list that actually returned a minimum list. It seemed like a typo, and this commit fixes it and adds a test.
  3. Keep type annotations for polymorphic parameters. Also keep attributes, which may silence warnings and should be kept on the new value binding (found while instrumenting opam; see testing below) so that the new value binding continues to silence such warnings.
  4. Unpack module arguments so that module-dependent functions can compile.

I comment the code quite extensively because I did not exactly have an easy time figuring out how to eta-expand these two new features. It was simpler than I first expected, but since the details are quite implicit in the parse tree, it felt necessary to explain what's happening.

Testing

I have added tests to cover the features. Since optional arguments seemed to be an edge case, I used Sherlocode (see link below) to look for optional module arguments, and it seems no code will be broken by these updates. opam uses optional first class module arguments frequently, so I instrumented all of opam with --auto (nearly 60_000 lines), and it all compiled without issue.

The tests include some classic modular explicits code, but I did not fully stress test because I don't have a wealth of examples for this new feature.

The tests pass with dune test (and instrumented opam builds) on OCaml 5.5.0~alpha1 with ppxlib release 0.38.0, and also on OCaml 5.4 with ppxlib release 0.37.0.

Optional module arguments in the ecosystem: https://sherlocode.com/?q=%3F%5Cw%5C*%3A%5C((module

@brandonzstride

Copy link
Copy Markdown
Contributor Author

I just learned that there is syntactic support for labelled module-dependent functions from this comment in ocaml/ocaml. The comment suggests that indeed there are no optional modular explicit arguments, only labelled arguments. Hence a few code comments in the present PR were slightly misleading, while the implementation remained correct.

I clarified the comment and added a test that the ppx can instrument labelled modular explicits.

@mlasson

mlasson commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Maximally eta-expand functions so that the timing of a function does not happen until it is fully applied. The previous behavior used a function called max_list that actually returned a minimum list. It seemed like a typo, and this commit fixes it and adds a test.

The typo was in the name, not in the implementation :/.

I think we should not eta-expand function maximally across branches. A branch may perform some computation/effect before returning a function. Fully eta-expanding it would defer that computation until all arguments are supplied, changing the semantics and potentially breaking existing instrumented code.

That's why I undid brandonzstride@6275ff7 in cc6347c.

@mlasson mlasson merged commit fb2b803 into LexiFi:master Jun 17, 2026
@mlasson

mlasson commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Thank you for this PR !

@brandonzstride brandonzstride deleted the support-5.5 branch June 17, 2026 15:57
mlasson added a commit that referenced this pull request Jun 17, 2026
* test polymorphic functions with ppx

* eta expand for max arity in ppx

* annotate polymorphic parameters in ppx during eta expansion

* handle modular explicits in ppx

* test labelled modular explicits

* Undo 6275ff7

* Adds a comment.

---------

Co-authored-by: Marc Lasson <marc.lasson@lexifi.com>
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.

2 participants