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 #203 Port to ppxlib - continuation of #206 #210

Merged
merged 2 commits into from
May 6, 2020

Conversation

XVilka
Copy link
Contributor

@XVilka XVilka commented Dec 16, 2019

cppo is also required for OCaml 4.10 support, so cannot remove yet: https://github.com/ocaml-ppx/ppx_deriving/blob/master/src/api/ppx_deriving.cppo.ml#L626

@XVilka
Copy link
Contributor Author

XVilka commented Dec 16, 2019

@rgrinberg @gasche please review this one.

@XVilka
Copy link
Contributor Author

XVilka commented Dec 18, 2019

Any objections on this PR?

@rgrinberg
Copy link
Contributor

and one macro I left for the convenience, because it reduces the code a lot - Attribute_patt(loc_, txt_, payload) used quite often in the matching, would be a lot of needless copy-pasting, imho.

I don't think it's the case and even if it was, it's still not a reason to use text substitution as a form of abstraction in OCaml.

@XVilka XVilka force-pushed the ppxlib branch 4 times, most recently from 514fbc6 to 9036cfd Compare December 20, 2019 05:08
@XVilka

This comment has been minimized.

@XVilka XVilka changed the title Port to ppxlib - continuation of #206 Fix #203 Port to ppxlib - continuation of #206 Dec 23, 2019
@XVilka

This comment has been minimized.

@XVilka

This comment has been minimized.

@XVilka

This comment has been minimized.

@XVilka

This comment has been minimized.

- Lower bound on OCaml version is raised to 4.04.1 because ppxlib
  0.9.0 requires it.

- ppx_tools is no longer used, because it is not compatible with
  ppxlib. ppx_tools was mostly used (1) for metaquot, which is handled
  by ppxlib.metaquot, and (2) for the Ast_convenience module, which is
  now defined in Ppx_deriving module.

- Most cppo conditional directives are gone, either because they
  were there to support OCaml <4.04.1, or because they are subsumed
  by the Migrate_parsetree.OCaml_408 implied by opening Ppxlib.
@XVilka XVilka force-pushed the ppxlib branch 3 times, most recently from 8dc784c to 87ce890 Compare April 15, 2020 09:36
@XVilka
Copy link
Contributor Author

XVilka commented Apr 15, 2020

@rgrinberg @gasche please take a look, lets start the ppxlib (and ppx in the future) porting begin.

@mseri
Copy link

mseri commented Apr 28, 2020

What is it that is blocking this PR at the moment? It would be very nice to have a ppxlib based ppx_deriving.

@gasche
Copy link
Contributor

gasche commented Apr 28, 2020

What is delaying the move to ppxlib is mostly maintainer availability. A couple months ago I gave maintainer rights to @thierry-martinez in the hope that he may be able to work on a release, but I didn't let him know explicitly enough (I only notified him before) and he is now probably overworked by the covid19 lockdown.

@thierry-martinez
Copy link
Collaborator

@gasche Sorry for the delay: I just noticed that the invitation you sent me has expired!

@gasche
Copy link
Contributor

gasche commented Apr 29, 2020

No apologies needed (and sorry for dumping this responsibility on you). I resent an invitation.

Copy link
Collaborator

@thierry-martinez thierry-martinez left a comment

Choose a reason for hiding this comment

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

Thanks @XVilka and sorry again for the very long delay. I have only suggestions for minor changes, but I am ready to approve.

"ounit" {with-test}
"ocaml" {>= "4.04.1"}
"ounit" {with-test}
"ocaml" {>= "4.05.0"}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why should we reject OCaml 4.04? The current code looks actually to work fine on 4.04 (even on 4.04.0). Anyway, if we want to constrain users to use OCaml 4.05, I think we should update the synopsis as well.

@@ -5,6 +5,10 @@ open Parsetree
open Ast_helper
open Ppx_deriving.Ast_convenience

#if OCAML_VERSION < (4, 08, 0)
module Stdlib = Pervasives
#endif
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we want to get rid of cppo, we could instead add the following binding at the beginning of the module:

let stdlib_compare = compare

Copy link

Choose a reason for hiding this comment

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

For this one could also depend on stdlib-shims which is quite lightweight

Copy link
Contributor Author

@XVilka XVilka May 6, 2020

