From 61cb1203a78fe4bc73f2f0460bb3a4179b40f897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 22 Aug 2025 15:16:34 +0200 Subject: [PATCH 1/6] Don't emit tokens for Belt.Array.concatMany generated by array spread --- analysis/src/SemanticTokens.ml | 19 +++++++++++++------ .../not_compiled/SemanticTokensArray.res | 3 +++ .../expected/SemanticTokensArray.res.txt | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 tests/analysis_tests/tests/not_compiled/SemanticTokensArray.res create mode 100644 tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArray.res.txt diff --git a/analysis/src/SemanticTokens.ml b/analysis/src/SemanticTokens.ml index ad22221186..8291f51a0e 100644 --- a/analysis/src/SemanticTokens.ml +++ b/analysis/src/SemanticTokens.ml @@ -247,12 +247,19 @@ let command ~debug ~emitter ~path = match e.pexp_desc with | Pexp_ident {txt = lid; loc} -> if lid <> Lident "not" then - if not loc.loc_ghost then - emitter - |> emitLongident ~pos:(Loc.start loc) - ~posEnd:(Some (Loc.end_ loc)) - ~lid ~debug; - Ast_iterator.default_iterator.expr iterator e + if not loc.loc_ghost then ( + let should_emit = + match lid with + (* Array spreads (`...`) are converted to `Belt.Array.concatMany` *) + | Ldot (Ldot (Lident "Belt", "Array"), "concatMany") -> false + | _ -> true + in + if should_emit then + emitter + |> emitLongident ~pos:(Loc.start loc) + ~posEnd:(Some (Loc.end_ loc)) + ~lid ~debug; + Ast_iterator.default_iterator.expr iterator e) | Pexp_jsx_element (Jsx_unary_element {jsx_unary_element_tag_name = lident}) -> (* diff --git a/tests/analysis_tests/tests/not_compiled/SemanticTokensArray.res b/tests/analysis_tests/tests/not_compiled/SemanticTokensArray.res new file mode 100644 index 0000000000..3e172fa30e --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/SemanticTokensArray.res @@ -0,0 +1,3 @@ +let xs = [1, 2] +let ys = [...xs, 3] +//^sem diff --git a/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArray.res.txt b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArray.res.txt new file mode 100644 index 0000000000..92a36a9961 --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArray.res.txt @@ -0,0 +1 @@ +{"data":[0,4,2,1,0,1,4,2,1,0,0,9,2,1,0]} From 9da507ac44aac905f4721ce4a0a831de0be86469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 22 Aug 2025 15:21:35 +0200 Subject: [PATCH 2/6] Don't emit tokens for Primitive_dict.make generated by dict literal syntax --- analysis/src/SemanticTokens.ml | 3 +++ tests/analysis_tests/tests/not_compiled/SemanticTokensDict.res | 2 ++ .../tests/not_compiled/expected/SemanticTokensDict.res.txt | 1 + 3 files changed, 6 insertions(+) create mode 100644 tests/analysis_tests/tests/not_compiled/SemanticTokensDict.res create mode 100644 tests/analysis_tests/tests/not_compiled/expected/SemanticTokensDict.res.txt diff --git a/analysis/src/SemanticTokens.ml b/analysis/src/SemanticTokens.ml index 8291f51a0e..950dad6cbf 100644 --- a/analysis/src/SemanticTokens.ml +++ b/analysis/src/SemanticTokens.ml @@ -252,6 +252,9 @@ let command ~debug ~emitter ~path = match lid with (* Array spreads (`...`) are converted to `Belt.Array.concatMany` *) | Ldot (Ldot (Lident "Belt", "Array"), "concatMany") -> false + (* Dict syntax (`dict{...}`) is converted to `Primitive_dict.make` *) + | Ldot (Lident "Primitive_dict", "make") -> false + | Lident "Primitive_dict" -> false | _ -> true in if should_emit then diff --git a/tests/analysis_tests/tests/not_compiled/SemanticTokensDict.res b/tests/analysis_tests/tests/not_compiled/SemanticTokensDict.res new file mode 100644 index 0000000000..529b636667 --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/SemanticTokensDict.res @@ -0,0 +1,2 @@ +let d = dict{"foo": bar} +//^sem diff --git a/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensDict.res.txt b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensDict.res.txt new file mode 100644 index 0000000000..747a90d8b3 --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensDict.res.txt @@ -0,0 +1 @@ +{"data":[0,4,1,1,0,0,16,3,1,0]} From 1e2062abe6dc7f49783a33521cc6065ac9fe55fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 22 Aug 2025 15:29:38 +0200 Subject: [PATCH 3/6] Don't emit tokens for Array.get generated by array access syntax --- analysis/src/SemanticTokens.ml | 2 ++ .../tests/not_compiled/SemanticTokensArrayAccess.res | 3 +++ .../not_compiled/expected/SemanticTokensArrayAccess.res.txt | 1 + 3 files changed, 6 insertions(+) create mode 100644 tests/analysis_tests/tests/not_compiled/SemanticTokensArrayAccess.res create mode 100644 tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayAccess.res.txt diff --git a/analysis/src/SemanticTokens.ml b/analysis/src/SemanticTokens.ml index 950dad6cbf..a9a610f0c6 100644 --- a/analysis/src/SemanticTokens.ml +++ b/analysis/src/SemanticTokens.ml @@ -255,6 +255,8 @@ let command ~debug ~emitter ~path = (* Dict syntax (`dict{...}`) is converted to `Primitive_dict.make` *) | Ldot (Lident "Primitive_dict", "make") -> false | Lident "Primitive_dict" -> false + (* Array access (`arr[index]`) is converted to `Array.get` *) + | Ldot (Lident "Array", "get") -> false | _ -> true in if should_emit then diff --git a/tests/analysis_tests/tests/not_compiled/SemanticTokensArrayAccess.res b/tests/analysis_tests/tests/not_compiled/SemanticTokensArrayAccess.res new file mode 100644 index 0000000000..64e62244cc --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/SemanticTokensArrayAccess.res @@ -0,0 +1,3 @@ +let x = xs[0] +let x = xs[index] +//^sem diff --git a/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayAccess.res.txt b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayAccess.res.txt new file mode 100644 index 0000000000..858e9ef372 --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayAccess.res.txt @@ -0,0 +1 @@ +{"data":[0,4,1,1,0,0,4,2,1,0,1,4,1,1,0,0,4,2,1,0,0,3,5,1,0]} From 3b5a5819baacfd49a0b2c36e8d8c966b9190b909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 22 Aug 2025 16:04:43 +0200 Subject: [PATCH 4/6] Output semantic tokens for direct usage of Belt.Array.concatMany --- analysis/src/SemanticTokens.ml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/analysis/src/SemanticTokens.ml b/analysis/src/SemanticTokens.ml index a9a610f0c6..bceaa88beb 100644 --- a/analysis/src/SemanticTokens.ml +++ b/analysis/src/SemanticTokens.ml @@ -248,10 +248,16 @@ let command ~debug ~emitter ~path = | Pexp_ident {txt = lid; loc} -> if lid <> Lident "not" then if not loc.loc_ghost then ( + (* Don't emit semantic tokens for identifiers not present in source code *) let should_emit = match lid with - (* Array spreads (`...`) are converted to `Belt.Array.concatMany` *) - | Ldot (Ldot (Lident "Belt", "Array"), "concatMany") -> false + (* Array spread (`...`) is converted to `Belt.Array.concatMany` with `@res.spread` decorator *) + | Ldot (Ldot (Lident "Belt", "Array"), "concatMany") -> + let has_spread_attr = + e.pexp_attributes + |> List.exists (fun ({Location.txt}, _) -> txt = "res.spread") + in + not has_spread_attr (* Dict syntax (`dict{...}`) is converted to `Primitive_dict.make` *) | Ldot (Lident "Primitive_dict", "make") -> false | Lident "Primitive_dict" -> false From 8072798f529938c6a0b7e5041626f2b5ace7ec4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Fri, 22 Aug 2025 16:14:18 +0200 Subject: [PATCH 5/6] Don't emit tokens for Array.set generated by array mutation syntax --- analysis/src/SemanticTokens.ml | 2 ++ .../tests/not_compiled/SemanticTokensArrayMutation.res | 2 ++ .../not_compiled/expected/SemanticTokensArrayMutation.res.txt | 1 + 3 files changed, 5 insertions(+) create mode 100644 tests/analysis_tests/tests/not_compiled/SemanticTokensArrayMutation.res create mode 100644 tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayMutation.res.txt diff --git a/analysis/src/SemanticTokens.ml b/analysis/src/SemanticTokens.ml index bceaa88beb..7868f01cd1 100644 --- a/analysis/src/SemanticTokens.ml +++ b/analysis/src/SemanticTokens.ml @@ -263,6 +263,8 @@ let command ~debug ~emitter ~path = | Lident "Primitive_dict" -> false (* Array access (`arr[index]`) is converted to `Array.get` *) | Ldot (Lident "Array", "get") -> false + (* Array mutation (`arr[index]`) is converted to `Array.set` *) + | Ldot (Lident "Array", "set") -> false | _ -> true in if should_emit then diff --git a/tests/analysis_tests/tests/not_compiled/SemanticTokensArrayMutation.res b/tests/analysis_tests/tests/not_compiled/SemanticTokensArrayMutation.res new file mode 100644 index 0000000000..e195ab10b6 --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/SemanticTokensArrayMutation.res @@ -0,0 +1,2 @@ +xs[0] = 42 +//^sem diff --git a/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayMutation.res.txt b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayMutation.res.txt new file mode 100644 index 0000000000..4d3810f43b --- /dev/null +++ b/tests/analysis_tests/tests/not_compiled/expected/SemanticTokensArrayMutation.res.txt @@ -0,0 +1 @@ +{"data":[0,0,2,1,0]} From da945fd760f087ac4ea3116e3f249902694cdd38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9di-R=C3=A9mi=20Hashim?= Date: Sun, 24 Aug 2025 01:18:44 +0200 Subject: [PATCH 6/6] Add CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4355c3866d..406201f006 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ #### :bug: Bug fix +- Fix semantic highlighting for array spreads, array access and dict literals. https://github.com/rescript-lang/rescript/pull/7789 - Preserve `@as(...)` decorator on record fields when creating interface. https://github.com/rescript-lang/rescript/pull/7779 - Fix parse error with nested record types and attributes on the field name that has the nested record type. https://github.com/rescript-lang/rescript/pull/7781 - Fix ppx resolution with package inside monorepo. https://github.com/rescript-lang/rescript/pull/7776