miden_assembly_syntax/sema/
errors.rs1#![allow(unused_assignments)]
3
4use alloc::{boxed::Box, sync::Arc, vec::Vec};
5use core::fmt;
6
7use miden_debug_types::{SourceFile, SourceSpan};
8use miden_utils_diagnostics::{Diagnostic, miette};
9
10use crate::{
11 Path,
12 ast::{SymbolResolutionError, constants::ConstEvalError},
13};
14
15#[derive(Debug, thiserror::Error, Diagnostic)]
26#[error("syntax error")]
27#[diagnostic(help("see emitted diagnostics for details"))]
28pub struct SyntaxError {
29 #[source_code]
30 pub source_file: Arc<SourceFile>,
31 #[related]
32 pub errors: Vec<SemanticAnalysisError>,
33}
34
35#[derive(Debug, thiserror::Error, Diagnostic)]
41#[error("one or more warnings were emitted")]
42#[diagnostic(help("see below for details"))]
43#[cfg_attr(not(feature = "std"), expect(unused))]
44pub struct SyntaxWarning {
45 #[source_code]
46 pub source_file: Arc<SourceFile>,
47 #[related]
48 pub errors: Vec<SemanticAnalysisError>,
49}
50
51#[derive(Clone, Copy)]
53pub enum ExportedTypeUse {
54 ProcedureSignature,
55 TypeDeclaration,
56}
57
58impl ExportedTypeUse {
59 pub fn private_type_error(
60 self,
61 span: SourceSpan,
62 defined: SourceSpan,
63 ) -> SemanticAnalysisError {
64 match self {
65 Self::ProcedureSignature => {
66 SemanticAnalysisError::PrivateTypeInExportedSignature { span, defined }
67 },
68 Self::TypeDeclaration => {
69 SemanticAnalysisError::PrivateTypeInExportedType { span, defined }
70 },
71 }
72 }
73}
74
75#[derive(Debug, thiserror::Error, Diagnostic)]
77pub enum SemanticAnalysisError {
78 #[error(
79 "conflicting module namespace specification: expected '{expected}', but got '{actual}'"
80 )]
81 NamespaceConflict {
82 expected: Arc<Path>,
83 actual: Arc<Path>,
84 #[label("this declaration conflicts with the expected namespace")]
85 span: SourceSpan,
86 },
87 #[error("invalid namespace '{path}': {err}")]
88 InvalidNamespacePath { path: Arc<Path>, err: crate::PathError },
89 #[error("invalid namespace declaration: must be placed before any other item in the module")]
90 MisplacedNamespaceDeclaration {
91 #[label("make sure this declaration precedes other declarations in this module")]
92 span: SourceSpan,
93 },
94 #[error("invalid module: no namespace declared or explicitly provided")]
95 #[diagnostic(help(
96 "ensure you declare this module's namespace with a `namespace` declaration, or by providing it to the parser"
97 ))]
98 MissingNamespace,
99 #[error("invalid program: no entrypoint defined")]
100 #[diagnostic(help(
101 "ensure you define an entrypoint somewhere in the body with `begin`..`end`"
102 ))]
103 MissingEntrypoint,
104 #[error("invalid module: unexpected entrypoint definition")]
105 #[diagnostic(help("library modules cannot contain `begin`..`end` blocks"))]
106 UnexpectedEntrypoint {
107 #[label]
108 span: SourceSpan,
109 },
110 #[error("invalid module: multiple conflicting entrypoints defined")]
111 #[diagnostic(help("an executable module can only have a single `begin`..`end` block"))]
112 MultipleEntrypoints {
113 #[label]
114 span: SourceSpan,
115 #[label]
116 prev_span: SourceSpan,
117 },
118 #[error("invalid invocation target")]
119 #[diagnostic(help("path contains an invalid component"))]
120 InvalidInvokePath {
121 #[label]
122 span: SourceSpan,
123 },
124 #[error("invalid program: procedure exports are not allowed")]
125 #[diagnostic(help("perhaps you meant to use `proc` instead of `export`?"))]
126 UnexpectedExport {
127 #[label]
128 span: SourceSpan,
129 },
130 #[error("invalid enum type representation: underlying type must be an integral or felt type")]
131 #[diagnostic()]
132 InvalidEnumRepr {
133 #[label]
134 span: SourceSpan,
135 },
136 #[error("invalid enum discriminant: value is not a valid instance of the {repr} type")]
137 #[diagnostic()]
138 InvalidEnumDiscriminant {
139 #[label]
140 span: SourceSpan,
141 repr: crate::ast::types::Type,
142 },
143 #[error("invalid enum discriminant: value conflicts with another variant of the same enum")]
144 #[diagnostic()]
145 EnumDiscriminantConflict {
146 #[label("this discriminant value conflicts with a previous variant")]
147 span: SourceSpan,
148 #[label("discriminant previously observed here")]
149 prev: SourceSpan,
150 },
151 #[error("symbol conflict: found duplicate definitions of the same name")]
152 #[diagnostic()]
153 SymbolConflict {
154 #[label("conflict occurs here")]
155 span: SourceSpan,
156 #[label("previously defined here")]
157 prev_span: SourceSpan,
158 },
159 #[error("dependency conflict: found duplicate 'extern package' declarations")]
160 #[diagnostic()]
161 ExternPackageConflict {
162 #[label("conflict occurs here")]
163 span: SourceSpan,
164 #[label("previously defined here")]
165 prev_span: SourceSpan,
166 },
167 #[error("private type in exported procedure signature")]
168 #[diagnostic(help(
169 "exported procedure signatures may only reference public types, including nested type dependencies"
170 ))]
171 PrivateTypeInExportedSignature {
172 #[label("this exported procedure signature references a private type")]
173 span: SourceSpan,
174 #[label("this type is private")]
175 defined: SourceSpan,
176 },
177 #[error("private type in exported type declaration")]
178 #[diagnostic(help(
179 "exported type declarations may only reference public types, including nested type dependencies"
180 ))]
181 PrivateTypeInExportedType {
182 #[label("this exported type declaration references a private type")]
183 span: SourceSpan,
184 #[label("this type is private")]
185 defined: SourceSpan,
186 },
187 #[error("unused import")]
188 #[diagnostic(severity(Warning), help("this import is never used and can be safely removed"))]
189 UnusedImport {
190 #[label]
191 span: SourceSpan,
192 },
193 #[error("missing import: the referenced module has not been imported")]
194 #[diagnostic()]
195 MissingImport {
196 #[label("this reference is invalid without a corresponding import")]
197 span: SourceSpan,
198 },
199 #[error("symbol conflict: import would shadow a previous import of the same name")]
200 #[diagnostic(help(
201 "imports must have unique names within a module, \
202 try aliasing one of the imports if both are needed"
203 ))]
204 ImportConflict {
205 #[label("caused by this import")]
206 span: SourceSpan,
207 #[label("previously imported here")]
208 prev_span: SourceSpan,
209 },
210 #[error("invalid re-exported module: you may only re-export items")]
211 #[diagnostic()]
212 ReexportedModule {
213 #[label]
214 span: SourceSpan,
215 },
216 #[error("invalid re-export target: kernel procedures may not be re-exported")]
217 #[diagnostic()]
218 ReexportedKernelProcedure {
219 #[label]
220 span: SourceSpan,
221 },
222 #[error(
223 "invalid re-exported procedure: kernel modules may not re-export procedures from other modules"
224 )]
225 #[diagnostic()]
226 ReexportFromKernel {
227 #[label]
228 span: SourceSpan,
229 },
230 #[error("invalid syscall: callee must be resolvable to kernel module")]
231 #[diagnostic()]
232 InvalidSyscallTarget {
233 #[label]
234 span: SourceSpan,
235 },
236 #[error("invalid procedure path: not an item")]
237 #[diagnostic()]
238 InvalidInvokeTargetViaImport {
239 #[label("call occurs here")]
240 span: SourceSpan,
241 #[label("expected this to resolve to a module, but got a module item")]
242 import: SourceSpan,
243 },
244 #[error("invalid recursive procedure call")]
245 #[diagnostic(help(
246 "this call induces a cycle that returns back to the caller, you must break that cycle"
247 ))]
248 InvalidRecursiveCall {
249 #[label("caused by this call")]
250 span: SourceSpan,
251 },
252 #[error("invalid recursive procedure call")]
253 #[diagnostic(help("this call is self-recursive, which is not allowed"))]
254 SelfRecursive {
255 #[label]
256 span: SourceSpan,
257 },
258 #[error("invalid repeat count")]
259 #[diagnostic(help("repeat count must be in the range {min}..={max}"))]
260 InvalidRepeatCount {
261 #[label]
262 span: SourceSpan,
263 min: u32,
264 max: u32,
265 },
266 #[error("invalid immediate: value is larger than expected range")]
267 #[diagnostic()]
268 ImmediateOverflow {
269 #[label]
270 span: SourceSpan,
271 },
272 #[error("invalid module: {}", kind)]
273 #[diagnostic(help("try breaking this module up into submodules"))]
274 LimitExceeded {
275 #[label]
276 span: SourceSpan,
277 kind: LimitKind,
278 },
279 #[error("unused docstring")]
280 #[diagnostic(
281 severity(Warning),
282 help(
283 "this docstring is immediately followed by at least one empty line, then another docstring, \
284 if you intended these to be a single docstring, you should remove the empty lines"
285 )
286 )]
287 UnusedDocstring {
288 #[label]
289 span: SourceSpan,
290 },
291 #[error("unused docstring")]
292 #[diagnostic(severity(Warning), help("trailing docstrings are useless"))]
293 TrailingDocstring {
294 #[label]
295 span: SourceSpan,
296 },
297 #[error("unused docstring")]
298 #[diagnostic(
299 severity(Warning),
300 help(
301 "imports and re-exports cannot have docstrings, you should use line comment syntax here instead"
302 )
303 )]
304 ImportDocstring {
305 #[label]
306 span: SourceSpan,
307 },
308 #[error("advmap key already defined")]
309 #[diagnostic()]
310 AdvMapKeyAlreadyDefined {
311 #[label]
312 span: SourceSpan,
313 },
314 #[error(transparent)]
315 #[diagnostic(transparent)]
316 ConstEvalError(#[from] ConstEvalError),
317 #[error(transparent)]
318 #[diagnostic(transparent)]
319 SymbolResolutionError(#[from] Box<SymbolResolutionError>),
320}
321
322impl From<SymbolResolutionError> for SemanticAnalysisError {
323 fn from(value: SymbolResolutionError) -> Self {
324 Self::SymbolResolutionError(Box::new(value))
325 }
326}
327
328#[derive(Debug, Copy, Clone, PartialEq, Eq)]
330pub enum LimitKind {
331 Items,
333 Procedures,
335 Locals,
337 Imports,
339 CalledImports,
343 Instructions,
345}
346
347impl fmt::Display for LimitKind {
348 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
349 match self {
350 Self::Items => f.write_str("too many items in module"),
351 Self::Procedures => f.write_str("too many procedures in module"),
352 Self::Locals => f.write_str("too many procedure locals"),
353 Self::Imports => f.write_str("too many imported procedures"),
354 Self::CalledImports => f.write_str("too many calls to imported procedures"),
355 Self::Instructions => f.write_str("too many instructions in block"),
356 }
357 }
358}