Skip to content

Commit 46012ef

Browse files
committed
Optimize hasRefBelow to use per-file refs
hasRefBelow only checks refs from the same file as the declaration. Now we group refs by source file (value_refs_from_by_file) and only scan refs from the declaration's file. Complexity per dead decl: O(file_refs) instead of O(total_refs) All 380/19000 issues still match between reactive and non-reactive modes.
1 parent c25272c commit 46012ef

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

analysis/reanalyze/src/ReactiveSolver.ml

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,14 @@
77
- dead_decls, live_decls = decls partitioned by liveness (reactive join)
88
- dead_modules = modules with dead decls but no live decls (reactive anti-join)
99
- dead_decls_by_file = dead decls grouped by file (reactive flatMap with merge)
10+
- value_refs_from_by_file = refs grouped by source file (reactive flatMap with merge)
1011
- issues_by_file = per-file issue generation (reactive flatMap)
1112
- is_pos_live uses reactive live collection (no resolvedDead mutation)
1213
- shouldReport callback replaces report field mutation (no mutation needed)
1314
- isInsideReportedValue is per-file only, so files are independent
15+
- hasRefBelow uses per-file refs: O(file_refs) per dead decl (was O(total_refs))
1416
- Module issues generated in collect_issues from dead_modules + modules_with_reported_values
1517
16-
TODO for further optimization:
17-
- hasRefBelow: uses O(total_refs) linear scan of refs_from per dead decl;
18-
could use reactive refs_to index for O(1) lookup per decl
19-
2018
All issues now match between reactive and non-reactive modes (380 on deadcode test):
2119
- Dead code issues: 362 (Exception:2, Module:31, Type:87, Value:233, ValueWithSideEffects:8)
2220
- Incorrect @dead: 1
@@ -108,20 +106,26 @@ let create ~(decls : (Lexing.position, Decl.t) Reactive.t)
108106
()
109107
in
110108

111-
(* hasRefBelow callback - captured once, uses current state of value_refs_from *)
109+
(* Reactive per-file grouping of value refs (for hasRefBelow optimization) *)
112110
let transitive = config.DceConfig.run.transitive in
113-
let hasRefBelow =
111+
let value_refs_from_by_file =
114112
match value_refs_from with
115-
| None -> fun _ -> false
113+
| None -> None
116114
| Some refs_from ->
117-
DeadCommon.make_hasRefBelow ~transitive ~iter_value_refs_from:(fun f ->
118-
Reactive.iter f refs_from)
115+
Some (
116+
Reactive.flatMap refs_from
117+
~f:(fun posFrom posToSet -> [(posFrom.Lexing.pos_fname, [(posFrom, posToSet)])])
118+
~merge:(fun refs1 refs2 -> refs1 @ refs2)
119+
()
120+
)
119121
in
120122

121123
(* Reactive per-file issues - recomputed when dead_decls_by_file changes.
122124
Returns (file, (value_issues, modules_with_reported_values)) where
123125
modules_with_reported_values are modules that have at least one reported dead value.
124-
Module issues are generated separately in collect_issues using dead_modules. *)
126+
Module issues are generated separately in collect_issues using dead_modules.
127+
128+
hasRefBelow now uses per-file refs: O(file_refs) instead of O(total_refs). *)
125129
let issues_by_file =
126130
Reactive.flatMap dead_decls_by_file
127131
~f:(fun file decls ->
@@ -140,6 +144,23 @@ let create ~(decls : (Lexing.position, Decl.t) Reactive.t)
140144
Hashtbl.replace modules_with_values moduleName ();
141145
None (* Module issues generated separately *)
142146
in
147+
(* Per-file hasRefBelow: only scan refs from this file *)
148+
let hasRefBelow =
149+
if transitive then fun _ -> false
150+
else
151+
match value_refs_from_by_file with
152+
| None -> fun _ -> false
153+
| Some refs_by_file ->
154+
let file_refs = Reactive.get refs_by_file file in
155+
fun decl ->
156+
match file_refs with
157+
| None -> false
158+
| Some refs_list ->
159+
List.exists (fun (posFrom, posToSet) ->
160+
PosSet.mem decl.Decl.pos posToSet &&
161+
DeadCommon.refIsBelow decl posFrom
162+
) refs_list
163+
in
143164
(* Sort within file and generate issues *)
144165
let sorted = decls |> List.fast_sort Decl.compareForReporting in
145166
let reporting_ctx = DeadCommon.ReportingContext.create () in

0 commit comments

Comments
 (0)