Drop items without source text in Code_matcher - #648
Conversation
NathanReb
left a comment
There was a problem hiding this comment.
The change looks sane to me but I think it is worth a test!
|
Could you also rebase it on top of |
| match_loop ~end_pos ~mismatch_handler ~expected ~source | ||
|
|
||
| (* [source] is supposed to be the list of items that follow the [@@deriving_inline] | ||
| item in the source file. That is not the case when the [@@deriving_inline] item is |
There was a problem hiding this comment.
This sounds a little bit odd, I think adding the ppx_template example here would make a bit more sense as otherwise, ppx generated deriving_inline nodes sounds a bit crazy and something we don't necessarily want to support.
|
Can you elaborate a bit more on |
|
Sure, happy to expand a bit. ppx_template is a ppx that expands one type/function/module/etc. declaration/definition in the source code to multiple declarations/definitions in the ppx-generated code, with mangled names. This isn't useful for vanilla OCaml, but is really common in OxCaml because the compiler doesn't (yet) natively know how to generate code which is polymorphic over some of the language extensions. Here's an example: [@@@expand_inline:
type%template ('a : k) ref = { mutable contents : 'a } [@@kind k = (value, bits64)]]
type ('a : value) ref = { mutable contents : 'a }
and ('a : bits64) ref__bits64 = { mutable contents : 'a }
[@@@end]In practice, we found that users would commonly generate so much code that odoc-generated documentation was functionally unusable. So, we modified ppx_template to hide generated code from odoc if all of the identifiers were mangled, using the special [@@@expand_inline:
type%template ('a : k) ref = { mutable contents : 'a } [@@kind k = (float64, bits64)]]
[@@@ocaml.text "/*"]
type ('a : float64) ref__float64 = { mutable contents : 'a }
and ('a : bits64) ref__bits64 = { mutable contents : 'a }
[@@@ocaml.text "/*"]
[@@@end]Ok, now, the problem is I have another The first is that I could use [@@@expand_inline:
type%template ('a : k) ref = { mutable contents : 'a }
[@@deriving sexp_of] [@@kind k = (float64, bits64)]]
[@@@ocaml.text "/*"]
type ('a : float64) ref__float64 = { mutable contents : 'a } [@@deriving sexp_of]
and ('a : bits64) ref__bits64 = { mutable contents : 'a }
include sig
[@@@ocaml.warning "-32"]
val sexp_of_ref__float64
: ('a : float64).
(('a : float64) -> Sexplib0.Sexp.t) -> ('a : float64) ref__float64 -> Sexplib0.Sexp.t
val sexp_of_ref__bits64
: ('a : bits64).
(('a : bits64) -> Sexplib0.Sexp.t) -> ('a : bits64) ref__bits64 -> Sexplib0.Sexp.t
end
[@@ocaml.doc "@inline"] [@@merlin.hide]
[@@@ocaml.text "/*"]
[@@@end]But notice that there's still a The second option is to use [%%template:
type ('a : k) ref = { mutable contents : 'a }
[@@deriving_inline sexp_of] [@@kind k = (float64, bits64)]
include sig
[@@@ocaml.warning "-32"]
val sexp_of_ref__float64
: ('a : float64).
(('a : float64) -> Sexplib0.Sexp.t) -> ('a : float64) ref__float64 -> Sexplib0.Sexp.t
val sexp_of_ref__bits64
: ('a : bits64).
(('a : bits64) -> Sexplib0.Sexp.t) -> ('a : bits64) ref__bits64 -> Sexplib0.Sexp.t
end
[@@ocaml.doc "@inline"]
[@@@end]]This works great, except the So, this PR modifies |
|
ppx_template, in general, passes through any source code in its payload unchanged, except for things annotated with specific attributes it understands, like Note that this form doesn't work: type%template ('a : k) ref = { mutable contents : 'a }
[@@deriving_inline sexp_of] [@@kind k = (float64, bits64)]
[@@@end]Because it's equivalent to: [%%template:
type ('a : k) ref = { mutable contents : 'a }
[@@deriving_inline sexp_of] [@@kind k = (float64, bits64)]]
[@@@end]That is, the |
Code_matcherassumes that the items following an inline block's anchor areexactly the items that were parsed from the source file, and rewrites their source text
in place. That assumption breaks when the anchor is itself inside code generated by
another ppx. In particular,
ppx_templatewraps template-mangled definitions in(**/**)markers so odoc hides them, and those markers inherit the location of the node they were
generated from. So
expands to a
(**/**)item whose location is the wholetypedeclaration, and thecorrected code replaces the declaration with the derived signature instead of inserting
it after.
Fix this by dropping items that start before the end of the anchor item, since those
cannot correspond to source text following it.