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