Skip to content

Support doc comment before variant #7535

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

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- Fix `index out of bounds` exception thrown in rare cases by `rescript-editor-analysis.exe codeAction` command. https://github.com/rescript-lang/rescript/pull/7523
- Don't produce duplicate type definitions for recursive types on hover. https://github.com/rescript-lang/rescript/pull/7524
- Prop punning when types don't match results in I/O error: _none_: No such file or directory. https://github.com/rescript-lang/rescript/pull/7533
- Fix doc comment before variant throwing syntax error. https://github.com/rescript-lang/rescript/pull/7535

#### :nail_care: Polish

Expand Down
45 changes: 38 additions & 7 deletions compiler/syntax/src/res_core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4885,12 +4885,35 @@ and parse_constr_decl_args p =
* | constr-name const-args
* | attrs constr-name const-args *)
and parse_type_constructor_declaration_with_bar p =
match p.Parser.token with
| Bar ->
let is_constructor_with_bar p =
Parser.lookahead p (fun state ->
match state.Parser.token with
| DocComment _ -> (
Parser.next state;
match state.token with
| Bar -> true
| _ -> false)
| Bar -> true
| _ -> false)
in
if is_constructor_with_bar p then (
let doc_comment_attrs =
match p.Parser.token with
| DocComment (loc, s) ->
Parser.next p;
[doc_comment_to_attribute loc s]
| _ -> []
in
let start_pos = p.Parser.start_pos in
Parser.next p;
Some (parse_type_constructor_declaration ~start_pos p)
| _ -> None
let constr = parse_type_constructor_declaration ~start_pos p in
Some
{
constr with
Parsetree.pcd_attributes =
doc_comment_attrs @ constr.Parsetree.pcd_attributes;
})
else None