Choose a reason for hiding this comment

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

Agree on moving to stdlib-shims. It will solve this particular #if, but there are some others, unrelated to Stdlib. For example, see this for 4.10 support: https://github.com/ocaml-ppx/ppx_deriving/blob/master/src/api/ppx_deriving.cppo.ml#L626

@@ -5,14 +5,11 @@ install: wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.t
script: bash -ex .travis-opam.sh
env:
matrix:
- OCAML_VERSION=4.02 # we require >=4.02.2 but this picks 4.02.3
- OCAML_VERSION=4.03
- OCAML_VERSION=4.04
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 could maintain compatibility with OCaml 4.04 (see below).

@XVilka
Copy link
Contributor Author

XVilka commented May 6, 2020

@thierry-martinez we restricted to 4.05 to reduce the cppo reliance:
I removed unnecessary ifdefs to reduce the churn like the following, most distributions have 4.05 now anyway:

open Parsetree
open Ppxlib

#if OCAML_VERSION >= (4, 05, 0)
type tyvar = string Location.loc
type tyvar = string Location.loc
#else

type tyvar = string
#endif

I would appreciate if we merge it as is, then we can improve it in subsequent pull requests.

@thierry-martinez thierry-martinez merged commit 0525a85 into ocaml-ppx:master May 6, 2020
@thierry-martinez
Copy link
Collaborator

Merged. Thanks, @XVilka!

@XVilka XVilka deleted the ppxlib branch May 6, 2020 11:23
@kit-ty-kate
Copy link
Collaborator

kit-ty-kate commented May 21, 2020

Using ppx_deriving master (now including this PR), many of the packages using ppx_deriving now fail with error messages similar to this one:

- + ocamlfind ocamldep -package zarith -package ppx_sexp_conv -package bytes -package sexplib -package cstruct -modules src/nocrypto.mli > src/nocrypto.mli.depends
- Location.Error(_)
- File "src/nocrypto.mli", line 1:
- Error: Error while running external preprocessor
- Command line: /home/opam/.opam/4.11.0+trunk/lib/ppx_deriving/./ppx_deriving package:ppx_sexp_conv '/tmp/camlppx3023b9' '/tmp/camlppx0159b2'

Is this expected?

@gasche
Copy link
Contributor

gasche commented May 21, 2020

You are politely phrasing it as a question but it sounds like a bug indeed. I don't know whether we should look for a bug within ppx_deriving itself, or at the interaction between ppx_deriving and ppxlib, or between ppxlib and the "driver" logic. (One reason to suspect the driver would be if the ocamlfind packages woud fail, and the dune packages would not, for example.)

@ghost
Copy link

ghost commented May 21, 2020

It's a bit odd that the error is reported like this. It should be passed from the ppx rewriter to the compiler via an ocaml.error extension point, and properly reported by the compiler.

You can try wrapping the entry point in ppx_deriving_main.cppo.ml as follow:

  try
    Ast_mapper.register "ppx_deriving" mapper
  with exn ->
    Location.report_exception Format.err_formatter exn;
    exit 1

that should help understand what is going on.

@kit-ty-kate
Copy link
Collaborator

One reason to suspect the driver would be if the ocamlfind packages woud fail, and the dune packages would not, for example.

It seems to be the case from the results I have. The only package I can see for now using dune that still does fail is jupyter:

