1#![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#[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}