and parse_type_constructor_declaration ~start_pos p =
Parser.leave_breadcrumb p Grammar.ConstructorDeclaration;
Expand Down Expand Up @@ -4919,9 +4942,17 @@ and parse_type_constructor_declarations ?first p =
let first_constr_decl =
match first with
| None ->
let doc_comment_attrs =
match p.Parser.token with
| DocComment (loc, s) ->
Parser.next p;
[doc_comment_to_attribute loc s]
| _ -> []
in
let start_pos = p.Parser.start_pos in
ignore (Parser.optional p Token.Bar);
parse_type_constructor_declaration ~start_pos p
let constr = parse_type_constructor_declaration ~start_pos p in
{constr with pcd_attributes = doc_comment_attrs @ constr.pcd_attributes}
| Some first_constr_decl -> first_constr_decl
in
first_constr_decl
Expand All @@ -4947,7 +4978,7 @@ and parse_type_representation ?current_type_name_path ?inline_types_context p =
in
let kind =
match p.Parser.token with
| Bar | Uident _ ->
| Bar | Uident _ | DocComment _ ->
Parsetree.Ptype_variant (parse_type_constructor_declarations p)
| Lbrace ->
Parsetree.Ptype_record
Expand Down Expand Up @@ -5500,7 +5531,7 @@ and parse_type_equation_and_representation ?current_type_name_path
parse_record_or_object_decl ?current_type_name_path ?inline_types_context
p
| Private -> parse_private_eq_or_repr p
| Bar | DotDot ->
| Bar | DotDot | DocComment _ ->
let priv, kind = parse_type_representation p in
(None, priv, kind)
| _ -> (
Expand Down
16 changes: 10 additions & 6 deletions compiler/syntax/src/res_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,8 @@ let print_list ~get_loc ~nodes ~print ?(force_break = false) t =
in
Doc.breakable_group ~force_break docs

let print_listi ~get_loc ~nodes ~print ?(force_break = false) t =
let print_listi ~get_loc ~nodes ~print ?(ignore_empty_lines = false)
?(force_break = false) t =
let rec loop i (prev_loc : Location.t) acc nodes =
match nodes with
| [] -> (prev_loc, Doc.concat (List.rev acc))
Expand All @@ -352,8 +353,10 @@ let print_listi ~get_loc ~nodes ~print ?(force_break = false) t =
| Some comment -> (Comment.loc comment).loc_start
in
let sep =
if start_pos.pos_lnum - prev_loc.loc_end.pos_lnum > 1 then
Doc.concat [Doc.hard_line; Doc.hard_line]
if
start_pos.pos_lnum - prev_loc.loc_end.pos_lnum > 1
&& not ignore_empty_lines
then Doc.concat [Doc.hard_line; Doc.hard_line]
else Doc.line
in
let doc = print_comments (print node t i) t loc in
Expand Down Expand Up @@ -1542,7 +1545,7 @@ and print_constructor_declarations ~state ~private_flag
~print:(fun cd cmt_tbl i ->
let doc = print_constructor_declaration2 ~state i cd cmt_tbl in
print_comments doc cmt_tbl cd.Parsetree.pcd_loc)
~force_break cmt_tbl
~force_break cmt_tbl ~ignore_empty_lines:true
in
Doc.breakable_group ~force_break
(Doc.indent (Doc.concat [Doc.line; private_flag; rows]))
Expand All @@ -1555,7 +1558,8 @@ and print_constructor_declaration2 ~state i
let comment_doc =
match comment_attrs with
| [] -> Doc.nil
| comment_attrs -> print_doc_comments ~state cmt_tbl comment_attrs
| comment_attrs ->
print_doc_comments ~sep:Doc.hard_line ~state cmt_tbl comment_attrs
in
let attrs = print_attributes ~state attrs cmt_tbl in
let is_dot_dot_dot = cd.pcd_name.txt = "..." in
Expand All @@ -1579,8 +1583,8 @@ and print_constructor_declaration2 ~state i
in
Doc.concat
[
bar;
comment_doc;
bar;
Doc.group
(Doc.concat
[
Expand Down
24 changes: 12 additions & 12 deletions tests/tests/src/arith_syntax.res
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
type rec expression =
| /** non-negative integer constant */
Numeral(float)
| /** Addition [e1 + e2] */
Plus(expression, expression)
| /** Difference [e1 - e2] */
Minus(expression, expression)
| /** Product [e1 * e2] */
Times(expression, expression)
| /** Quotient [e1 / e2] */
Divide(expression, expression)
| /** Opposite value [-e] */
Negate(expression)
/** non-negative integer constant */
| Numeral(float)
/** Addition [e1 + e2] */
| Plus(expression, expression)
/** Difference [e1 - e2] */
| Minus(expression, expression)
/** Product [e1 * e2] */
| Times(expression, expression)
/** Quotient [e1 / e2] */
| Divide(expression, expression)
/** Opposite value [-e] */
| Negate(expression)
| Variable(string)

let rec str = e =>
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/src/condition_compilation_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ function eq(loc, x, y) {
};
}

eq("File \"condition_compilation_test.res\", line 63, characters 5-12", 3, 3);
eq("File \"condition_compilation_test.res\", line 60, characters 5-12", 3, 3);

eq("File \"condition_compilation_test.res\", line 64, characters 5-12", v.contents, 2);
eq("File \"condition_compilation_test.res\", line 61, characters 5-12", v.contents, 2);

Mt.from_pair_suites("Condition_compilation_test", suites.contents);

Expand Down
3 changes: 0 additions & 3 deletions tests/tests/src/condition_compilation_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ type open_flag =
| O_DSYNC
| O_SYNC
| O_RSYNC

| O_SHARE_DELETE

| O_CLOEXEC

| O_KEEPEXEC
Copy link
Member Author

Choose a reason for hiding this comment

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

With this PR, no newlines in between variant constructors. This makes the implementation simpler since I don't need to hack around node's location.

Personally, I prefer the formatting this way too. What do you think? @cknitt @zth @nojaf

Copy link
Collaborator

Choose a reason for hiding this comment

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

Fine for me!

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 great! 🎉

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I meant the new formatting of doc comments before variants is great.

Regarding the newlines, it would be nice if this was still possible:

type x =
  // first group
  | A
  | B
  | C

  // second group
  | D
  | E
  | F

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can't you just put an empty comment line where you want the break?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@shulhi, this is better! I wasn't a fan of adjusting the ranges in the parser to satisfy the format. It felt wrong.

Copy link
Member Author

Choose a reason for hiding this comment

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

This will reformat it to

type x =
  // first group
  | A
  | B
  | C
  // second group
  | D
  | E
  | F

I can still investigate this if we want to preserve the previous behavior. I actually like it without the newline.

The challenge with preserving the previous behavior has to do with how we treat comments and doc comments (comment table and attribute). If we compare the location for the comment for the above example, first group is attached to line 3, while it would be at line 2 for doc comment. We would have to adjust the ranges to make it print the same way for both - which felt like a hack.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, that sounds quite hacky indeed.
I guess I can live with no newlines in that case. 🙂


let vv = 3
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/src/gpr_1822_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ let area;

area = myShape.TAG === "Circle" ? 100 * 3.14 : 10 * myShape._1 | 0;

eq("File \"gpr_1822_test.res\", line 23, characters 3-10", area, 314);
eq("File \"gpr_1822_test.res\", line 22, characters 3-10", area, 314);

Mt.from_pair_suites("Gpr_1822_test", suites.contents);

Expand Down
1 change: 0 additions & 1 deletion tests/tests/src/gpr_1822_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ let eq = (loc, x, y) => {

type shape =
| Circle(int)

| Rectangle(int, int)

let myShape = Circle(10)
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/src/mutual_non_recursive_type.res
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type t =
| Ta(t) /* * u compilation error [nonrec applices to all] */
| Tb(int)
and u =
| /** one attribute nonrecursive will affect all */
H(t) /* refers to old t */
/** one attribute nonrecursive will affect all */
| H(t) /* refers to old t */

let v: u = H(OT)
1 change: 0 additions & 1 deletion tests/tests/src/test_seq.res
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ type rec spec =
| Set_float(ref<float>) /* Set the reference to the float argument */
| Tuple(list<spec>) /* Take several arguments according to the
spec list */

| Symbol(list<string>, string => unit)
/* Take one of the symbols as argument and
call the function with the symbol. */
Expand Down
16 changes: 8 additions & 8 deletions tests/tools_tests/src/DocExtractionRes.res
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ let \"SomeConstant" = 12
module SomeInnerModule = {
/*** Another module level docstring here.*/
type status =
| /** If this is started or not */
Started(t)
| /** Stopped? */
Stopped
| /** Now idle.*/
Idle
/** If this is started or not */
| Started(t)
/** Stopped? */
| Stopped
/** Now idle.*/
| Idle

/** These are all the valid inputs.*/
type validInputs = [#something | #"needs-escaping" | #withPayload(int) | #status(status)]
Expand All @@ -55,8 +55,8 @@ module AnotherModule = {

/** Trying how it looks with an inline record in a variant. */
type someVariantWithInlineRecords =
| /** This has inline records...*/
SomeStuff({
/** This has inline records...*/
| SomeStuff({
offline: bool,
/** Is the user online? */
online?: bool,
Expand Down
Loading