#=== ERROR while compiling jupyter.2.7.1 ======================================#
# context              2.1.0~alpha | linux/x86_64 | ocaml-base-compiler.4.10.0 | file:///home/opam/opam-repository
# path                 ~/.opam/4.10.0/.opam-switch/build/jupyter.2.7.1
# command              ~/.opam/4.10.0/bin/dune build -p jupyter -j 71
# exit-code            1
# env-file             ~/.opam/log/jupyter-8-5bdbb6.env
# output-file          ~/.opam/log/jupyter-8-5bdbb6.out
### output ###
# [...]
# Segmentation fault (core dumped)
# File "jupyter/src/kernel/message_channel.mli", line 1:
# Error: Error while running external preprocessor
# Command line: /home/opam/.opam/4.10.0/lib/ppx_deriving/./ppx_deriving package:ppx_deriving_yojson '/tmp/camlppx443db1' '/tmp/camlppx387ffb'
# 
#       ocamlc jupyter/src/kernel/.jupyter_kernel.objs/byte/jupyter_kernel__Client.{cmi,cmti} (exit 2)
# (cd _build/default && /home/opam/.opam/4.10.0/bin/ocamlc.opt -ppx '/home/opam/.opam/4.10.0/lib/lwt_ppx/./ppx.exe --as-ppx' -ppx '/home/opam/.opam/4.10.0/lib/ppx_deriving/./ppx_deriving package:ppx_deriving_yojson' -short-paths -safe-string -strict-sequence -strict-formats -w A-4-31-33-34-39-41-42-43-44-45-48-49-50-58 -g -bin-annot -I jupyter/src/kernel/.jupyter_kernel.objs/byte -I /home/opam/[...]
# Segmentation fault (core dumped)
# File "jupyter/src/kernel/client.mli", line 1:
# Error: Error while running external preprocessor
# Command line: /home/opam/.opam/4.10.0/lib/ppx_deriving/./ppx_deriving package:ppx_deriving_yojson '/tmp/camlppx675f5a' '/tmp/camlppx54c3ed'

However it uses a patched version of ppx_deriving: ocaml-ppx/ppx_deriving_yojson#118. I will try again with @thierry-martinez's new and improved PR

@kit-ty-kate
Copy link
Collaborator

You can try wrapping the entry point in ppx_deriving_main.cppo.ml as follow:

  try
    Ast_mapper.register "ppx_deriving" mapper
  with exn ->
    Location.report_exception Format.err_formatter exn;
    exit 1

that should help understand what is going on.

I tried and the catch-block wasn't hit. The error seems to have been caught earlier and the program exited before the Ast_mapper.register was able to return anything (a prerr_endline displays something if placed before the call, but not after)

thierry-martinez added a commit to thierry-martinez/ppx_deriving that referenced this pull request May 21, 2020
This fixes the segmentation fault reported by kit-ty-kate:
ocaml-ppx#210 (comment)

I don't know where this segmentation fault precisely occurred, but I
suppose that converting the mapper makes Migrate_parsetree make a lot
of conversion between each sub-tree of the AST. The new approach is a
bit more verbose but conceptually simpler and should be more efficient.
@thierry-martinez
Copy link
Collaborator

I propose a fix here: #221

I don't know where exactly the segmentation fault occurs, but it appears that it occurs while executing the mapper obtained by conversion through Migrate_parsetree. Instead of converting the whole mapper, I suggest to convert only the parts of the AST that have to be deconstructed by pattern-matching: we keep the compatibility between the different AST versions, it appears to fix the segmentation fault, and it should be more efficient.

@gasche
Copy link
Contributor

gasche commented May 21, 2020

I find it worrying that we would have a segmentation fault that we can't explain and don't know if we actually fixed. I can try to have a look in the next few days; I assume that the issue is easy to reproduce by trying to build jupyter?

@kit-ty-kate
Copy link
Collaborator

kit-ty-kate commented May 21, 2020

@gasche yes it is. Here is a Dockerfile to reproduce the segfault:

FROM ocurrent/opam:debian-10
RUN opam pin add -n ppx_deriving git://github.com/ocaml-ppx/ppx_deriving.git#cb1ad02d14d4757221c8dfa2aea2df616ca9500c
RUN opam pin add -n ppx_deriving_yojson git://github.com/thierry-martinez/ppx_deriving_yojson.git#5a2680829a9d1cb30821d296b3ec66cb56fc7cc1
RUN git -C ~/opam-repository pull origin master && opam update
RUN opam depext jupyter.2.7.1
RUN opam install --deps-only jupyter.2.7.1
RUN opam install jupyter.2.7.1

@thierry-martinez
Copy link
Collaborator

thierry-martinez commented May 22, 2020

I think I understood the segmentation fault, but I don't see what would be the good solution to fix it. Ppx_deriving_main calls Ast_mapper.register where Ast_mapper is defined in Ast_408. Ast_408.Ast_mapper.register calls (through the reference register_function) the function Ast_408.Ast_mapper.run_main, which in turn calls the function Ast_408.Ast_mapper.apply_lazy. The problem occurs in this function.

