Skip to content

Commit 25ad75e

Browse files
authored
Version 12.2.0-rc.1 (#8229)
1 parent c895a20 commit 25ad75e

File tree

83 files changed

+1606
-248
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1606
-248
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ name: CI
22

33
on:
44
push:
5-
branches: [master, 11.0_release]
5+
branches: [master, maintenance/*]
66
# See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
77
tags:
88
- "v[0-9]+.[0-9]+.[0-9]+"
99
- "v[0-9]+.[0-9]+.[0-9]+-*"
1010

1111
pull_request:
12-
branches: [master, 11.0_release]
12+
branches: [master, maintenance/*]
1313

1414
concurrency:
1515
group: ci-${{ github.ref }}-1

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,32 @@
1010
> - :nail_care: [Polish]
1111
> - :house: [Internal]
1212
13+
# 12.2.0-rc.1
14+
15+
#### :boom: Breaking Change
16+
17+
- `js-post-build` now passes the correct output file path based on `in-source` configuration: when `in-source: true`, the path next to the source file is passed; when `in-source: false`, the path in the `lib/<module>/` directory is passed. Additionally, stdout and stderr from the post-build command are now logged. https://github.com/rescript-lang/rescript/pull/8190
18+
- `js-post-build` command now runs in the directory containing the `rescript.json` where it is defined, instead of the unpredictable build invocation directory. This provides consistent behavior in monorepos. https://github.com/rescript-lang/rescript/pull/8195
19+
20+
#### :rocket: New Feature
21+
22+
- Reanalyze: add scoped `@@live`/`@@dead` annotations for marking module/file sections as live or dead. https://github.com/rescript-lang/rescript/pull/8197
23+
24+
#### :bug: Bug fix
25+
26+
- Reanalyze: fix reactive/server stale results when cross-file references change without changing dead declarations (non-transitive mode). https://github.com/rescript-lang/rescript/pull/8173
27+
- Reanalyze: link record/variant label liveness across type re-exports (`type y = x = {...}`). https://github.com/rescript-lang/rescript/pull/8217
28+
- Add duplicate package detection to rewatch. https://github.com/rescript-lang/rescript/pull/8180
29+
- Rewatch: do not warn about "reanalyze" config field. https://github.com/rescript-lang/rescript/pull/8181
30+
- Fix error when importing CommonJS runtime modules with `require()`. https://github.com/rescript-lang/rescript/pull/8194
31+
- Rewatch: fix warnings from non-recompiled modules being lost during incremental builds in watch mode. https://github.com/rescript-lang/rescript/pull/8216
32+
33+
#### :nail_care: Polish
34+
35+
- Formatter no longer writes files when contents are already correctly formatted. https://github.com/rescript-lang/rescript/pull/8209
36+
- Build system: Only log verbose "Generating AST for module" when actually parsing. https://github.com/rescript-lang/rescript/pull/8210
37+
- Build system: Watch only source folders from build state instead of the entire project directory, and report missing configured source folders. https://github.com/rescript-lang/rescript/pull/8219
38+
1339
# 12.1.0
1440

1541
#### :rocket: New Feature

analysis/reanalyze/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ rescript-tools reanalyze -config -reactive -timing -runs 3
6060
| `-churn n` | Remove/re-add n random files between runs (incremental correctness/perf testing) |
6161
| `-timing` | Report timing of analysis phases |
6262
| `-mermaid` | Output Mermaid diagram of reactive pipeline (to stderr) |
63+
| `-transitive` | Force transitive reporting (overrides rescript.json) |
64+
| `-no-transitive` | Disable transitive reporting (overrides rescript.json) |
6365
| `-debug` | Print debug information |
6466
| `-json` | Output in JSON format |
6567
| `-ci` | Internal flag for CI mode |
@@ -68,6 +70,18 @@ rescript-tools reanalyze -config -reactive -timing -runs 3
6870

6971
See [ARCHITECTURE.md](ARCHITECTURE.md) for details on the analysis pipeline.
7072

73+
### Regenerating the checked-in reactive pipeline diagram
74+
75+
`analysis/reanalyze/diagrams/reactive-pipeline-full.mmd` is generated from the live reactive graph printer (`Reactive.to_mermaid()`), and **we check in the non-transitive (`-no-transitive`) variant** because that is where cross-file `hasRefBelow` suppression is relevant (and where reactive invalidation bugs are easiest to spot).
76+
77+
To regenerate it:
78+
79+
```bash
80+
# Run from any ReScript project (so -config works), then capture stderr:
81+
rescript-tools reanalyze -config -reactive -no-transitive -mermaid \
82+
>/dev/null 2> analysis/reanalyze/diagrams/reactive-pipeline-full.mmd
83+
```
84+
7185
The DCE analysis is structured as a pure pipeline:
7286

7387
1. **MAP** - Process each `.cmt` file independently → per-file data

analysis/reanalyze/diagrams/reactive-pipeline-full.mmd

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ graph TD
2525
solver.live_decls[solver.live_decls]
2626
type_deps.impl_decls[type_deps.impl_decls]
2727
liveness.all_roots[liveness.all_roots]
28-
solver.dead_modules[solver.dead_modules]
2928
liveness.external_type_refs[liveness.external_type_refs]
3029
decl_refs.combined[decl_refs.combined]
3130
type_refs_from[type_refs_from]
@@ -34,20 +33,20 @@ graph TD
3433
liveness.external_value_refs[liveness.external_value_refs]
3534
liveness.value_refs_from[liveness.value_refs_from]
3635
value_refs_from[value_refs_from]
37-
solver.modules_with_dead[solver.modules_with_dead]
3836
solver.dead_decls[solver.dead_decls]
3937
exception_refs_collection[exception_refs_collection]
4038
type_deps.intf_decls[type_deps.intf_decls]
4139
file_data_collection[file_data_collection]
4240
solver.dead_module_issues[solver.dead_module_issues]
4341
decl_refs.with_type_refs[decl_refs.with_type_refs]
44-
solver.modules_with_live[solver.modules_with_live]
4542
decl_refs.type_decl_refs[decl_refs.type_decl_refs]
4643
files[files]
4744
solver.modules_with_reported[solver.modules_with_reported]
4845
liveness.externally_referenced[liveness.externally_referenced]
4946
liveness.edges[liveness.edges]
47+
solver.refs_token[solver.refs_token]
5048
liveness.live[liveness.live]
49+
solver.dead_modules_empty[solver.dead_modules_empty]
5150
decls[decls]
5251
type_deps.intf_to_impl_refs_join{join}
5352
liveness.external_value_refs_join{join}
@@ -57,7 +56,6 @@ graph TD
5756
exc_refs.resolved_refs_join{join}
5857
type_deps.combined_refs_to_union{union}
5958
liveness.externally_referenced_union{union}
60-
solver.dead_modules_join{join}
6159
liveness.all_roots_union{union}
6260
solver.dead_module_issues_join{join}
6361
solver.dead_decls_join{join}
@@ -68,6 +66,7 @@ graph TD
6866
decl_refs.with_value_refs_join{join}
6967
liveness.type_refs_from_union{union}
7068
type_deps.impl_needing_path2_join{join}
69+
solver.issues_by_file_join{join}
7170
liveness.external_type_refs_join{join}
7271
liveness.live_fp{fixpoint}
7372
decl_refs.type_decl_refs_join{join}
@@ -103,24 +102,22 @@ graph TD
103102
type_deps.decl_by_path -->|flatMap| type_deps.same_path_refs
104103
type_deps.u2 --> type_deps.combined_refs_to_union
105104
solver.live_decls --> solver.incorrect_dead_decls_join
106-
solver.live_decls -->|flatMap| solver.modules_with_live
107105
type_deps.impl_decls --> type_deps.impl_needing_path2_join
108106
type_deps.impl_decls --> type_deps.impl_to_intf_refs_join
109107
liveness.all_roots --> liveness.live_fp
110-
solver.dead_modules --> solver.dead_module_issues_join
111108
liveness.external_type_refs --> liveness.externally_referenced_union
112109
decl_refs.combined -->|flatMap| liveness.edges
113110
type_refs_from --> liveness.type_refs_from_union
114111
liveness.type_refs_from --> liveness.external_type_refs_join
115112
liveness.type_refs_from --> decl_refs.type_decl_refs_join
116-
solver.dead_decls_by_file -->|flatMap| solver.issues_by_file
113+
solver.dead_decls_by_file --> solver.issues_by_file_join
117114
liveness.external_value_refs --> liveness.externally_referenced_union
118115
liveness.value_refs_from --> liveness.external_value_refs_join
119116
liveness.value_refs_from --> decl_refs.value_decl_refs_join
117+
value_refs_from -->|flatMap| solver.refs_token
120118
value_refs_from --> liveness.value_refs_from_union
121-
solver.modules_with_dead --> solver.dead_modules_join
122119
solver.dead_decls -->|flatMap| solver.dead_decls_by_file
123-
solver.dead_decls -->|flatMap| solver.modules_with_dead
120+
solver.dead_decls -->|flatMap| solver.dead_modules_empty
124121
exception_refs_collection --> exc_refs.resolved_refs_join
125122
type_deps.intf_decls --> type_deps.intf_to_impl_refs_join
126123
file_data_collection -->|flatMap| files
@@ -131,13 +128,14 @@ graph TD
131128
file_data_collection -->|flatMap| annotations
132129
file_data_collection -->|flatMap| decls
133130
decl_refs.with_type_refs --> decl_refs.combined_join
134-
solver.modules_with_live --> solver.dead_modules_join
135131
decl_refs.type_decl_refs --> decl_refs.with_type_refs_join
136132
solver.modules_with_reported --> solver.dead_module_issues_join
137133
liveness.externally_referenced --> liveness.all_roots_union
138134
liveness.edges --> liveness.live_fp
135+
solver.refs_token --> solver.issues_by_file_join
139136
liveness.live --> solver.live_decls_join
140137
liveness.live --> solver.dead_decls_join
138+
solver.dead_modules_empty --> solver.dead_module_issues_join
141139
decls --> solver.live_decls_join
142140
decls --> solver.dead_decls_join
143141
decls --> liveness.annotated_roots_join
@@ -158,7 +156,6 @@ graph TD
158156
exc_refs.resolved_refs_join --> exc_refs.resolved_refs
159157
type_deps.combined_refs_to_union --> type_deps.combined_refs_to
160158
liveness.externally_referenced_union --> liveness.externally_referenced
161-
solver.dead_modules_join --> solver.dead_modules
162159
liveness.all_roots_union --> liveness.all_roots
163160
solver.dead_module_issues_join --> solver.dead_module_issues
164161
solver.dead_decls_join --> solver.dead_decls
@@ -169,6 +166,7 @@ graph TD
169166
decl_refs.with_value_refs_join --> decl_refs.with_value_refs
170167
liveness.type_refs_from_union --> liveness.type_refs_from
171168
type_deps.impl_needing_path2_join --> type_deps.impl_needing_path2
169+
solver.issues_by_file_join --> solver.issues_by_file
172170
liveness.external_type_refs_join --> liveness.external_type_refs
173171
liveness.live_fp --> liveness.live
174172
decl_refs.type_decl_refs_join --> decl_refs.type_decl_refs
@@ -180,7 +178,7 @@ graph TD
180178
classDef joinClass fill:#e6f3ff,stroke:#0066cc
181179
classDef unionClass fill:#fff0e6,stroke:#cc6600
182180
classDef fixpointClass fill:#e6ffe6,stroke:#006600
183-
class decl_refs.with_type_refs_join,decl_refs.combined_join,decl_refs.type_decl_refs_join,liveness.external_type_refs_join,type_deps.impl_needing_path2_join,decl_refs.with_value_refs_join,solver.live_decls_join,type_deps.impl_to_intf_refs_join,decl_refs.value_decl_refs_join,liveness.annotated_roots_join,solver.dead_decls_join,solver.dead_module_issues_join,solver.dead_modules_join,exc_refs.resolved_refs_join,solver.incorrect_dead_decls_join,type_deps.impl_to_intf_refs_path2_join,liveness.external_value_refs_join,type_deps.intf_to_impl_refs_join joinClass
181+
class decl_refs.with_type_refs_join,decl_refs.combined_join,decl_refs.type_decl_refs_join,liveness.external_type_refs_join,solver.issues_by_file_join,type_deps.impl_needing_path2_join,decl_refs.with_value_refs_join,solver.live_decls_join,type_deps.impl_to_intf_refs_join,decl_refs.value_decl_refs_join,liveness.annotated_roots_join,solver.dead_decls_join,solver.dead_module_issues_join,exc_refs.resolved_refs_join,solver.incorrect_dead_decls_join,type_deps.impl_to_intf_refs_path2_join,liveness.external_value_refs_join,type_deps.intf_to_impl_refs_join joinClass
184182
class type_deps.u1_union,type_deps.u2_union,liveness.type_refs_from_union,liveness.all_roots_union,liveness.externally_referenced_union,type_deps.combined_refs_to_union,liveness.value_refs_from_union unionClass
185183
class liveness.live_fp fixpointClass
186184

analysis/reanalyze/src/CollectAnnotations.ml

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@
55

66
open DeadCommon
77

8-
let processAttributes ~state ~config ~doGenType ~name ~pos attributes =
8+
type scope_default = FileAnnotations.annotated_as option
9+
10+
let processAttributes ~(scope_default : scope_default) ~state ~config ~doGenType
11+
~name ~pos attributes =
12+
(match scope_default with
13+
| Some FileAnnotations.Live -> FileAnnotations.annotate_live state pos
14+
| Some FileAnnotations.Dead -> FileAnnotations.annotate_dead state pos
15+
| Some FileAnnotations.GenType -> FileAnnotations.annotate_gentype state pos
16+
| None -> ());
917
let getPayloadFun f = attributes |> Annotation.getAttributePayload f in
1018
let getPayload (x : string) =
1119
attributes |> Annotation.getAttributePayload (( = ) x)
@@ -39,15 +47,29 @@ let processAttributes ~state ~config ~doGenType ~name ~pos attributes =
3947
let collectExportLocations ~state ~config ~doGenType =
4048
let super = Tast_mapper.default in
4149
let currentlyDisableWarnings = ref false in
50+
let currentScopeDefault : scope_default ref = ref None in
51+
52+
let scopeDefaultFromToplevelAttribute (attribute : Parsetree.attribute) :
53+
scope_default =
54+
let attrs = [attribute] in
55+
let getPayload (x : string) =
56+
attrs |> Annotation.getAttributePayload (( = ) x)
57+
in
58+
if getPayload "dead" <> None then Some FileAnnotations.Dead
59+
else if getPayload "live" <> None then Some FileAnnotations.Live
60+
else if getPayload "genType" <> None then Some FileAnnotations.GenType
61+
else None
62+
in
63+
4264
let value_binding self
4365
({vb_attributes; vb_pat} as value_binding : Typedtree.value_binding) =
4466
(match vb_pat.pat_desc with
4567
| Tpat_var (id, {loc = {loc_start = pos}})
4668
| Tpat_alias ({pat_desc = Tpat_any}, id, {loc = {loc_start = pos}}) ->
4769
if !currentlyDisableWarnings then FileAnnotations.annotate_live state pos;
4870
vb_attributes
49-
|> processAttributes ~state ~config ~doGenType ~name:(id |> Ident.name)
50-
~pos
71+
|> processAttributes ~scope_default:!currentScopeDefault ~state ~config
72+
~doGenType ~name:(id |> Ident.name) ~pos
5173
| _ -> ());
5274
super.value_binding self value_binding
5375
in
@@ -58,8 +80,8 @@ let collectExportLocations ~state ~config ~doGenType =
5880
|> List.iter
5981
(fun ({ld_attributes; ld_loc} : Typedtree.label_declaration) ->
6082
toplevelAttrs @ ld_attributes
61-
|> processAttributes ~state ~config ~doGenType:false ~name:""
62-
~pos:ld_loc.loc_start)
83+
|> processAttributes ~scope_default:!currentScopeDefault ~state
84+
~config ~doGenType:false ~name:"" ~pos:ld_loc.loc_start)
6385
| Ttype_variant constructorDeclarations ->
6486
constructorDeclarations
6587
|> List.iter
@@ -74,14 +96,15 @@ let collectExportLocations ~state ~config ~doGenType =
7496
(fun ({ld_attributes; ld_loc} : Typedtree.label_declaration)
7597
->
7698
toplevelAttrs @ cd_attributes @ ld_attributes
77-
|> processAttributes ~state ~config ~doGenType:false
78-
~name:"" ~pos:ld_loc.loc_start)
99+
|> processAttributes ~scope_default:!currentScopeDefault
100+
~state ~config ~doGenType:false ~name:""
101+
~pos:ld_loc.loc_start)
79102
flds
80103
| Cstr_tuple _ -> ()
81104
in
82105
toplevelAttrs @ cd_attributes
83-
|> processAttributes ~state ~config ~doGenType:false ~name:""
84-
~pos:cd_loc.loc_start)
106+
|> processAttributes ~scope_default:!currentScopeDefault ~state
107+
~config ~doGenType:false ~name:"" ~pos:cd_loc.loc_start)
85108
| _ -> ());
86109
super.type_kind self typeKind
87110
in
@@ -96,36 +119,46 @@ let collectExportLocations ~state ~config ~doGenType =
96119
Typedtree.value_description) =
97120
if !currentlyDisableWarnings then FileAnnotations.annotate_live state pos;
98121
val_attributes
99-
|> processAttributes ~state ~config ~doGenType ~name:(val_id |> Ident.name)
100-
~pos;
122+
|> processAttributes ~scope_default:!currentScopeDefault ~state ~config
123+
~doGenType ~name:(val_id |> Ident.name) ~pos;
101124
super.value_description self value_description
102125
in
103126
let structure_item self (item : Typedtree.structure_item) =
104127
(match item.str_desc with
105-
| Tstr_attribute attribute
106-
when [attribute] |> Annotation.isOcamlSuppressDeadWarning ->
107-
currentlyDisableWarnings := true
128+
| Tstr_attribute attribute -> (
129+
match scopeDefaultFromToplevelAttribute attribute with
130+
| Some _ as newDefault -> currentScopeDefault := newDefault
131+
| None ->
132+
if [attribute] |> Annotation.isOcamlSuppressDeadWarning then
133+
currentlyDisableWarnings := true)
108134
| _ -> ());
109135
super.structure_item self item
110136
in
111137
let structure self (structure : Typedtree.structure) =
112138
let oldDisableWarnings = !currentlyDisableWarnings in
139+
let oldScopeDefault = !currentScopeDefault in
113140
super.structure self structure |> ignore;
114141
currentlyDisableWarnings := oldDisableWarnings;
142+
currentScopeDefault := oldScopeDefault;
115143
structure
116144
in
117145
let signature_item self (item : Typedtree.signature_item) =
118146
(match item.sig_desc with
119-
| Tsig_attribute attribute
120-
when [attribute] |> Annotation.isOcamlSuppressDeadWarning ->
121-
currentlyDisableWarnings := true
147+
| Tsig_attribute attribute -> (
148+
match scopeDefaultFromToplevelAttribute attribute with
149+
| Some _ as newDefault -> currentScopeDefault := newDefault
150+
| None ->
151+
if [attribute] |> Annotation.isOcamlSuppressDeadWarning then
152+
currentlyDisableWarnings := true)
122153
| _ -> ());
123154
super.signature_item self item
124155
in
125156
let signature self (signature : Typedtree.signature) =
126157
let oldDisableWarnings = !currentlyDisableWarnings in
158+
let oldScopeDefault = !currentScopeDefault in
127159
super.signature self signature |> ignore;
128160
currentlyDisableWarnings := oldDisableWarnings;
161+
currentScopeDefault := oldScopeDefault;
129162
signature
130163
in
131164
{

analysis/reanalyze/src/DeadCommon.ml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ module FileContext = struct
44
(** Get module name as Name.t tagged with interface/implementation info *)
55
let module_name_tagged file =
66
file.module_name |> Name.create ~isInterface:file.is_interface
7+
8+
let isInterface (file : t) = file.is_interface
79
end
810

911
(* Adapted from https://github.com/LexiFi/dead_code_analyzer *)
@@ -82,7 +84,7 @@ let addValueReference ~config ~refs ~file_deps ~(binding : Location.t)
8284

8385
let addDeclaration_ ~config ~decls ~(file : FileContext.t) ?posEnd ?posStart
8486
~declKind ~path ~(loc : Location.t) ?(posAdjustment = Decl.Nothing)
85-
~moduleLoc (name : Name.t) =
87+
?manifestTypePath ~moduleLoc (name : Name.t) =
8688
let pos = loc.loc_start in
8789
let posStart =
8890
match posStart with
@@ -110,6 +112,7 @@ let addDeclaration_ ~config ~decls ~(file : FileContext.t) ?posEnd ?posStart
110112
moduleLoc;
111113
posAdjustment;
112114
path = name :: path;
115+
manifestTypePath;
113116
pos;
114117
posEnd;
115118
posStart;
@@ -182,6 +185,16 @@ let reportDeclaration ~config ~hasRefBelow ?checkModuleDead ?shouldReport
182185
| Some f -> f decl
183186
| None -> decl.report
184187
in
188+
(* For type re-exports (type y = x = {...}), the re-exported record/variant
189+
labels are restated but not independently actionable. Avoid duplicate/noisy
190+
warnings by suppressing reporting for the re-exported copy. *)
191+
let should_report =
192+
should_report
193+
&&
194+
match (decl.declKind, decl.manifestTypePath) with
195+
| (RecordLabel | VariantCase), Some _ -> false
196+
| _ -> true
197+
in
185198
if not should_report then []
186199
else
187200
let deadWarning, message =

0 commit comments

Comments
 (0)