Skip to content
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 @@ -26,6 +26,7 @@

#### :nail_care: Polish

- Represent explicit expression braces as `Pexp_braces` in parsetree v1 and format `else` branches consistently with `if` branches. https://github.com/rescript-lang/rescript/pull/8678
- Omit redundant braces around multi-statement switch case bodies when formatting. https://github.com/rescript-lang/rescript/pull/8677
- Avoid running `rescript-schema-ppx` and `sury-ppx` on source files without an `@schema` annotation. https://github.com/rescript-lang/rescript/pull/8662

Expand Down
7 changes: 4 additions & 3 deletions analysis/src/completion_expressions.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ let rec traverse_expr (exp : Parsetree.expression) ~expr_path ~pos
if loc_has_cursor exp.pexp_loc then Some v else None
in
match exp.pexp_desc with
| Pexp_ident {txt = Lident txt} when Utils.has_braces exp.pexp_attributes ->
(* An ident with braces attribute corresponds to for example `{n}`.
Looks like a record but is parsed as an ident with braces. *)
| Pexp_braces {expr = {pexp_desc = Pexp_ident {txt = Lident txt}}} ->
(* `{n}` looks like a record but contains an identifier. *)
some_if_has_cursor
(txt, [Completable.NRecordBody {seen_fields = []}] @ expr_path)
| Pexp_braces {expr} ->
traverse_expr expr ~expr_path ~pos ~first_char_before_cursor_no_white
| Pexp_ident {txt = Lident txt} -> some_if_has_cursor (txt, expr_path)
| Pexp_construct ({txt = Lident "()"}, _) -> some_if_has_cursor ("", expr_path)
| Pexp_construct ({txt = Lident txt}, {txt = []}) ->
Expand Down
52 changes: 33 additions & 19 deletions analysis/src/completion_front_end.ml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ let find_arg_completables ~(args : arg list) ~end_pos ~pos_before_cursor
let rec expr_to_context_path_inner ~(in_jsx_context : bool)
(e : Parsetree.expression) =
match e.pexp_desc with
| Pexp_braces {expr} -> expr_to_context_path_inner ~in_jsx_context expr
| Pexp_constant (Pconst_string _ | Pconst_json _ | Pconst_raw_source _) ->
Some Completable.CPString
| Pexp_template _ -> Some Completable.CPString
Expand Down Expand Up @@ -1152,6 +1153,31 @@ let completion_with_parser1 ~debug ~offset ~pos_cursor ~kind_file
in
typed_completion_expr expr;
match expr.pexp_desc with
| Pexp_braces {expr = {pexp_desc = Pexp_ident lid}} ->
if expr.pexp_loc |> Loc.has_pos ~pos:pos_no_white && !result = None then (
set_found ();
let lid_path = flatten_lid_check_dot lid in
if debug then
Printf.printf "Pexp_ident %s:%s\n"
(lid_path |> String.concat ".")
(Loc.to_string lid.loc);
if lid.loc |> Loc.has_pos ~pos:pos_before_cursor then
let is_likely_module_path =
match lid_path with
| head :: _ when String.length head > 0 ->
head.[0] == Char.uppercase_ascii head.[0]
| _ -> false
in
set_result
(Cpath
(CPId
{
loc = lid.loc;
path = lid_path;
completion_context =
(if is_likely_module_path then ValueOrField else Value);
})))
| Pexp_braces {expr = inner} -> iterator.expr iterator inner
Comment thread
cknitt marked this conversation as resolved.
| Pexp_match (expr, cases)
when cases <> []
&& loc_has_cursor expr.pexp_loc = false
Expand Down Expand Up @@ -1262,27 +1288,10 @@ let completion_with_parser1 ~debug ~offset ~pos_cursor ~kind_file
(lid_path |> String.concat ".")
(Loc.to_string lid.loc);
if lid.loc |> Loc.has_pos ~pos:pos_before_cursor then
let is_likely_module_path =
match lid_path with
| head :: _
when String.length head > 0
&& head.[0] == Char.uppercase_ascii head.[0] ->
true
| _ -> false
in
set_result
(Cpath
(CPId
{
loc = lid.loc;
path = lid_path;
completion_context =
(if
is_likely_module_path
&& expr |> Res_parsetree_viewer.is_braced_expr
then ValueOrField
else Value);
}))
{loc = lid.loc; path = lid_path; completion_context = Value}))
| Pexp_construct (lid, {txt = args; loc = args_loc}) -> (
let lid_path = flatten_lid_check_dot lid in
if debug then
Expand Down Expand Up @@ -1367,7 +1376,12 @@ let completion_with_parser1 ~debug ~offset ~pos_cursor ~kind_file
}
in
set_result (Cpath context_path)
else if Loc.end_ e.pexp_loc = pos_before_cursor then
else if
(match e.pexp_desc with
| Pexp_braces {braces_loc} -> Loc.end_ braces_loc
| _ -> Loc.end_ e.pexp_loc)
= pos_before_cursor
then
match expr_to_context_path ~in_jsx_context:!in_jsx_context e with
| Some context_path ->
set_result
Expand Down
4 changes: 1 addition & 3 deletions analysis/src/utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ let flatten_long_ident ?(jsx = false) ?(cut_at_offset = None) lid =