The problem is that the source file in read by using input_value (which is known to be unsafe), and the result is supposed to be of type Ast_408.Parsetree.signature or Ast_408.Parsetree.structure, which is correct only if the current OCaml is 4.08.

I observe the segmentation fault quite soon afterwards, when Migrate_parsetree_408_409_migrate.copy_module_type is called on the signature just read, which is expected to fail since Parsetree,module_type has changed between 4.08 and my current 4.10.

I don't see a good solution for this problem apart from not using Ast_xxx.Ast_mapper.register. I believe that these functions cannot check that the version of the given AST is correct since I believe that AST are not versioned. What they could do is to suppose that the given AST is from the current version of the compiler instead of the migrated one, but that would suppose that they convert the AST before applying the mapper, which would involve some recursion twists since the migrate-parsetree machinery is being defined: but I don't think it is worth changing this, because it is not clear that the new semantics (supposing that the given AST is for the current OCaml version) is better than the old one (even if it does not look very useful to be able to cross-compile a PPX transformer for another version of OCaml, who knows...)

Not using Ast_xxx.Ast_mapper.register is essentially what I proposed in #221.

@gasche
Copy link
Contributor

gasche commented May 22, 2020

I haven't followed your tracks yet, but yet another naive question: there should be a magic number in serialized ASTs, that differs between language versions. If this is really an incompatible-format mismatch, how come that we didn't see a magic-number failure instead of a segfault?

I initially wondered if it was an upstream issue, not updating magic numbers at this point of the 4.11 release process (so they would be wrongly identical to the 4.10 ones). But Florian did update the magic numbers, and in any case they are distinct from the 4.08 ones.

@gasche
Copy link
Contributor

gasche commented May 22, 2020

P.S.: It does not go without saying: thanks a lot for your work on the ppxlib port and tracking this new issue.

@gasche
Copy link
Contributor

gasche commented May 22, 2020

I suspect a bug in ocaml-migrate-parsetree; in ast_408.ml, the magic number checks of apply_lazy are implemented by comparing with Config module, where Config appears to point to the compiler libraries Config module, for the current OCaml version, instead of a 4.08-specific Config module. There is a Config submodule in the file that should override the compiler-libs Config, but it is only defined later.

@thierry-martinez
Copy link
Collaborator

Oh, sorry, I suspected that initially but I missed the fact that utils/config.mlp was regenerated by ./configure in OCaml source tree, and I was lead to the surprising observation that the magic numbers did not change between versions. Thank you for correcting me! So yes, the fix should be not to use Config in Ast_xxx modules but version specific magic numbers instead. May I submit a patch to ocaml-migrate-parsetree? The fix I proposed for ppx_deriving still seems correct.

@gasche
Copy link
Contributor

gasche commented May 22, 2020

May I submit a patch to ocaml-migrate-parsetree?

Yes, feel free to. I created an issue (not a PR) there as ocaml-ppx/ocaml-migrate-parsetree#97 . If you fix this, you should fix it for all affected OCaml versions. I think it would also be nice to include a device to ensure that the error would lead to a compilation failure if the modules get reordered again. For example the Config submodule could include a value let in_ast_408 = () (with a comment that refers to the issue/PR), and then the magic-check code would first let () = Config.in_ast_408 in.

thierry-martinez added a commit to thierry-martinez/ocaml-migrate-parsetree that referenced this pull request May 22, 2020
…gister`

This commit fixes
ocaml-ppx#97
which caused segfaults: `Ast_4NN.register` now correctly checks
AST magic number against the version-specific magic number instead
of using the magic number defined in the `Config` module of the
current compiler.

Version-specific magic numbers was already defined by overriding
`Config` module later in the file: the fix just consists in riding up the
overriding of `Config` before the overriding of
`Ast_helper`. Following Gabriel Scherer's trick recommended in
ocaml-ppx/ppx_deriving#210 (comment)
a unit-value `in_ast_4nn` is defined in `Config` module and used in
`Ast_helper.register` to ensure that the module are well ordered.
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.
kit-ty-kate added a commit to kit-ty-kate/opam-repository that referenced this pull request Oct 26, 2020
CHANGES:

* Migrate to ppxlib ocaml-ppx/ppx_deriving#206, ocaml-ppx/ppx_deriving#210
  (Anton Kochkov, Gabriel Scherer, Thierry Martinez)
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.

6 participants