rukalang/modules/error.rs
1use thiserror::Error;
2
3use crate::syntax::{self, ast::SourceSpan};
4
5/// Module resolution error produced while loading imports.
6#[derive(Debug, Error)]
7pub enum ModuleError {
8 /// Imported module failed to parse.
9 #[error("failed to parse module `{module}` from {source}: {error}")]
10 Parse {
11 /// Logical module name requested by the importer.
12 module: String,
13 /// Source file path where parsing failed.
14 source: String,
15 /// Underlying syntax error from parsing.
16 #[source]
17 error: syntax::SyntaxError,
18 },
19 /// Imported module path could not be resolved.
20 #[error(
21 "module `{module}` imported from `{from}` at {source_name}:{span} was not found at {path}"
22 )]
23 NotFound {
24 /// Logical module name requested by the importer.
25 module: String,
26 /// Module containing the import statement.
27 from: String,
28 /// Candidate filesystem path that was attempted.
29 path: String,
30 /// Source file where the import appears.
31 source_name: String,
32 /// Span of the import clause.
33 span: SourceSpan,
34 },
35 /// Cyclic import chain was detected.
36 #[error("cyclic module import detected at {source_name}:{span}: {cycle}")]
37 ImportCycle {
38 /// Human-readable cycle path.
39 cycle: String,
40 /// Source file where cycle detection surfaced.
41 source_name: String,
42 /// Span of the triggering import.
43 span: SourceSpan,
44 },
45 /// The same import name was declared twice in one module.
46 #[error(
47 "duplicate import `{import}` in module `{module}` at {source_name}:{duplicate_span}; first declared at {first_span}"
48 )]
49 DuplicateImport {
50 /// Module containing the duplicate import.
51 module: String,
52 /// Duplicate imported module name.
53 import: String,
54 /// Source file where the duplicate appears.
55 source_name: String,
56 /// Span of the first import declaration.
57 first_span: SourceSpan,
58 /// Span of the second import declaration.
59 duplicate_span: SourceSpan,
60 },
61 /// Browser import violated static-import restrictions.
62 #[error(
63 "web playground only supports static import `{allowed}`; found `{found}` at {source_name}:{span}"
64 )]
65 BrowserStaticImportUnsupported {
66 /// Required static import path.
67 allowed: String,
68 /// Import path found in source.
69 found: String,
70 /// Source file containing the unsupported import.
71 source_name: String,
72 /// Span of the unsupported import.
73 span: SourceSpan,
74 },
75 /// Reading a module file from disk failed.
76 #[error("failed to read module file {path}: {error}")]
77 Io {
78 /// Filesystem path that failed to read.
79 path: String,
80 /// Underlying I/O error.
81 #[source]
82 error: std::io::Error,
83 },
84}
85
86impl ModuleError {
87 /// Return the primary diagnostic line/column when one is available.
88 pub fn diagnostic_line_column(&self) -> Option<(usize, usize)> {
89 match self {
90 Self::NotFound { span, .. } => Some((span.start.line, span.start.column)),
91 Self::ImportCycle { span, .. } => Some((span.start.line, span.start.column)),
92 Self::DuplicateImport { duplicate_span, .. } => {
93 Some((duplicate_span.start.line, duplicate_span.start.column))
94 }
95 Self::BrowserStaticImportUnsupported { span, .. } => {
96 Some((span.start.line, span.start.column))
97 }
98 Self::Parse { .. } | Self::Io { .. } => None,
99 }
100 }
101}