Skip to main content

bynk_check/
recovery.rs

1//! #1663: diagnosing a file the strict parser rejects, for the CLI's
2//! single-file check. The editor's `bynk_ide::diagnose` follows the same rules
3//! (Decisions A and B) on its own recovering parse.
4
5use bynk_syntax::CompileError;
6use bynk_syntax::ast::SourceUnit;
7use bynk_syntax::lexer::Token;
8use bynk_syntax::parser;
9
10use crate::{checker, resolver};
11
12/// #1663: the diagnostics for a file the strict parser rejects with `strict` —
13/// that error, every other syntax error from a recovering parse, then the
14/// resolver's and checker's findings in the declarations that did parse. References to a declaration recovery had to
15/// skip are known names, not unknown ones (Decision B), and the checker's
16/// diagnostics in a declaration the resolver rejected are its echoes (Decision
17/// A); both are left out.
18pub fn diagnose_unparsable(
19    tokens: &[Token],
20    source: &str,
21    strict: Vec<CompileError>,
22) -> Vec<CompileError> {
23    let parser::Recovered {
24        units,
25        errors,
26        broken_decl_names,
27    } = parser::parse_units_recovering(tokens, source);
28    let (recovered, _warnings) = bynk_syntax::partition_by_severity(errors);
29    let mut out = parser::merge_syntax_errors(strict, recovered);
30    if let Some(SourceUnit::Commons(commons)) = units.into_iter().next() {
31        let item_spans: Vec<_> = commons.items.iter().map(|i| i.span()).collect();
32        let (resolved, resolve_errors) = resolver::resolve_recovering(commons);
33        let (shown, _hidden) =
34            resolver::split_broken_decl_echoes(resolve_errors.clone(), &broken_decl_names);
35        out.extend(shown);
36        if let Err(checked) = checker::check(resolved) {
37            let (checked, _warnings) = bynk_syntax::partition_by_severity(checked);
38            // #1710: the checker reports some echoes of a skipped declaration
39            // under its own codes (a method, a capability, an actor).
40            let checked = resolver::without_resolve_echoes(checked, &resolve_errors, &item_spans);
41            out.extend(resolver::split_broken_decl_echoes(checked, &broken_decl_names).0);
42        }
43    }
44    out
45}