Skip to content

Add support for 5.4 bivariant type parameters in type declaration#629

Merged
NathanReb merged 11 commits intoocaml-ppx:mainfrom
NathanReb:support-5-4-bivariant-params
Mar 18, 2026
Merged

Add support for 5.4 bivariant type parameters in type declaration#629
NathanReb merged 11 commits intoocaml-ppx:mainfrom
NathanReb:support-5-4-bivariant-params

Conversation

@NathanReb
Copy link
Collaborator

This exhibits how I initially envisioned the encoding of bivariant type parameters, or of any other such AST change that cannot directly be encoded into an extension point.

The idea is that the feature is encoded locally at the parameter tuple level (which is already one level up the variance node), and then wrapped into an extension at the closest level, e.g. here, at the structure_item_desc level.

The reason why we don't simply use the parameter encoding is because it can to easily result in ppx-authors misinterpreting it, e.g. they could operate on the variance, ignoring the core_type in the tuple and therefore completely misinterpreting the AST.
We instead ensure that no one inadvertently traverse an encoded node by wrapping the whole structure_item in an extension.

This may seem overkill but protects us against nasty and hard to trace bugs by preventing tempering with encoded data which can lead to migration failure or worse, silent and invalid rewriting of the AST during migration.

The addition of bivariant type parameters makes for one of the worst possible case for our new encoding approach as it spreads quite far up the tree, especially considering it would have been ignored by most ppx-es. We chose the safe approach here, the tradeoff being that ppx won't be able to support bivariant parameters without updating.

The positive here is that this is such a niche feature that most users will never encounter this feature, let alone have it involved with any kind of ppx rewriting, that the encoding should not cause too much trouble in the wild.

Once again, this is still a net positive over the previous situation since old code will always preprocess and compile without troubles.

@NathanReb
Copy link
Collaborator Author

NathanReb commented Mar 2, 2026

I'm opening a draft PR that only handles bivariant parameters in type declaration, in structures. We still need to add support for them in:

  • type_declaration in signature
  • type_declaration in module_type_desc
  • type_extension
  • class_declaration
  • class_description
  • class_type_declaration

This amounts to writing boilerplate that plugs in the existing encoding/decoding of type parameters and add the right extension point wrapping but is still a significant bit of work for a niche feature.

@NathanReb NathanReb force-pushed the support-5-4-bivariant-params branch from 51fb44d to b60d4ec Compare March 2, 2026 14:30
@NathanReb NathanReb marked this pull request as ready for review March 3, 2026 16:00
Ast_504.Parsetree.Pstr_include (copy_include_declaration x0)
| Ast_503.Parsetree.Pstr_attribute x0 ->
Ast_504.Parsetree.Pstr_attribute (copy_attribute x0)
| Ast_503.Parsetree.Pstr_extension (({ txt; _ }, payload), [])
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Checking that attributes are [] should be moved to the decode function here so that it leads to an error rather than to let an uninterpreted extension slip through.

I'm also conflicted on whether we should go for this case based approach vs having the decode function simply be something like:

val decode_pstr : loc:Location.t -> structure_item_desc -> structure_item_desc option

Any thoughts @patricoferris ?

Copy link
Collaborator

@patricoferris patricoferris left a comment

Choose a reason for hiding this comment

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

This looks good to me @NathanReb.

Whilst I'm not stoked about the use of exceptions for non-exceptional control-flow, I think it is worthwhile given how little the migration code tends to move for older compiler versions.

@NathanReb NathanReb force-pushed the support-5-4-bivariant-params branch from 386a5fe to 97afc38 Compare March 10, 2026 15:03
@NathanReb NathanReb requested a review from patricoferris March 10, 2026 17:42
@NathanReb NathanReb force-pushed the support-5-4-bivariant-params branch from 87d9709 to 017f024 Compare March 11, 2026 09:31
Copy link
Collaborator

@patricoferris patricoferris left a comment

Choose a reason for hiding this comment

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

Thanks @NathanReb -- I much prefer this implementation over the previous exception and reference based version! Happy for this to go in whenever.

Nathan Rebours added 11 commits March 17, 2026 15:17
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
Signed-off-by: Nathan Rebours <nathan.rebours@ocamlpro.com>
@NathanReb NathanReb force-pushed the support-5-4-bivariant-params branch from 017f024 to e1257bc Compare March 17, 2026 14:18
@NathanReb
Copy link
Collaborator Author

I just rebased and will merge once it goes green!

@NathanReb NathanReb merged commit 2a3fb53 into ocaml-ppx:main Mar 18, 2026
6 of 8 checks passed
NathanReb pushed a commit to NathanReb/opam-repository that referenced this pull request Mar 20, 2026
CHANGES:

- Add support for OCaml 5.5 (ocaml-ppx/ppxlib#622, @patricoferris, @NathanReb)

- Add support for OCaml 5.4 bivariant type parameters, they can now be used
  alongside ppx-es. (ocaml-ppx/ppxlib#629, @NathanReb)

- Add `Attribute.Floating.declare_with_attr_loc` and `.declare_with_name_loc`,
  by analogy to the same functions at top level of `Attribute`. (ocaml-ppx/ppxlib#631, @ceastlund)

- Migrate `Ptyp_open` nodes using an extension point (ocaml-ppx/ppxlib#625, @patricoferris)

- Add Ast_builder and Ast_pattern utilities to manipulate encoded
  effect patterns (ocaml-ppx/ppxlib#624, @NathanReb)

- Fix a bug where ppat_effects would be encoded/decoded instead of copied by
  the 5.4 <-> 5.3 migrations (ocaml-ppx/ppxlib#624, @NathanReb)

- Fix infinite loop when duplicate attributes are present, raising
  an error instead (ocaml-ppx/ppxlib#613, @ceastlund, @patricoferris)
- Ignore extensions inside attributes for the unused extension check
  (ocaml-ppx/ppxlib#616, @Skepfyr)
- Fix a bug that inserted `Location.none` into `Longident`s when using OCaml
  5.4 and above (ocaml-ppx/ppxlib#619, @patricoferris)

- Add support for OCaml 5.4 labeled tuples, they can now be used alongside
  ppx-es. Also adds Ast_builder and Ast_pattern utilities to manipulate them.
  (ocaml-ppx/ppxlib#607, @NathanReb)
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