1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
use Arc;
use Issue;
use cratePass2Driver;
use cratePhpVersion;
use *;
// S4 Step 1: analyze_file accumulators + tracked-query skeleton
//
// First step toward S4 (issues + reference locations as Salsa accumulators,
// `analyze_file` as a tracked query). This step is purely additive:
//
// 1. Defines `IssueAccumulator` and `RefLocAccumulator` salsa accumulator
// types — push targets for analyzer-emitted issues and reference-index
// entries during tracked-query evaluation.
// 2. Defines `analyze_file` as a tracked-query stub keyed on a
// `(SourceFile, AnalyzeFileInput)` pair. The stub does NOT perform
// analysis — it accumulates only the parse errors (a strict subset of
// what `collect_file_definitions` already produces, so semantics are
// unchanged). The full analyzer wiring follows in subsequent S4 PRs.
//
// Nothing in this module is wired into the batch (`analyze`) or LSP
// (`re_analyze_file`) paths yet. Behavior change: zero.
/// Salsa accumulator carrying analyzer-emitted issues. In the eventual
/// S4 design, every site that today calls `IssueBuffer::add` / `Vec::push`
/// from inside a tracked query will instead call
/// `IssueAccumulator(issue).accumulate(db)`, and `re_analyze_file` will read
/// the accumulated issues for the file with
/// `analyze_file::accumulated::<IssueAccumulator>(db, file, ...)`.
;
/// Reference-index entry as produced during analysis. Mirrors the tuple
/// shape that `Codebase::record_ref` accepts:
///
/// - `symbol_key`: interner-bound string (`"fn:foo"`, `"cls:Foo"`,
/// `"prop:Foo::$bar"`, `"cnst:Foo::BAR"`, `"meth:Foo::bar"` — same keys
/// `Codebase::mark_*_referenced_at` use).
/// - `file`: the file in which the reference appears.
/// - `(line, col_start, col_end)`: span within the file.
/// Salsa accumulator carrying reference-index entries. In the eventual
/// S4 design this replaces the `Codebase::mark_*_referenced_at` side
/// effects: instead of mutating the codebase's reference index inside a
/// tracked query (which Salsa cannot observe), the analyzer pushes
/// `RefLocAccumulator(loc)` and the consumer (LSP / dead-code) reads via
/// `analyze_file::accumulated::<RefLocAccumulator>(db, …)`.
;
/// Salsa tracked-query input for `analyze_file`. Carries the analysis
/// parameters that aren't already captured by `SourceFile` itself. Kept
/// minimal in this PR; subsequent PRs in the S4 chain will extend it as
/// the query body grows to call the full analyzer pipeline.
// S4 Step 3: Lazy inferred-type queries
//
// These tracked queries compute inferred return types on-demand during Pass 2.
// When `Pass2Driver` encounters a function/method call, it reads the inferred
// type via these queries instead of from a pre-computed buffer.
//
// This enables two key optimizations:
// 1. Single-pass execution: inferred types are computed as needed, not upfront
// 2. Incremental caching: if a dependent file doesn't call a function, its
// inferred type is never computed (Salsa skips the query)
// Helper: collect analysis results via tracked query accumulators
/// Collects all accumulated issues from a set of files analyzed via the
/// `analyze_file` tracked query. Used during batch analysis to read issues
/// that were emitted during tracked-query evaluation.
pub
/// Tracked-query skeleton for `analyze_file`.
///
/// **Current behavior (S4 step 2):** parses the file, emits parse-error issues,
/// and calls Pass 2 to analyze function/method bodies. Issues and reference
/// locations are emitted via `IssueAccumulator` and `RefLocAccumulator`.
///
/// This is still a hybrid: inferred types come from the prior
/// `run_inference_sweep` → `commit_inferred_return_types` in the double-pass
/// orchestration. Future S4 PRs will replace that with lazy
/// `inferred_return_type(node)` tracked queries.