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

fix(melange): run melc ppx with merlin #6476

Merged
merged 25 commits into from
Nov 30, 2022

Conversation

jchavarri
Copy link
Collaborator

Fixes #6456.

A couple of questions:

  • I am not sure what to do with to_dot_merlin. It seems all FLG directives are commented? I don't understand what's the purpose
  • Unsure if -bs-jsx 3 should be conditionally added, based on flags field value on library or melange.emit stanzas.

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@jchavarri jchavarri self-assigned this Nov 15, 2022
@rgrinberg
Copy link
Member

I am not sure what to do with to_dot_merlin. It seems all FLG directives are commented? I don't understand what's the purpose

No idea. Anyway printing the .merlin is just for debugging so don't bother thinking too hard.

Unsure if -bs-jsx 3 should be conditionally added, based on flags field value on library or melange.emit stanzas.

It should be always added for emit stanzas and for libraries that are "melange only". See the condition we have for object directories already.

make_directive "FLG"
(Sexp.List [ Atom (Pp_kind.to_flag flag); Atom args ])
(Sexp.List
[ Atom (Pp_kind.to_flag Ppx); Atom "melc -as-ppx -bs-jsx 3" ])
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't the melange ppx come first?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Isn't the merlin syntax something like FLG -ppx melc -as-ppx -bs-jsx 3? The first atom is what renders the -ppx flag next to FLG.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We should make a note to remove the -bs-jsx-3 stuff eventually. Here's my rough plan:

@@ -414,7 +435,7 @@ module Unprocessed = struct
Path.Set.union src_dirs
(Path.Set.of_list_map ~f:Path.source more_src_dirs)
in
{ Processed.stdlib_dir; src_dirs; obj_dirs; flags; extensions }
{ Processed.stdlib_dir; src_dirs; obj_dirs; flags; extensions; mode }
Copy link
Member

Choose a reason for hiding this comment

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

Processed shouldn't include the mode. The flags should already contain what's needed.

Copy link
Collaborator Author

@jchavarri jchavarri Nov 16, 2022

Choose a reason for hiding this comment

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

Sorry, I spent some time trying to implement this, but I don't understand how it is possible.

flags includes only the compiler flags, and it's dumped in a single FLG directive here:

| flags ->
[ make_directive "FLG"
(Sexp.List (List.map ~f:(fun s -> Sexp.Atom s) flags))
]

We want melange FLG to be a separate directive. I can replace mode field in processed with something like melange_ppx_flag of type string list option or similar. In any case, something else needs to be passed to Processed in order to add this new directive.

Copy link
Member

Choose a reason for hiding this comment

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

Why does it need to be a separate FLG directive? We manage to put all the other flags in one directive.

Copy link
Collaborator Author

@jchavarri jchavarri Nov 18, 2022

Choose a reason for hiding this comment

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

I don't think so, there were two separate FLG directives already.

One for the OCaml flags:

[ make_directive "FLG"
(Sexp.List (List.map ~f:(fun s -> Sexp.Atom s) flags))
]

Another for the pp (or ppx) flags:

make_directive "FLG"
(Sexp.List [ Atom (Pp_kind.to_flag flag); Atom args ])
:: flags

I don't understand how to inject the melc ppx in either of those. The first one (afaiu) is to tell Merlin which flags are used for the OCaml compiler. The second one is for user-defined ppxs. We need a new directive to tell Merlin "you also need to run this ppx", as it's a separate process: it's not part of the compiler flags, nor a ppx that is user defined.

Do you or @anmonteiro see a way to "blend" it with any of the two other existing directives?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@rgrinberg Any thoughts on the above? Considering there were already two FLG directives, should melc ppx be made part of any of them or could it exist on its own? If anything, it should be part of the second, but I don't think it's possible at the moment as it's not a user defined ppx (so can't be compiled with ppx driver).

Copy link
Member

Choose a reason for hiding this comment

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

This is hacky but it looks good enough for now. A few points:

  1. We shouldn't hard code the path of melc. We should use the absolute path that was resolved by dune
  2. We should make sure that melc is actually built if it's defined in the same workspace.

In any case, if @anmonteiro is fine with this temporary hack then we can merge it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree we should fix 1. & 2. before merging.

What's the temporary hack? the 2 FLG directives?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. I would expect all these melange ppx's to be ported to ppxlib and enabled explicitly.

Copy link
Collaborator

Choose a reason for hiding this comment

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

that's the goal for the ReactJS PPX, as highlighted in #6476 (comment).

I don't yet have a clear plan for the builtin PPX, which currently is very tightly integrated into the compiler.

