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

Support empty Location.input_name in input ast #196

Merged
merged 1 commit into from
Jul 6, 2019

Conversation

ryanartecona
Copy link
Contributor

Fixes jaredly/reason-language-server#297

When using reason-language-server in a dune project, I started seeing the following error bubble up from the running language server instance when I introduced ppx_deriving.std:

Fatal error: exception (Invalid_argument Filename.chop_suffix)
Raised at file "parsing/ast_mapper.ml", line 826, characters 12-21
Called from file "parsing/ast_mapper.ml", line 843, characters 38-58
Called from file "parsing/ast_mapper.ml", line 878, characters 14-27
Called from file "src/driver.ml", line 1266, characters 6-39
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Re-raised at file "parsing/location.ml", line 465, characters 14-25
Called from file "parsing/location.ml" (inlined), line 470, characters 31-61
Called from file "src/driver.ml", line 1271, characters 4-59
Called from file ".ppx/2a2600f2bea99fd7f9b28cf9261397f6/ppx.ml", line 1, characters 9-36
File "", line 1:
Error: Error while running external preprocessor
Command line: /Users/ryanartecona/code/axl/_build/default/.ppx/2a2600f2bea99fd7f9b28cf9261397f6/ppx.exe --as-ppx --cookie 'library-name="axl"' '/var/folders/6y/6ml47_vs4rgbh77xcb2vtzch0000gn/T/camlppx1912f1' '/var/folders/6y/6ml47_vs4rgbh77xcb2vtzch0000gn/T/camlppx90145c'

It wasn't straightforward to get here (dune collapsing multiple ppxes in use but not telling me which one an exception was raised from was annoying), but I eventually traced it to this module_from_input_name function in ppx_deriving.

The reason-language-server server uses refmt and ocamlc to do incremental error checking between saves while the user is working in a file. It turns out, when reason-language-server grabs the contents of an editor buffer, it first passes it straight to refmt (presumably to surface syntax errors first) which outputs a binary format AST, and next that AST file is passed to ocamlc. With a ppx like ppx_deriving in use, that ocamlc invocation will have a big hairy -ppx '...' argument, and it appears the ppx will be given whatever that prior refmt step output. In this case, since refmt was given buffer contents via stdin, it doesn't have a file name to put in its binary AST output, so the ppx sees a Location.input_name of "".

Adding this one match case for an empty string was the simplest thing that fixed my specific error. I don't know how sensitive the rest of ppx_deriving internals are to module_from_input_name generating something meaningful, but if it's not critical, it may be better to have an Invalid_argument _ -> [] exception handler in case that (basename (chop_suffix ...)) bit chokes on other nonsense. Unsure.

@gasche
Copy link
Contributor

gasche commented Jul 6, 2019

Looks good, thanks! I may also extend the patch to return [] in all the cases where chop_suffix fails, for extra robustness.

The inferred module name is used as the first component of the path : string list argument that is recursively passed to most derivers, and is supposed to contain a module path that goes from the toplevel environment (outside any module, no open) to the scope in which the derivation happens. For example, a [@@deriving ..] annotation on a type t within a submodule Foo of file.ml will be called with ~path:["File"; "Foo"]. In your case with the chop_suffix workaround, the path will only be Foo.

