Skip to content

parser: partially align use of loc_ghost with what the documentation says - #13854

Merged
Octachron merged 4 commits into
ocaml:trunkfrom
v-gb:loc_ghost
Apr 18, 2025
Merged

Octachron merged 4 commits into
ocaml:trunkfrom
v-gb:loc_ghost

Conversation

@v-gb

@v-gb v-gb commented Mar 6, 2025 •

Copy link
Copy Markdown
Contributor

loc.loc_ghost is supposed to false iff the ast described by loc is present at that location. The parser doesn't follow this condition consistently, which can result in unpredictable results in ocamlformat, where loc_ghost is sometimes consulted.

I fixed cases created by the rules forkeyword%extension kind of syntax, as these seems like the main offenders I've seen in ocamlformat.

But there are more failures found by the check. Some may be harmless (+foo creates a ~+ node whose location refers to +), some look weirder (empty non-ghost location with object[@foo] in some case).

In the changed test, the parser change should imply that a Pext_extension and its child swap their ghost boolean. But in some cases, the diff shows only ghost locations being added, which confused me. The reason is that new%foo x has a top node with a ghost location, while (new%foo x) creates the same top node with a non-ghost location.

@gasche

gasche commented Mar 6, 2025

Copy link
Copy Markdown
Member

This discussion would be easier to follow if you could repeat (in your PR message or here) what the documentation says about ghost nodes -- it is documented in a somewhere obscure place (introduced in b062620) and I suspect most people are unfamiliar with this proposed specification.

@v-gb

v-gb commented Mar 6, 2025

Copy link
Copy Markdown
Contributor Author

This discussion would be easier to follow if you could repeat (in your PR message or here) what the documentation says about ghost nodes -- it is documented in a somewhere obscure place (introduced in b062620) and I suspect most people are unfamiliar with this proposed specification.

I adjusted the pr description.

@v-gb
v-gb force-pushed the loc_ghost branch 4 times, most recently from fce7e0a to bfb73a1 Compare March 6, 2025 13:28
@damiendoligez damiendoligez self-assigned this Mar 19, 2025
@Octachron Octachron added the parsetree-change Track changes to the parsetree for that affects ppxs label Apr 4, 2025
Comment thread driver/pparse.ml Outdated
lexbuf

let check_loc_ghost (type a) (kind : a ast_kind) (ast : a) ~inputfile =
if Option.is_some (Sys.getenv_opt "OCAML_LOC_GHOST_CHECK") then

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.

Having this check enabled on an environment variable does not sound optimal to me.
Moreover, my impression is that this check is mostly useful for the compiler, ocamlformat and ppxlib developers,
rather than most users.
Thus I think it might be better to just expose this check in the pparse API and let the compiler testsuite use it directly.

@v-gb v-gb Apr 4, 2025 •

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.

The variable is definitely not intended to be user facing.

My thinking has been that the whole test suite should run with this, at least if the perf impact is negligible. This way, any parser change that's tested somewhere would have its ghostness checked (whereas a test dedicated to this invariant would have limited coverage, because no one would update it when updating the parser).

But this invariant doesn't hold in a number of places, so I can't really do that. So instead this is partial progress: we now have an executable specification of the invariant, but it is used only manually via the env var. With more work (which I don't currently plan to do, but may if the need arises), it could be turned on in some test, e.g. testsuite/tests/parsing, as that seems to have a good coverage of syntax.

I don't really know what I would do with a ?check_ghost_locs:bool argument in the api of pparse.

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.

Maybe we could have a -dparsetree-ghost-locs-invariants (or maybe -dparsetree-invariants-ghost-locs) command-line flag on compiler invocation? We already have -dcmm-invariants and -dflambda-invariants in ocamlopt.

(A cynical way to say this would be: so far we have been careful in trying not to read random environment variables, and we would want to keep some discipline there. On the other hand the command-line options are already a dumpster fire, so we could add one more user-irrelevant thing in this flat namespace.)

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.

We could also also have a Clflags variable (ast_linter?) without a CLI flag. Typically, the test for the AST pretty printer is already using compiler-libs, and it could easily set this new flag.

@v-gb v-gb Apr 4, 2025 •

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.

I replaced the env var by -dparsetree-ghost-loc-invariants, and added that flag to a test that exercises a lot of the syntax I'm touching. There are still two invariants failures in there (down from a screenful, as you can see in the first commit), but we can just promote the invariant failure, no need to fix absolutely everything first.

Comment thread parsing/ast_invariants.ml
; typ =
limit_quadratic_complexity (fun s -> s.typ)
(fun v -> check (fun s -> s.typ) Parse.core_type v v.ptyp_loc )
}

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.

Naive question: do you only check expressions, type expressions, and patterns because they are the most relevant or because other constructs produce less (or no) ghost locations?

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.

I can't say I remember my decision making, but I presumably only tested the syntactic categories I was modifying. But yes, I expect most problems (in frequency) to be in these categories.
In principle, we could test more, but it doesn't seem helpful to do that without also spending time fixing the resulting errors, otherwise I think the main effect would be more errors to sift through.

@v-gb
v-gb force-pushed the loc_ghost branch 8 times, most recently from f0d955e to e069e59 Compare April 6, 2025 14:25
Comment thread parsing/parser.mly Outdated
Comment thread parsing/ast_invariants.ml
(fun v ->
check
(* ~print:(fun f ty -> Printast.payload 0 f (PTyp ty)) *)
(fun s -> s.typ) Parse.core_type v v.ptyp_loc )

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.

Note for later: the more generic parsing function would be poly_type rather than core_type.

Comment thread parsing/ast_invariants.ml Outdated

@Octachron Octachron 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.

The changes make the syntax keyword%ext follows the specification for ghost locations, and the test looks useful. Thus the PR looks ready to merge once:

  • the menhir bootstrap are localized to a single commit
  • the last debugging line is removed

@v-gb

v-gb commented Apr 17, 2025

Copy link
Copy Markdown
Contributor Author

Thanks!
I addressed the various things you mentioned. I squashed some of the existing commits, without really changing them (just removed the debugging line, and maybe some other minor thing like that), and I added the refactor you mentioned on top, so you may want to read just that one commit.

Comment thread parsing/parser.mly Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-me parsetree-change Track changes to the parsetree for that affects ppxs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants