Skip to content

Commit 23fc6cc

Browse files
Fix loss of LOC during AST0 translation (#8350)
* Fix loss of LOC during AST0 translation * Changelog * Format and completion test updates * Fix build
1 parent b91c862 commit 23fc6cc

15 files changed

Lines changed: 235 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
- Fix partial application generalization for `...`. https://github.com/rescript-lang/rescript/pull/8343
2626

27+
- Preserve JSX prop locations across the AST0 translation layer, fixing `0:0` editor diagnostics in PPX-related flows. https://github.com/rescript-lang/rescript/pull/8350
28+
2729
#### :memo: Documentation
2830

2931
#### :nail_care: Polish

analysis/src/CompletionBackEnd.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2154,7 +2154,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
21542154
Sys.readdir (Filename.dirname (env.file.uri |> Uri.toPath))
21552155
|> Array.to_list
21562156
in
2157-
(* Try to filter out compiled in source files *)
2157+
(* Filter out generated build artifacts from in-source builds. *)
21582158
let resFiles =
21592159
StringSet.of_list
21602160
(files
@@ -2163,6 +2163,10 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
21632163
Some (try Filename.chop_extension f with _ -> f)
21642164
else None))
21652165
in
2166+
let is_internal_artifact_extension = function
2167+
| ".ast" | ".cmi" | ".cmj" | ".cmt" | ".cmti" | ".iast" -> true
2168+
| _ -> false
2169+
in
21662170
files
21672171
|> List.filter_map (fun fileName ->
21682172
let withoutExtension =
@@ -2175,6 +2179,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
21752179
else
21762180
match Filename.extension fileName with
21772181
| ".res" | ".resi" | "" -> None
2182+
| ext when is_internal_artifact_extension ext -> None
21782183
| _ -> Some ("./" ^ fileName))
21792184
|> List.sort String.compare
21802185
with _ ->

compiler/bsc/rescript_compiler_main.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ let command_line_flags : (string * Bsc_args.spec * string) array =
268268
Js_config.binary_ast := true;
269269
Js_config.syntax_only := true),
270270
"*internal* Generate binary .mli_ast and ml_ast and stop" );
271+
( "-bs-test-ast-conversion",
272+
set Js_config.test_ast_conversion,
273+
"*internal* Roundtrip the parsed AST through Parsetree0 before continuing"
274+
);
271275
( "-bs-syntax-only",
272276
set Js_config.syntax_only,
273277
"*internal* Only check syntax" );

compiler/common/js_config.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ let check_div_by_zero = ref true
4343
let get_check_div_by_zero () = !check_div_by_zero
4444
let syntax_only = ref false
4545
let binary_ast = ref false
46+
let test_ast_conversion = ref false
4647
let debug = ref false
4748
let cmi_only = ref false
4849
let cmj_only = ref false

compiler/common/js_config.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ val syntax_only : bool ref
6565

6666
val binary_ast : bool ref
6767

68+
val test_ast_conversion : bool ref
69+
6870
val debug : bool ref
6971

7072
val cmi_only : bool ref

compiler/common/ml_binary.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ let ast0_to_signature : ast0 -> Parsetree.signature = function
5252
Ast_mapper_from0.default_mapper.signature Ast_mapper_from0.default_mapper
5353
sig0
5454

55+
let ast0_roundtrip : type a. a kind -> a -> a =
56+
fun kind ast ->
57+
match kind with
58+
| Ml -> ast |> to_ast0 Ml |> ast0_to_structure
59+
| Mli -> ast |> to_ast0 Mli |> ast0_to_signature
60+
5561
let magic_of_kind : type a. a kind -> string = function
5662
| Ml -> Config.ast_impl_magic_number
5763
| Mli -> Config.ast_intf_magic_number

compiler/common/ml_binary.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ type ast0 = Impl of Parsetree0.structure | Intf of Parsetree0.signature
3232
val magic_of_kind : 'a kind -> string
3333
val magic_of_ast0 : ast0 -> string
3434
val to_ast0 : 'a kind -> 'a -> ast0
35+
val ast0_roundtrip : 'a kind -> 'a -> 'a
3536
val ast0_to_structure : ast0 -> Parsetree.structure
3637
val ast0_to_signature : ast0 -> Parsetree.signature

compiler/core/cmd_ppx_apply.ml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ let rewrite kind ppxs ast =
9595

9696
let apply_rewriters_str ?(restore = true) ~tool_name ast =
9797
match !Clflags.all_ppx with
98-
| [] -> ast
98+
| [] ->
99+
if !Js_config.test_ast_conversion then
100+
Ml_binary.ast0_roundtrip Ml_binary.Ml ast
101+
else ast
99102
| ppxs ->
100103
ast
101104
|> Ast_mapper.add_ppx_context_str ~tool_name
@@ -104,7 +107,10 @@ let apply_rewriters_str ?(restore = true) ~tool_name ast =
104107

105108
let apply_rewriters_sig ?(restore = true) ~tool_name ast =
106109
match !Clflags.all_ppx with
107-
| [] -> ast
110+
| [] ->
111+
if !Js_config.test_ast_conversion then
112+
Ml_binary.ast0_roundtrip Ml_binary.Mli ast
113+
else ast
108114
| ppxs ->
109115
ast
110116
|> Ast_mapper.add_ppx_context_sig ~tool_name

compiler/ml/ast_mapper_from0.ml

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ open Ast_helper
2525
open Location
2626
module Pt = Parsetree
2727

28+
let jsx_prop_loc_attr = "res.jsxPropLoc"
29+
let jsx_spread_loc_attr = "res.jsxSpreadLoc"
30+
31+
let extract_internal_loc_attr attr_name attrs =
32+
let rec loop rev_acc = function
33+
| [] -> (None, List.rev rev_acc)
34+
| (({txt; loc}, payload) as attr) :: rest ->
35+
if txt = attr_name && payload = PStr [] then
36+
(Some loc, List.rev_append rev_acc rest)
37+
else loop (attr :: rev_acc) rest
38+
in
39+
loop [] attrs
40+
2841
type mapper = {
2942
attribute: mapper -> attribute -> Pt.attribute;
3043
attributes: mapper -> attribute list -> Pt.attribute list;
@@ -331,9 +344,22 @@ module E = struct
331344

332345
let try_map_jsx_prop (sub : mapper) (lbl : Asttypes.Noloc.arg_label)
333346
(e : expression) : Parsetree.jsx_prop option =
347+
let map_expr_with_loc_attr attr_name fallback make_prop =
348+
let loc, attrs = extract_internal_loc_attr attr_name e.pexp_attributes in
349+
let e = {e with pexp_attributes = attrs} in
350+
let expr = sub.expr sub e in
351+
make_prop
352+
(match loc with
353+
| Some loc -> loc
354+
| None -> fallback expr)
355+
expr
356+
in
334357
match (lbl, e) with
335-
| Asttypes.Noloc.Labelled "_spreadProps", expr ->
336-
Some (Parsetree.JSXPropSpreading (Location.none, sub.expr sub expr))
358+
| Asttypes.Noloc.Labelled "_spreadProps", _expr ->
359+
Some
360+
(map_expr_with_loc_attr jsx_spread_loc_attr
361+
(fun expr -> expr.pexp_loc)
362+
(fun loc expr -> Parsetree.JSXPropSpreading (loc, expr)))
337363
| ( Asttypes.Noloc.Labelled name,
338364
{pexp_desc = Pexp_ident {txt = Longident.Lident v}; pexp_loc = name_loc}
339365
)
@@ -344,14 +370,18 @@ module E = struct
344370
)
345371
when name = v ->
346372
Some (Parsetree.JSXPropPunning (true, {txt = name; loc = name_loc}))
347-
| Asttypes.Noloc.Labelled name, exp ->
373+
| Asttypes.Noloc.Labelled name, _exp ->
348374
Some
349-
(Parsetree.JSXPropValue
350-
({txt = name; loc = Location.none}, false, sub.expr sub exp))
351-
| Asttypes.Noloc.Optional name, exp ->
375+
(map_expr_with_loc_attr jsx_prop_loc_attr
376+
(fun expr -> expr.pexp_loc)
377+
(fun loc expr ->
378+
Parsetree.JSXPropValue ({txt = name; loc}, false, expr)))
379+
| Asttypes.Noloc.Optional name, _exp ->
352380
Some
353-
(Parsetree.JSXPropValue
354-
({txt = name; loc = Location.none}, true, sub.expr sub exp))
381+
(map_expr_with_loc_attr jsx_prop_loc_attr
382+
(fun expr -> expr.pexp_loc)
383+
(fun loc expr ->
384+
Parsetree.JSXPropValue ({txt = name; loc}, true, expr)))
355385
| _ -> None
356386

357387
let extract_props_and_children (sub : mapper) items =

compiler/ml/ast_mapper_to0.ml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ open Ast_helper0
2525
open Location
2626
module Pt = Parsetree0
2727

28+
let jsx_prop_loc_attr = "res.jsxPropLoc"
29+
let jsx_spread_loc_attr = "res.jsxSpreadLoc"
30+
31+
let wrap_with_loc_attr attr_name loc (expr : Pt.expression) =
32+
let attr : Pt.attribute = (Location.mkloc attr_name loc, Pt.PStr []) in
33+
{expr with pexp_attributes = attr :: expr.pexp_attributes}
34+
2835
type mapper = {
2936
attribute: mapper -> attribute -> Pt.attribute;
3037
attributes: mapper -> attribute list -> Pt.attribute list;
@@ -334,9 +341,12 @@ module E = struct
334341
if is_optional then Asttypes.Noloc.Optional name.txt
335342
else Asttypes.Noloc.Labelled name.txt
336343
in
337-
(label, sub.expr sub value)
338-
| JSXPropSpreading (_, value) ->
339-
(Asttypes.Noloc.Labelled "_spreadProps", sub.expr sub value))
344+
( label,
345+
sub.expr sub value |> wrap_with_loc_attr jsx_prop_loc_attr name.loc
346+
)
347+
| JSXPropSpreading (loc, value) ->
348+
( Asttypes.Noloc.Labelled "_spreadProps",
349+
sub.expr sub value |> wrap_with_loc_attr jsx_spread_loc_attr loc ))
340350

341351
let map_jsx_children sub loc children =
342352
match children with

0 commit comments

Comments
 (0)