@jchavarri jchavarri requested review from rgrinberg and removed request for rgrinberg November 16, 2022 09:13
* main:
  test(melange): demonstrate error in melange compilation trying to build @ALL (ocaml#6485)
  chore(nix): make it faster to get melange (ocaml#6347)
  refactor: status db style tweaks (ocaml#6478)
  fix: improve error message for status db (ocaml#6479)
  refactor: remove unused [flags] parameter (ocaml#6480)
  refactor(ctypes): remove pesky aliases (ocaml#6482)
  chore: tweak `hacking.rst` following `dune.exe` move to _boot (ocaml#6484)
  feature(coq): automatic detection of native
  chore(coq): bump Coq lang to 0.7
  test: disable formatting for a single dune file (ocaml#6465)
  refactor: clean up module compilation (ocaml#6461)
  doc: add button to copy code blocks in Dune manual (ocaml#6428)
  refactor: deforest a set conversion (ocaml#6473)
  refactor: remove temporary map used for sorting (ocaml#6472)
  fix(melange): handle include_subdirs unqualified (ocaml#6475)
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@jchavarri
Copy link
Collaborator Author

It should be always added for emit stanzas and for libraries that are "melange only". See the condition we have for object directories already.

I meant something else, rather how to pass compiler flags to melange -ppx directive. I managed to do it in 5de0797 cc @anmonteiro

@jchavarri
Copy link
Collaborator Author

I meant something else, rather how to pass compiler flags to melange -ppx directive. I managed to do it in 5de0797

I tested this change with vscode editor and it seems it doesn't work, I started getting errors of the kind unknown flag -as-ppx. It seems they come from merlin?

I am not sure how to fix this, so I reverted the change in 993c0ff.

@anmonteiro
Copy link
Collaborator

  • We don't need to pass all the compiler flags to melc --as-ppx, just the -bs-jsx 3 flag
  • It's not the end of the world to pass -bs-jsx 3 unconditionally, it just means that the PPX will always be applied

* main:
  test: formatting of alternative dune files (ocaml#6567)
  refactor: remove Modules.is_empty (ocaml#6564)
  refactor: module kinds (ocaml#6562)
  refactor(coq): resolve lack of coqc properly
  Cache file contents in action builder by name. (ocaml#6555)
  fix: re-enable dune on older macos sdk's (ocaml#6515)
  fix: do not hide lib interface module (ocaml#6549)
  test: remove pkg-config output for reproducibility (ocaml#6543)
  melange: add test for ocaml flags (ocaml#6548)
  fix: improve virtual library error messages
  test: virtual library and impl locations
  test: alias module regression (ocaml#6544)
  refactor(merlin): dump config sub command (ocaml#6547)
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
Copy link
Collaborator

@anmonteiro anmonteiro left a comment

Choose a reason for hiding this comment

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

Looks good. Do you plan to fix the remaining TODO in Merlin.to_dot_merlin?

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@jchavarri
Copy link
Collaborator Author

Do you plan to fix the remaining TODO in Merlin.to_dot_merlin?

Fixed the todo and verified the output in test in
c4a6d2b.

let () =
match mode with
| `Ocaml -> ()
| `Melange -> print "# FLG -ppx melc -as-ppx -bs-jsx 3\n"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can use the same machinery above, with quote_for_dot_merlin. See my comment in the test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Please check 5c34973.

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@rgrinberg
Copy link
Member

Merlin might rely on a few binaries to exist (ocaml toolchain, user ppxs, etc) but I can't find an example that shows how one can define a dependency on binaries. I can only see directives B, S, FLG, STDLIB, EXCLUDE_QUERY_DIR, but idu how any of them could be used to define a dependency on a binary.

Note that user ppx's are provided as absolute paths to merlin for exactly this reason. Merlin doesn't use the ocaml toolchain (it vendors what it needs), so there's no need to worry about that.

Okay, we can skip the dependency on melc for now because we don't handle ppx cleanly either.

@@ -68,7 +69,9 @@ module Processed = struct

let serialize_path = Path.to_absolute_filename

let to_sexp ~pp { stdlib_dir; obj_dirs; src_dirs; flags; extensions } =
let melc_ppx_flg = "melc -as-ppx -bs-jsx 3"
Copy link
Member

Choose a reason for hiding this comment

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

This is the offending line. It should be using serialize_path to encode melc and using the melc path we resolved to build the actual library

Copy link
Member

Choose a reason for hiding this comment

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

Also, I'm pretty sure you can provide flags as separate atoms. So that we don't have to rely on merlin to parse anything.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It should be using serialize_path to encode melc and using the melc path we resolved to build the actual library

@rgrinberg Could you help me understand this part, please? The path that is resolved in merlin points to the melc stdlib e.g. _opam/lib/melange, assuming you refer to this code

| `Melange -> Melange_binary.where sctx ~dir

But the path here should be to the melc command, which would be in e.g. _opam/bin/melc. How are both related? Or am I misunderstanding?

Copy link
Member

Choose a reason for hiding this comment

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

Sure, keep asking questions if something is unclear. The gist of the issue is: we should not use any relative paths in the .Merlin directive. All paths should be absolute. So, library paths, stdlib paths, preprocessors, etc should all be fully resolved.

The current code violates this with the way it refers to the melc binary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for clarifying. I tried a fix in c6e8bd6.

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@jchavarri
Copy link
Collaborator Author

@rgrinberg in f698bd6 I lifted the calculation of melc flags to the Unprocessed.process function. This allows to share the flags between both to_dot_merlin and to_sexp functions. I think the code is cleaner now, but please let me know your thoughts.

Comment on lines 234 to 236
, match acc_melc_flags with
| Some _ -> acc_melc_flags
| None -> melc_flags ))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am not sure about this. Should it rather be melc_flags directly? (i.e. no accumulation needed)

I guess the missing part is: what is the relationship between the paths passed as param to print_generic_dot_merlin?

src/dune_rules/merlin.ml Outdated Show resolved Hide resolved
_
Signed-off-by: Rudi Grinberg <me@rgrinberg.com>
src/dune_rules/merlin.ml Outdated Show resolved Hide resolved
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@rgrinberg
Copy link
Member

According to the tests, melc is being added even when it's not being used.

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@jchavarri
Copy link
Collaborator Author

@rgrinberg Fixed in dadc896. I moved the definition of melc_compiler inside the code block where melc_flags is calculated in order to follow the style guidelines about scope.

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@jchavarri
Copy link
Collaborator Author

I have been testing vscode-ocaml extension using this PR, but unfortunately something regressed with the most recent changes and now it does not work at all.

I see errors in lsp log of the kind:

melc: can not handle multiple files
unknown flag 3
unknown flag -as-ppx

This used to work at the beginning of the PR, when passing whole command in quotes, e.g. (FLG (-ppx "melc -as-ppx -bs-jsx 3")). Is there a way to do something similar with sexp atoms?

@rgrinberg
Copy link
Member

This used to work at the beginning of the PR, when passing whole command in quotes, e.g. (FLG (-ppx "melc -as-ppx -bs-jsx 3")). Is there a way to do something similar with sexp atoms?

Not that I know. Let's just leave it as a single form for now.

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
@jchavarri
Copy link
Collaborator Author

updated in 8bacbb7 to pass single string. Confirmed it works with editor integration.

@rgrinberg rgrinberg merged commit 4cfff5d into ocaml:main Nov 30, 2022
@jchavarri jchavarri deleted the melange/fix-melc-ppx branch November 30, 2022 21:50
moyodiallo pushed a commit to moyodiallo/dune that referenced this pull request Dec 2, 2022
Fixes merlin support when using the melange ppx

Signed-off-by: Javier Chavarri <javier.chavarri@gmail.com>
jchavarri added a commit to jchavarri/dune that referenced this pull request Dec 5, 2022
* main: (54 commits)
  doc: how we write `to_dyn` and `equal` (ocaml#6621)
  test(cache): test output of man pages
  test: dune utop for (subdir ..) (ocaml#6629)
  refactor: improve style of utop rules (ocaml#6628)
  test: depend on utop (ocaml#6627)
  refactor(stdune): Add Appendable_list.cons (ocaml#6624)
  doc: tighten wording in README.md
  test: add a repro case for ocaml#6607 (ocaml#6612)
  doc: cleanup status badges in README.md (ocaml#6618)
  doc(README): rewrap paragraphs and cleanup links
  coq: more resilient config query
  fix: link time code gen (ocaml#6606)
  fix(melange): run melc ppx with merlin (ocaml#6476)
  feature(melange): add compile_flags (ocaml#6569)
  refactor: move `modules: Modules.t` from `Dune_package.Lib` to `Lib_info` (ocaml#6605)
  Set CLICOLOR_FORCE=0 (ocaml#6608)
  fix: declare deps for ccomp detection (ocaml#6610)
  refactor: assume Cmdliner.Arg.conv is abstract (ocaml#6609)
  refactor: gen_rules pattern matching (ocaml#6604)
  Add CI for MSVC using dkml-workflows (ocaml#6540)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

bug(melange): merlin does not know about pipe first (|.) operator
3 participants