let identify_pexp pexp =
match pexp with
| Parsetree.Pexp_braces _ -> "Pexp_braces"
| Parsetree.Pexp_ident _ -> "Pexp_ident"
| Pexp_constant _ -> "Pexp_constant"
| Pexp_let _ -> "Pexp_let"
Expand Down Expand Up @@ -149,9 +150,6 @@ let rec skip_white text i =
| ' ' | '\n' | '\r' | '\t' -> skip_white text (i - 1)
| _ -> i

let has_braces attributes =
attributes |> List.exists (fun (loc, _) -> loc.Location.txt = "res.braces")

let rec unwrap_if_option (t : Types.type_expr) =
match t.desc with
| Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> unwrap_if_option t1
Expand Down
42 changes: 24 additions & 18 deletions analysis/src/xform.ml
Original file line number Diff line number Diff line change
Expand Up @@ -247,20 +247,6 @@ module Add_braces_to_fn = struct
current_structure_item := saved
in
let expr (iterator : Ast_iterator.iterator) (e : Parsetree.expression) =
let braces_attribute =
let loc =
{
Location.none with
loc_start = Lexing.dummy_pos;
loc_end =
{
Lexing.dummy_pos with
pos_lnum = Lexing.dummy_pos.pos_lnum + 1 (* force line break *);
};
}
in
(Location.mkloc "res.braces" loc, Parsetree.PStr [])
in
let is_function = function
| {Parsetree.pexp_desc = Pexp_fun _} -> true
| _ -> false
Expand All @@ -270,9 +256,8 @@ module Add_braces_to_fn = struct
when Loc.has_pos ~pos body_expr.pexp_loc
&& is_braced_expr body_expr = false
&& is_function body_expr = false ->
body_expr.pexp_attributes <-
braces_attribute :: body_expr.pexp_attributes;
changed := !current_structure_item
changed :=
Option.map (fun item -> (item, body_expr)) !current_structure_item
| _ -> ());
Ast_iterator.default_iterator.expr iterator e
in
Expand All @@ -285,7 +270,28 @@ module Add_braces_to_fn = struct
iterator.structure iterator structure;
match !changed with
| None -> ()
| Some new_structure_item ->
| Some (structure_item, body_expr) ->
let braces_loc =
{
Location.none with
loc_start = Lexing.dummy_pos;
loc_end =
{
Lexing.dummy_pos with
pos_lnum = Lexing.dummy_pos.pos_lnum + 1 (* force line break *);
};
}
in
let mapper =
{
Ast_mapper.default_mapper with
expr =
(fun mapper expr ->
if expr == body_expr then Ast_helper.Exp.braces ~braces_loc expr
else Ast_mapper.default_mapper.expr mapper expr);
}
in
let new_structure_item = mapper.structure_item mapper structure_item in
let range = Loc.range_of_loc new_structure_item.pstr_loc in
let new_text = print_structure_item ~range new_structure_item in
let code_action =
Expand Down
11 changes: 11 additions & 0 deletions compiler/frontend/ast_open_cxt.ml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type whole =
* Longident.t Asttypes.loc
* loc
* Parsetree.attributes)
| Braces of loc * loc * Parsetree.attributes

