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

generate better asts for function bindings #2651

Merged
merged 1 commit into from
Feb 17, 2025

Conversation

v-gb
Copy link
Contributor

@v-gb v-gb commented Feb 11, 2025

Currently:

let foo1 : _ = function () -> ()
let foo2 x : _ = function () -> ()

are parsed into these value_bindings:

  (* foo1 *)
  { pvb_args = []
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_cases ...
  }
  (* foo2 *)
  { pvb_args = ["x"]
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_cases ...
  }

I expect instead:

  (* foo1 *)
  { pvb_args = []
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_body (Pexp_function ([], None, Pfunction_cases ...))
  }
  (* foo2 (no changes here) *)
  { pvb_args = ["x"]
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_cases ...
  }

I think the ast for foo1:

  • is confusing
  • creates a needless distinction between let f : _ = function () -> () vs let f : _ = (function () -> ()), unlike, say, 1 + function () -> () vs 1 + (function () -> ()).
  • is essentially an invariant violation. The type of value_bindings in ocamlformat should be understood to be the union of a non-function let-binding + an inline pexp_function node. But the node for foo1 corresponds to the syntax of neither a non-function let-binding (because of body = Pfunction_cases _), nor an inline pexp_function (because pexp_function can't have a type_constraint with an empty list of params).

Currently:

```ocaml
let foo1 : _ = function () -> ()
let foo2 x : _ = function () -> ()
```

are parsed into these value_bindings:

```ocaml
  (* foo1 *)
  { pvb_args = []
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_cases ...
  }
  (* foo2 *)
  { pvb_args = ["x"]
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_cases ...
  }
```

I expect instead:

```ocaml
  (* foo1 *)
  { pvb_args = []
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_body (Pexp_function ([], None, Pfunction_cases ...))
  }
  (* foo2 (no changes here) *)
  { pvb_args = ["x"]
  ; pvb_constraint = Some "_"
  ; pvb_body = Pfunction_cases ...
  }
```

I think the ast for foo1:

- is confusing
- creates a needless distinction between
  `let f : _ = function () -> ()` vs `let f : _ = (function () -> ())`,
  unlike, say, `1 + function () -> ()` vs `1 + (function () -> ())`.
- is essentially an invariant violation. The type of value_bindings
  in ocamlformat should be understood to be the union of a non-function
  let-binding + an inline pexp_function node.
  But the node for foo1 corresponds to the syntax of neither a non-function
  let-binding (because of body = Pfunction_cases _), nor an inline
  pexp_function (because pexp_function can't have a type_constraint with
  an empty list of params).
@v-gb v-gb force-pushed the push-uullkpsupwvx branch from f1c296f to 75ff311 Compare February 11, 2025 13:37
Copy link
Collaborator

@Julow Julow left a comment

Choose a reason for hiding this comment

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

This makes total sense :) This also slightly reduce the diff with OCaml's parser and that's a good thing too.

Thanks!

@Julow Julow merged commit 5cc318b into ocaml-ppx:main Feb 17, 2025
10 checks passed
@v-gb
Copy link
Contributor Author

v-gb commented Feb 17, 2025

Thanks!

@v-gb v-gb deleted the push-uullkpsupwvx branch February 17, 2025 10:48
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