-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Fix printing of bindings with polymorphic type annotations and attributes #9778
Fix printing of bindings with polymorphic type annotations and attributes #9778
Conversation
This fixes a bug that bit @mobileink recently, where printing the code generated by ppx_deriving.eq and attempting to re-parse it resulted in a parse error. This bug manifested where a let binding has a polymorphic type `'a. _` and an attribute on the bound expression. To reproduce: * create `testfile` with ```ocaml #load_rec "parsing/pprintast.cmo";; #load_rec "parsing/lexer.cmo";; #load_rec "parsing/parser.cmo";; let phrase = {ocaml| let rec equal : 'a. ('a -> 'a -> Ppx_deriving_runtime.bool) -> 'a t -> 'a t -> Ppx_deriving_runtime.bool = (let open! Ppx_deriving_runtime in fun poly_a (_ : unit) (_ : unit) -> true) [@ocaml.warning "-A"] [@@ocaml.warning "-39"] |ocaml};; let parse_roundtrip str = Pprintast.string_of_structure (Parser.implementation Lexer.token (Lexing.from_string str));; let phrase_roundtrip = parse_roundtrip phrase;; parse_roundtrip phrase_roundtrip;; ``` * start the toplevel with `TOPFLAGS="-I parsing -I utils" make runtop` * run `#use "testfile"` On `trunk`, this fails with an error at `parse_roundtrip phrase_roundtrip`, where the parser chokes on the `let (equal : 'a. ...) = ...` construction. With this change, the printer and parser round-trip successfully.
f65dbf6
to
39c4e15
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a quick reading to the code, but couldn't figure out what was being fixed. Could you post the output of Pprintast
"before" and "after" this change for your sample? It would help reviewing the PR.
Also, it may be a good idea adding a regression test with your sample (although the best thing would be to have a systematic test of Pprintast
on a large set of files, but that is orthogonal to the present PR).
Before: let rec (equal :
'a .
('a -> 'a -> Ppx_deriving_runtime.bool) ->
'a t -> 'a t -> Ppx_deriving_runtime.bool)
=
((let open! Ppx_deriving_runtime in
fun poly_a -> fun (_ : unit) -> fun (_ : unit) -> true)
[@ocaml.warning "-A"])[@@ocaml.warning "-39"] After: let rec equal
: 'a .
('a -> 'a -> Ppx_deriving_runtime.bool) ->
'a t -> 'a t -> Ppx_deriving_runtime.bool
=
((let open! Ppx_deriving_runtime in
fun poly_a -> fun (_ : unit) -> fun (_ : unit) -> true)
[@ocaml.warning "-A"])[@@ocaml.warning "-39"] The brackets in the |
Thanks, it is clearer now. Sorry for the naive question, but do you know of a case where the parentheses removed by this patch are actually needed? |
They would be needed if there was an annotation that spans the name and the type signature, e.g. let (x : int) [@hi] = 1 The let (((x : int))[@hi ]) = 1 For bare patterns, I think only |
See also #7200 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The patch LGTM. The only thing missing is to add a test for it. This is easy: just add your sample fragment to the file testsuite/tests/parsetree/source.ml
. The test testsuite/tests/parsetree/test.ml
checks that this file can be re-parsed after being parsed and printed with Pprintast
.
Done, thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (once CI passes).
Merged, thanks! |
This fixes a bug that bit @mobileink recently, where printing the code
generated by ppx_deriving.eq and attempting to re-parse it resulted in a
parse error. This bug manifested where a let binding has a polymorphic
type
'a. _
and an attribute on the bound expression.To reproduce:
testfile
withTOPFLAGS="-I parsing -I utils" make runtop
#use "testfile"
On
trunk
, this fails with an error atparse_roundtrip phrase_roundtrip
, where the parser chokes on thelet (equal : 'a. ...) = ...
construction. With this change, theprinter and parser round-trip successfully.