type t = whole list
type exp = Parsetree.expression
Expand All @@ -42,6 +43,9 @@ type destruct_output = exp list
let rec destruct_open_tuple (e : Parsetree.expression) (acc : t) :
(t * destruct_output * _) option =
match e.pexp_desc with
| Pexp_braces {expr; braces_loc} ->
destruct_open_tuple expr
(Braces (e.pexp_loc, braces_loc, e.pexp_attributes) :: acc)
| Pexp_open (flag, lid, cont) ->
destruct_open_tuple cont
(Let_open (flag, lid, e.pexp_loc, e.pexp_attributes) :: acc)
Expand All @@ -57,5 +61,12 @@ let restore_exp (xs : Parsetree.expression) (qualifiers : t) :
pexp_desc = Pexp_open (flag, lid, x);
pexp_attributes = attrs;
pexp_loc = loc;
}
: Parsetree.expression)
| Braces (loc, braces_loc, attrs) ->
({
pexp_desc = Pexp_braces {expr = x; braces_loc};
pexp_attributes = attrs;
pexp_loc = loc;
}
: Parsetree.expression))
1 change: 1 addition & 0 deletions compiler/frontend/bs_builtin_ppx.ml
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ let rec structure_mapper ~await_context (self : mapper) (stru : Ast_structure.t)
~typ:(Mty.typeof_ ~loc me)))
:: aux expr)
| Pexp_let (_, vbs, expr) -> aux expr @ spelunk_vbs acc vbs
| Pexp_braces {expr} -> aux expr
| Pexp_ifthenelse (_, then_expr, Some else_expr) ->
aux then_expr @ aux else_expr
| Pexp_construct (_, {txt = [expr]}) -> aux expr
Expand Down
2 changes: 2 additions & 0 deletions compiler/ml/ast_helper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ module Exp = struct
{pexp_desc = d; pexp_loc = loc; pexp_attributes = attrs}
let attr d a = {d with pexp_attributes = d.pexp_attributes @ [a]}

let braces ?(attrs = []) ~braces_loc e =
mk ~loc:e.pexp_loc ~attrs (Pexp_braces {expr = e; braces_loc})
let ident ?loc ?attrs a = mk ?loc ?attrs (Pexp_ident a)
let constant ?loc ?attrs a = mk ?loc ?attrs (Pexp_constant a)
let let_ ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_let (a, b, c))
Expand Down
1 change: 1 addition & 0 deletions compiler/ml/ast_helper.mli
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ module Exp : sig
val mk : ?loc:loc -> ?attrs:attrs -> expression_desc -> expression
val attr : expression -> attribute -> expression

