Skip to main content

bynk_emit/project/
diagnostics.rs

1use super::*;
2
3/// Internal: do the work, given a source root (for commons/contexts) and a
4/// test root (for test units). When both roots are the same path the
5/// behaviour is identical to the v0.4+ single-tree layout. When they differ
6/// — v0.9.1's split-paths mode — sources and tests are discovered separately
7/// and the new `inconsistent_test_path` check fires.
8/// v0.24 (ADR 0052): how the project pipeline is driven. `Build` preserves
9/// the CLI contract exactly (bail at the structural and pre-emit gates);
10/// `Analyse` never bails after discovery, skips all emission, and lets
11/// independent unit groups resolve/check past another group's errors.
12#[derive(Clone, Copy, PartialEq, Eq)]
13pub(crate) enum Mode {
14    Build,
15    Analyse,
16}
17
18/// v0.24 (ADR 0052): a compile error attributed — where possible — to the
19/// project-relative source file it belongs to, tagged at the collection
20/// point (the phase that produced it knows which file it was processing).
21/// `None` is the project-level bucket: validations spanning files
22/// (group/cycle/directory consistency) with no single owning file.
23pub struct AttributedError {
24    pub source_path: Option<PathBuf>,
25    pub error: CompileError,
26}
27
28/// Collection-point error sink (ADR 0052). Helpers keep their plain
29/// `&mut Vec<CompileError>` signatures; call sites attribute via
30/// `extend_for` with the file in scope at that point.
31pub(crate) struct ErrorSink {
32    entries: Vec<AttributedError>,
33    /// v0.89 (ADR 0117): non-failing warnings, classified on push by
34    /// `Severity::for_error`. Kept apart so `is_empty`/`len` — the build-failure
35    /// gates — stay errors-only, while every warning source (commons-fn checks,
36    /// service/agent handler validation, parser) is captured uniformly.
37    warnings: Vec<AttributedError>,
38}
39
40impl ErrorSink {
41    pub(crate) fn new() -> Self {
42        Self {
43            entries: Vec::new(),
44            warnings: Vec::new(),
45        }
46    }
47    pub(crate) fn push_for(&mut self, file: Option<&Path>, error: CompileError) {
48        let attributed = AttributedError {
49            source_path: file.map(Path::to_path_buf),
50            error,
51        };
52        match bynk_syntax::Severity::for_error(&attributed.error) {
53            bynk_syntax::Severity::Warning => self.warnings.push(attributed),
54            bynk_syntax::Severity::Error => self.entries.push(attributed),
55        }
56    }
57    pub(crate) fn extend_for(
58        &mut self,
59        file: Option<&Path>,
60        errs: impl IntoIterator<Item = CompileError>,
61    ) {
62        for e in errs {
63            self.push_for(file, e);
64        }
65    }
66    /// True when no **error-severity** diagnostic has been collected — the
67    /// build-failure gate. Warnings do not count (ADR 0117).
68    pub(crate) fn is_empty(&self) -> bool {
69        self.entries.is_empty()
70    }
71    /// Consume the sink, yielding the non-failing **warnings** (ADR 0117).
72    pub(crate) fn into_warnings(self) -> Vec<AttributedError> {
73        self.warnings
74    }
75    /// Consume the sink, yielding errors then warnings — the full diagnostic
76    /// list the LSP and a failed build render together.
77    pub(crate) fn into_all(self) -> Vec<AttributedError> {
78        let mut all = self.entries;
79        all.extend(self.warnings);
80        all
81    }
82    /// The count of **error-severity** diagnostics.
83    pub(crate) fn len(&self) -> usize {
84        self.entries.len()
85    }
86}
87
88/// v0.24: the analyse-mode result — every discovered file's analysed text
89/// snapshot (positions must convert against the text that was analysed,
90/// not a newer buffer) plus the attributed diagnostics.
91pub struct ProjectAnalysis {
92    /// `(project-relative source path, analysed text)` for every file read,
93    /// including clean files (the LSP needs them to clear diagnostics).
94    pub snapshots: Vec<(PathBuf, String)>,
95    pub errors: Vec<AttributedError>,
96    /// v0.25 (ADR 0053): the project-wide binding index. Empty when the
97    /// pipeline bails before resolution (discovery/parse failures).
98    pub index: ProjectIndex,
99    /// v0.27 (ADR 0056): per-file inferred-type inlay hints — `(binding-name
100    /// span, label)`, span-ordered, harvested from the checker's binding
101    /// sites. Empty for files the pipeline never type-checked.
102    pub hints: FileHints,
103    /// v0.30.2 (ADR 0063): per-file expression types — `(expr span, Ty)`,
104    /// captured on the Ok path (a file that checks clean), for `.`-member
105    /// completion's receiver typing. Empty for files with errors (the
106    /// clean-file ceiling) and for synthetic files.
107    pub expr_types: FileExprTypes,
108    /// v0.31 (ADR 0064): per-file local bindings with their scope ranges —
109    /// `let`/`let <-`, fn/handler/lambda params — for the scope-at-offset
110    /// query backing locals completion + navigation. Synthetic files muted.
111    pub locals: FileLocals,
112    /// v0.99: per-file capability-requirement ledger — every capability-consuming
113    /// site (direct call, store op), covered or not, with its provenance. Drives
114    /// the ghost `given` inlay hint and capability hover. Empty for files the
115    /// pipeline never type-checked, and for synthetic/test files (muted).
116    pub requirements: FileRequirements,
117    /// Slice 6b (ADR 0095): qualified unit name → the project source file(s)
118    /// that comprise it, in discovery order — the unit→file map backing document
119    /// links and consumed-context navigation. Excludes synthetic (toolchain-
120    /// injected) units; empty when the pipeline bails before the checker.
121    pub unit_sources: HashMap<String, Vec<PathBuf>>,
122}
123
124/// v0.24: a failed build with its attribution and snapshots intact — what
125/// the CLI renders rich (ariadne source context per file); the plain
126/// `compile_project*` wrappers flatten it to the pre-v0.24 error list.
127pub struct ProjectFailure {
128    pub errors: Vec<AttributedError>,
129    pub snapshots: Vec<(PathBuf, String)>,
130}
131
132impl ProjectFailure {
133    /// The pre-v0.24 contract: collection-ordered, attribution dropped.
134    pub fn flatten(self) -> Vec<CompileError> {
135        self.errors.into_iter().map(|a| a.error).collect()
136    }
137}