This path value is rarely used by the standard derivers plugins (I don't know about other plugins); it is used for example in the show plugin when with_path option is passed: if the t in my example above is defined as type t = Blob of int [@@deriving show { with_path = true ], then the show function on Blob 3 will show "File.Foo.Blob 3" instead of just "Blob 3" -- or just "Foo.Blob 3" in your specific workaround setting.

Overall I think that the fix is sensible: it passes some slightly wrong information to the derivers, but that will not matter much in the vast majority of cases, which is much better than failing with an error as you encountered. Note however that the "proper" fix would be for you to ensure that the tool you run have enough contextual information on the filename to work as intended (and not in degraded mode as here). Maybe there should be a way to pass the module name on ppx_deriving invocation, but I think that it should also be possible to fix the issue at the reason-language-server or refmt level by ensuring that the refmt output properly contains the intended buffer filename -- the binary-ast format accepted by the OCaml compiler (which then invokes the ppx binaries) specifically starts with a string for the filename.

@gasche gasche merged commit fe9ab34 into ocaml-ppx:master Jul 6, 2019
@rgrinberg
Copy link
Contributor

It wasn't straightforward to get here (dune collapsing multiple ppxes in use but not telling me which one an exception was raised from was annoying), but I eventually traced it to this module_from_input_name function in ppx_deriving.

This should be reported as a driver issue I believe. The driver has enough information to know which rewriter raised.

gasche added a commit to gasche/ppx_deriving that referenced this pull request Jul 6, 2019
@gasche
Copy link
Contributor

gasche commented Jul 6, 2019

(See #198 for my minor follow-up PR.)

@ryanartecona
Copy link
Contributor Author

Thanks all! And thanks @gasche especially for that generously detailed explanation.

This should be reported as a driver issue I believe. The driver has enough information to know which rewriter raised.

@rgrinberg by 'driver', do you mean in ppxlib or in the ocaml compiler? When I was digging around I saw some indication that dune is using ppxlib to squash multiple ppxes together, but I didn't get far enough to be certain that's the case or to know that's the one you mean.

@rgrinberg
Copy link
Contributor

Ppxlib and omp. As it stands, both of these libraries provide a driver. Perhaps @diml should consider phasing out one of them :)

gasche added a commit that referenced this pull request Jul 6, 2019
extend #196 (`Location.input_filename` fix) and add a CHANGELOG entry
kit-ty-kate added a commit to kit-ty-kate/opam-repository that referenced this pull request Oct 26, 2020
CHANGES:

5.0 (26/10/2020)
----------------

* Migrate to ppxlib ocaml-ppx/ppx_deriving#206, ocaml-ppx/ppx_deriving#210
  (Anton Kochkov, Gabriel Scherer, Thierry Martinez)

4.5
---

* Add support for OCaml 4.11.
  - `Ppx_deriving.string_of_{constant,expression}_opt` to destruct
    `Pconst_string` in a version-independent way
  ocaml-ppx/ppx_deriving#220, ocaml-ppx/ppx_deriving#222
  (Kate Deplaix, Thierry Martinez, review by Gabriel Scherer)

* Stronger type equalities in `Ppx_deriving_runtime` (for instance,
  `Ppx_deriving_runtime.result` and `Result.result` are now compatible with
  all OCaml versions)
  ocaml-ppx/ppx_deriving#223, ocaml-ppx/ppx_deriving#225
  (Thierry Martinez, review by Gabriel Scherer)

* `Ppx_deriving_runtime.Option` compatibility module
  ocaml-ppx/ppx_deriving#222
  (Thierry Martinez, review by Gabriel Scherer)

4.4.1
-----

* Add support for OCaml 4.10
  ocaml-ppx/ppx_deriving#211
  (Kate Deplaix, review by Gabriel Scherer)

4.4
---

* Restore support for OCaml 4.02.3
  ocaml-ppx/ppx_deriving#188
  (ELLIOTTCABLE)
* workaround Location.input_filename being empty
  when using reason-language-server
  ocaml-ppx/ppx_deriving#196
  (Ryan Artecona)
* Add support for OCaml 4.08.0
  ocaml-ppx/ppx_deriving#193, ocaml-ppx/ppx_deriving#197, ocaml-ppx/ppx_deriving#200
  (Gabriel Scherer)

4.3
---

* use Format through Ppx_deriving_runtime to avoid deprecation warning
  for users of JaneStreet Base
  (Stephen Bastians and Gabriel Scherer, review by whitequark)
* silence a ambiguous-field warning (41) in generated code
  ocaml-ppx/ppx_deriving#163
  (Étienne Millon, review by Gabriel Scherer)
* use dune
  ocaml-ppx/ppx_deriving#170
  (Rudi Grinberg, Jérémie Dimino)
* silence an unused-value warning for show
  ocaml-ppx/ppx_deriving#179
  (Nathan Rebours)

4.2.1
-----

  * Add support for OCaml 4.06.0
    ocaml-ppx/ppx_deriving#154, ocaml-ppx/ppx_deriving#155, ocaml-ppx/ppx_deriving#156, ocaml-ppx/ppx_deriving#159
    (Gabriel Scherer, Fabian, Leonid Rozenberg)
  * Consider { with_path = false } when printing record fields
    ocaml-ppx/ppx_deriving#157
    (François Pottier)

4.2
---

  * Add support for OCaml 4.05.0.
  * Use the `ocaml-migrate-parsetree` library to support multiple
    versions of OCaml.
  * Fix comparison order of fields in records (ocaml-ppx/ppx_deriving#136).
  * Silence an `unused rec flag` warning in generated code (ocaml-ppx/ppx_deriving#137).
  * Monomorphize comparison function for builtin types (ocaml-ppx/ppx_deriving#115)
  * Raise an error when `type nonrec` is encountered (ocaml-ppx/ppx_deriving#116).
  * Display an error message when dynamic package loading fails.
  * Add a `with_path` option to `@@deriving` to skip the module path
    in generated code (ocaml-ppx/ppx_deriving#120).

The homepage for the project has now moved to:
<https://github.com/ocaml-ppx/ppx_deriving>

4.1
---

  * Fix type error with inheritied polymorphic variant type in
    [@@deriving map].
  * Fix incorrect handling of multi-argument constructors in
    [@@deriving show].
  * Add API hooks for ppx_type_conv.

4.0
---

  * Show, eq, ord, map, iter, fold: add support for `Result.result`.
  * Ppx_deriving.Arg: use Result.result instead of polymorphic variants.
  * Ppx_deriving.sanitize: parameterize over an opened module.
  * Add support for `[@@deriving]` in module type declarations.
  * Add support for loading findlib packages instead of just files in
    ppx_deriving_main.
  * Treat types explicitly qualified with Pervasives also as builtin.
  * Compatibility with statically linked ppx drivers.

3.1
---

  * Show, eq, ord: hygienically invoke functions from referenced modules
    (such as X.pp for X.t when deriving show) to coexist with modules
    shadowing ones from standard library.
  * Iter, map, fold: hygienically invoke List and Array functions.

3.0
---

  * Implement hygiene: Ppx_deriving.{create_quoter,quote,sanitize,with_quoter}.
  * Show, eq, ord: add support for `lazy_t`.
  * Add support for `[@nobuiltin]` attribute.
  * Add Ppx_deriving.hash_variant.
  * Remove allow_std_type_shadowing option.
  * Remove Ppx_deriving.extract_typename_of_type_group.

2.1
---

  * Fix breakage occurring with 4.02.2 w.r.t record labels
  * Fix prefixed attribute names (`[@deriving.foo.attr]` and `[@foo.attr]`).
  * Add allow_std_type_shadowing option for eq and show.

2.0
---

  * Add support for open types.

1.1
---

  * New plugin: create.
  * Show, eq, ord: handle `_`.
  * Show, eq, ord, map, iter, fold: handle inheriting from a parametric
    polymorphic variant type.
  * Make `Ppx_deriving.poly_{fun,arrow}_of_type_decl` construct functions
    in correct order. This also fixes all derivers with types with
    more than one parameter.
  * Add `Ppx_deriving.fold_{left,right}_type_decl`.

1.0
---

  * Make deriver names lowercase.
  * Remove Findlib+dynlink integration. All derivers must now be
    explicitly required.
  * Allow shortening [%derive.x:] to [%x:] when deriver x exists.
  * Make `Ppx_deriving.core_type` field optional to allow ignoring
    unsupported [%x:] shorthands.
  * Add support for [@@deriving foo { optional = true }] that does
    not error out if foo is missing, useful for optional dependencies.
  * Rename ~name and ~prefix of `Ppx_deriving.attr` and
    `Ppx_deriving.Arg.payload` to `~deriver`.
  * Renamed `Ppx_deriving.Arg.payload` to `get_attr`.
  * Add `Ppx_deriving.Arg.get_expr` and `get_flag`.

0.3
---

  * Show, Eq, Ord, Iter, Fold: handle ref.
  * Show: handle functions.
  * Show: include break hints in format strings.
  * Show: pull fprintf into local environment.
  * Show: add `[@polyprinter]` and `[@opaque]`.
  * Add `Ppx_deriving.Arg.expr`.

0.2
---

  * New plugins: Enum, Iter, Map, Fold.
  * All plugins: don't concatenate affix if type is named `t`.
  * Add `[%derive.Foo:]` shorthand.
  * Show, Eq, Ord: add support for list, array, option.
  * Show: include full module path in output, including for types with manifest.
  * A lot of changes in `Ppx_deriving interface`.

0.1
---

  * Initial release.
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.

Adding (preprocess (pps ppx_deriving.std))) results in an error on each file.
4 participants