val braces : ?attrs:attrs -> braces_loc:loc -> expression -> expression
val ident : ?loc:loc -> ?attrs:attrs -> lid -> expression
val constant : ?loc:loc -> ?attrs:attrs -> constant -> expression
val let_ :
Expand Down
3 changes: 3 additions & 0 deletions compiler/ml/ast_iterator.ml
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ module E = struct
sub.location sub loc;
sub.attributes sub attrs;
match desc with
| Pexp_braces {expr; braces_loc} ->
sub.location sub braces_loc;
sub.expr sub expr
| Pexp_ident x -> iter_loc sub x
| Pexp_constant _ -> ()
| Pexp_let (_r, vbs, e) ->
Expand Down
4 changes: 4 additions & 0 deletions compiler/ml/ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ module E = struct
let loc = sub.location sub loc in
let attrs = sub.attributes sub attrs in
match desc with
| Pexp_braces {expr; braces_loc} ->
braces
~braces_loc:(sub.location sub braces_loc)
~attrs (sub.expr sub expr)
| Pexp_ident x -> ident ~loc ~attrs (map_loc sub x)
| Pexp_constant x -> constant ~loc ~attrs x
| Pexp_let (r, vbs, e) ->
Expand Down
30 changes: 29 additions & 1 deletion compiler/ml/ast_mapper_from0.ml
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,36 @@ module E = struct
let has_jsx_attribute () =
attrs |> List.exists (fun ({txt}, _) -> txt = "JSX")
in
let first_wrapper =
let rec find = function
| ({txt = "res.braces" | "ns.braces"; loc}, _) :: _ ->
Some (`Braces loc)
| ({txt = "res.await"}, _) :: _ -> Some `Await
| _ :: rest -> find rest
| [] -> None
in
find e.pexp_attributes
in
match desc with
| _ when has_await_attribute attrs ->
| _
when match first_wrapper with
| Some (`Braces _) -> true
| _ -> false ->
let outer_attrs0, braces_loc, inner_attrs0 =
let rec split acc = function
| ({Location.txt = "res.braces" | "ns.braces"; loc}, _) :: rest ->
(List.rev acc, loc, rest)
| a :: rest -> split (a :: acc) rest
| [] -> assert false
in
split [] e.pexp_attributes
in
let inner = sub.expr sub {e with pexp_attributes = inner_attrs0} in
braces
~braces_loc:(sub.location sub braces_loc)
~attrs:(sub.attributes sub outer_attrs0)
inner
| _ when first_wrapper = Some `Await ->
(* [Ast_mapper_to0] merges the await node's attributes and the inner
expression's attributes into the one v0 slot, with [res.await] as
the boundary: await-node attributes before it, inner attributes
Expand Down
10 changes: 10 additions & 0 deletions compiler/ml/ast_mapper_to0.ml
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,16 @@ module E = struct
let is_ppx_context_string = has_ppx_context_string_attr attrs in
let attrs = sub.attributes sub (remove_ppx_context_string_attr attrs) in
match desc with
| Pexp_braces {expr; braces_loc} ->
let inner = sub.expr sub expr in
{
inner with
pexp_attributes =
attrs
@ ( Location.mkloc "res.braces" (sub.location sub braces_loc),
Pt.PStr [] )
:: inner.pexp_attributes;
}
| Pexp_ident x -> ident ~loc ~attrs (map_loc sub x)
| Pexp_constant (Pconst_string payload) when is_ppx_context_string ->
(* The PPX protocol predates source-preserving strings. Existing PPXs
Expand Down
1 change: 1 addition & 0 deletions compiler/ml/depend.ml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ let add_pattern bv pat =

let rec add_expr bv exp =
match exp.pexp_desc with
| Pexp_braces {expr = inner} -> add_expr bv inner
| Pexp_ident l -> add bv l
| Pexp_constant _ -> ()
| Pexp_let (rf, pel, e) ->
Expand Down
3 changes: 3 additions & 0 deletions compiler/ml/parsetree.ml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ and expression = {
}

and expression_desc =
| Pexp_braces of {expr: expression; braces_loc: Location.t}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Update editor binding classifiers for braced expressions

Introducing this wrapper changes every explicitly braced binding's top-level descriptor, but the editor classifiers still inspect that descriptor directly. For example, analysis/src/document_symbol.ml:18-21 now reports let f = {x => x} as a variable rather than a function, while analysis/src/hint.ml:120-129 omits its function code lens (and the analogous inlay-hint match also skips braced values). Unwrap Pexp_braces in these binding classifiers and add analysis coverage beyond completion.

AGENTS.md reference: AGENTS.md:L104-L109

Useful? React with 👍 / 👎.

(* Explicit braces around an expression. [pexp_loc] stays on the enclosed
expression; [braces_loc] covers the delimiters for printing. *)
Comment thread
cknitt marked this conversation as resolved.
| Pexp_ident of Longident.t loc (* x
M.x
*)
Expand Down
3 changes: 2 additions & 1 deletion compiler/ml/pprintast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ and expression ctxt f x =
| _ -> assert false
in
pp f "%a`%a`" (simple_expr ctxt) tag parts (raw_sources, values)
| Pexp_braces {expr = inner} -> pp f "{%a}" (expression ctxt) inner
| _ -> expression1 ctxt f x

and expression1 ctxt f x =
Expand Down Expand Up @@ -846,7 +847,7 @@ and simple_expr ctxt f x =
| Pexp_tuple l ->
pp f "@[<hov2>(%a)@]" (list (simple_expr ctxt) ~sep:",@;") l
| Pexp_constraint (e, ct) ->
pp f "(%a : %a)" (expression ctxt) e (core_type ctxt) ct
pp f "(%a :@ %a)" (expression ctxt) e (core_type ctxt) ct
| Pexp_coerce (e, (), ct) ->
pp f "(%a :> %a)" (expression ctxt) e (core_type ctxt) ct
| Pexp_variant (l, {txt = []}) -> pp f "`%s" l
Expand Down
4 changes: 4 additions & 0 deletions compiler/ml/printast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ and expression i ppf x =
attributes i ppf x.pexp_attributes;
let i = i + 1 in
match x.pexp_desc with
| Pexp_braces {expr = inner; braces_loc} ->
line i ppf "Pexp_braces\n";
line (i + 1) ppf "braces_loc %a\n" fmt_location braces_loc;
expression i ppf inner
| Pexp_ident li -> line i ppf "Pexp_ident %a\n" fmt_longident_loc li
| Pexp_object_literal fields ->
line i ppf "Pexp_object_literal\n";
Expand Down
Loading
Loading