1use assura_parser::ast::{SourceFile, Span};
4
5use crate::imports::ResolvedImport;
6use crate::symbols::SymbolTable;
7
8#[derive(Debug, Clone)]
10pub struct ResolutionError {
11 pub code: assura_diagnostics::ErrorCode,
12 pub message: String,
13 pub span: Span,
14 pub secondary: Option<(Span, String)>,
16 pub suggestion: Option<String>,
18}
19
20impl From<ResolutionError> for assura_diagnostics::Diagnostic {
21 fn from(e: ResolutionError) -> Self {
22 let error_span = e.span.clone();
23 let mut d = assura_diagnostics::Diagnostic::error(e.code, e.message, e.span);
24 if let Some((span, label)) = e.secondary {
25 d.secondary.push(assura_diagnostics::SecondaryLabel {
26 span,
27 message: label,
28 });
29 }
30 if let Some(hint) = e.suggestion {
31 d = d.with_suggestion(hint, error_span, String::new());
32 }
33 d
34 }
35}
36
37#[derive(Debug, Clone)]
40pub struct ResolvedFile {
41 pub source: SourceFile,
42 pub symbols: SymbolTable,
43 pub imports: Vec<ResolvedImport>,
45 pub warnings: Vec<ResolutionError>,
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn resolution_error_to_diagnostic() {
56 let err = ResolutionError {
57 code: "A02001".into(),
58 message: "undefined name `x`".into(),
59 span: 0..5,
60 secondary: None,
61 suggestion: Some("did you mean `y`?".into()),
62 };
63 let diag: assura_diagnostics::Diagnostic = err.into();
64 assert_eq!(diag.code, "A02001");
65 assert!(diag.message.contains("undefined name `x`"));
66 }
67
68 #[test]
69 fn resolution_error_with_secondary() {
70 let err = ResolutionError {
71 code: "A02003".into(),
72 message: "duplicate name `x`".into(),
73 span: 10..15,
74 secondary: Some((0..5, "previously defined here".into())),
75 suggestion: None,
76 };
77 let diag: assura_diagnostics::Diagnostic = err.into();
78 assert_eq!(diag.secondary.len(), 1);
79 assert!(diag.secondary[0].message.contains("previously defined"));
80 }
81}