Skip to main content

miden_assembly/linker/
errors.rs

1// Allow unused assignments - required by miette::Diagnostic derive macro
2#![allow(unused_assignments)]
3
4use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
5
6use miden_assembly_syntax::{
7    Felt, Path, Word,
8    ast::{SymbolResolutionError, constants::ConstEvalError},
9    debuginfo::{SourceFile, SourceSpan},
10    diagnostics::{Diagnostic, RelatedError, RelatedLabel, miette},
11};
12
13// LINKER ERROR
14// ================================================================================================
15
16/// An error which can be generated while linking modules and resolving procedure references.
17#[derive(Debug, thiserror::Error, Diagnostic)]
18#[non_exhaustive]
19pub enum LinkerError {
20    #[error("there are no modules to analyze")]
21    #[diagnostic()]
22    Empty,
23    #[error(transparent)]
24    #[diagnostic(transparent)]
25    SymbolResolution(#[from] Box<SymbolResolutionError>),
26    #[error(transparent)]
27    #[diagnostic(transparent)]
28    ConstEval(#[from] Box<ConstEvalError>),
29    #[error("linking failed")]
30    #[diagnostic(help("see diagnostics for details"))]
31    Related {
32        #[related]
33        errors: Box<[RelatedError]>,
34    },
35    #[error("linking failed")]
36    #[diagnostic(help("see diagnostics for details"))]
37    Failed {
38        #[related]
39        labels: Box<[RelatedLabel]>,
40    },
41    #[error("found a cycle in the call graph, involving these procedures: {}", nodes.join(", "))]
42    #[diagnostic()]
43    Cycle { nodes: Box<[String]> },
44    #[error("duplicate definition found for module '{path}'")]
45    #[diagnostic()]
46    DuplicateModule { path: Arc<Path> },
47    #[error("invalid module surface metadata for package '{package}': {reason}")]
48    #[diagnostic()]
49    InvalidPackageModuleSurface { package: String, reason: String },
50    #[error("ambiguous module path resolution for '{path}'")]
51    #[diagnostic(help("matching module prefixes: {}", matches.join(", ")))]
52    AmbiguousModulePath {
53        #[label]
54        span: SourceSpan,
55        #[source_code]
56        source_file: Option<Arc<SourceFile>>,
57        path: Arc<Path>,
58        matches: Box<[String]>,
59    },
60    #[error("undefined module '{path}'")]
61    #[diagnostic()]
62    UndefinedModule {
63        #[label]
64        span: SourceSpan,
65        #[source_code]
66        source_file: Option<Arc<SourceFile>>,
67        path: Arc<Path>,
68    },
69    #[error("private submodule '{module}'")]
70    #[diagnostic(help("only public submodules can be imported from another module"))]
71    PrivateSubmodule {
72        #[label("this submodule is private")]
73        span: SourceSpan,
74        #[source_code]
75        source_file: Option<Arc<SourceFile>>,
76        module: Arc<Path>,
77        #[related]
78        defined: Option<RelatedLabel>,
79    },
80    #[error(
81        "module '{path}' is not declared by its parent module '{parent}' as `mod {name}` or `pub mod {name}`"
82    )]
83    #[diagnostic(help(
84        "source modules must be declared by their parent module before they can be linked as descendants"
85    ))]
86    UndeclaredSubmodule {
87        path: Arc<Path>,
88        parent: Arc<Path>,
89        name: String,
90    },
91    #[error(
92        "name conflict in module '{module}': {kind} '{name}' conflicts with an existing item, import, or submodule"
93    )]
94    #[diagnostic()]
95    NamespaceNameConflict {
96        #[label("conflicting namespace member")]
97        span: SourceSpan,
98        #[source_code]
99        source_file: Option<Arc<SourceFile>>,
100        module: Arc<Path>,
101        name: String,
102        kind: &'static str,
103    },
104    #[error("modules cannot be re-exported with `pub use`: '{path}'")]
105    #[diagnostic(help(
106        "declare the module with `pub mod` in its parent module instead of re-exporting it"
107    ))]
108    ModuleReExport {
109        #[label("this `pub use` resolves to a module")]
110        span: SourceSpan,
111        #[source_code]
112        source_file: Option<Arc<SourceFile>>,
113        path: Arc<Path>,
114    },
115    #[error("module import target '{path}' resolved to an item")]
116    #[diagnostic(help(
117        "module-form imports must target modules; use `use {{item}} from module` for items"
118    ))]
119    InvalidModuleImportTarget {
120        #[label("this import expects a module target")]
121        span: SourceSpan,
122        #[source_code]
123        source_file: Option<Arc<SourceFile>>,
124        path: Arc<Path>,
125    },
126    #[error("item import target '{path}' resolved to a module")]
127    #[diagnostic(help("item-form imports may only import procedures, constants, or types"))]
128    InvalidItemImportTarget {
129        #[label("this import expects an item target")]
130        span: SourceSpan,
131        #[source_code]
132        source_file: Option<Arc<SourceFile>>,
133        path: Arc<Path>,
134    },
135    #[error("invalid re-export of kernel syscall '{path}'")]
136    #[diagnostic(help(
137        "re-export of kernel procedures is not permitted, except from the kernel root"
138    ))]
139    InvalidReExportOfKernelSyscall {
140        #[label("this import attempts to re-export a kernel syscall")]
141        span: SourceSpan,
142        #[source_code]
143        source_file: Option<Arc<SourceFile>>,
144        path: Arc<Path>,
145    },
146    #[error("import re-export cycle involving '{path}'")]
147    #[diagnostic(help("public item re-exports must not form cycles"))]
148    ImportReExportCycle {
149        #[label("this import participates in a re-export cycle")]
150        span: SourceSpan,
151        #[source_code]
152        source_file: Option<Arc<SourceFile>>,
153        path: Arc<Path>,
154    },
155    #[error("import target '{path}' cannot be resolved through import '{alias}'")]
156    #[diagnostic(help(
157        "imports are resolved independently; use the original global path instead of another import alias"
158    ))]
159    ImportTargetUsesImport {
160        #[label("this import target starts with another import alias")]
161        span: SourceSpan,
162        #[source_code]
163        source_file: Option<Arc<SourceFile>>,
164        path: Arc<Path>,
165        alias: String,
166    },
167    #[error("self-referential import of module '{path}'")]
168    #[diagnostic(help(
169        "a module cannot import itself; reference local items directly or use absolute paths in code"
170    ))]
171    SelfReferentialImport {
172        #[label("this import resolves to the module that contains it")]
173        span: SourceSpan,
174        #[source_code]
175        source_file: Option<Arc<SourceFile>>,
176        path: Arc<Path>,
177    },
178    #[error("cannot import submodule '{path}' declared in the same module")]
179    #[diagnostic(help(
180        "reference the submodule directly with a submodule-qualified path instead of importing it"
181    ))]
182    ImportTargetIsLocalSubmodule {
183        #[label("this import resolves to a submodule declared in the same scope")]
184        span: SourceSpan,
185        #[source_code]
186        source_file: Option<Arc<SourceFile>>,
187        path: Arc<Path>,
188    },
189    #[error("invalid relative item path '{path}'")]
190    #[diagnostic(help(
191        "item paths must be absolute, local, or qualified by an import or submodule in the current module"
192    ))]
193    InvalidRelativePath {
194        #[label("this path does not start with a local item, import, or submodule")]
195        span: SourceSpan,
196        #[source_code]
197        source_file: Option<Arc<SourceFile>>,
198        path: Arc<Path>,
199    },
200    #[error("undefined item '{path}'")]
201    #[diagnostic(help(
202        "you might be missing an import, or the containing library has not been linked"
203    ))]
204    UndefinedSymbol {
205        #[label]
206        span: SourceSpan,
207        #[source_code]
208        source_file: Option<Arc<SourceFile>>,
209        path: Arc<Path>,
210    },
211    #[error("invalid syscall: '{callee}' is not an exported kernel procedure")]
212    #[diagnostic()]
213    InvalidSysCallTarget {
214        #[label("call occurs here")]
215        span: SourceSpan,
216        #[source_code]
217        source_file: Option<Arc<SourceFile>>,
218        callee: Arc<Path>,
219    },
220    #[error("kernel procedure '{callee}' can only be invoked via syscall")]
221    #[diagnostic()]
222    KernelProcNotSyscall {
223        #[label("non-syscall reference to kernel procedure")]
224        span: SourceSpan,
225        #[source_code]
226        source_file: Option<Arc<SourceFile>>,
227        callee: Arc<Path>,
228    },
229    #[error("invalid procedure reference: path refers to a non-procedure item")]
230    #[diagnostic()]
231    InvalidInvokeTarget {
232        #[label("this path resolves to {path}, which is not a procedure")]
233        span: SourceSpan,
234        #[source_code]
235        source_file: Option<Arc<SourceFile>>,
236        path: Arc<Path>,
237    },
238    #[error("value for key {key} already present in the advice map")]
239    #[diagnostic(help(
240        "previous values at key were '{prev_values:?}'. Operation would have replaced them with '{new_values:?}'",
241    ))]
242    AdviceMapKeyAlreadyPresent {
243        key: Word,
244        prev_values: Vec<Felt>,
245        new_values: Vec<Felt>,
246    },
247    #[error("undefined type alias")]
248    #[diagnostic()]
249    UndefinedType {
250        #[label]
251        span: SourceSpan,
252        #[source_code]
253        source_file: Option<Arc<SourceFile>>,
254    },
255    #[error("invalid type reference")]
256    #[diagnostic(help("the item this path resolves to is not a type definition"))]
257    InvalidTypeRef {
258        #[label]
259        span: SourceSpan,
260        #[source_code]
261        source_file: Option<Arc<SourceFile>>,
262    },
263    #[error("invalid constant reference")]
264    #[diagnostic(help("the item this path resolves to is not a constant definition"))]
265    InvalidConstantRef {
266        #[label]
267        span: SourceSpan,
268        #[source_code]
269        source_file: Option<Arc<SourceFile>>,
270    },
271}
272
273impl From<SymbolResolutionError> for LinkerError {
274    #[inline]
275    fn from(value: SymbolResolutionError) -> Self {
276        Self::SymbolResolution(Box::new(value))
277    }
278}
279
280impl From<ConstEvalError> for LinkerError {
281    #[inline]
282    fn from(value: ConstEvalError) -> Self {
283        Self::ConstEval(Box::new(value))
284    }
285}