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::ast::{SymbolResolutionError, constants::ConstEvalError};
11
12#[derive(Debug, thiserror::Error, Diagnostic)]
23#[error("syntax error")]
24#[diagnostic(help("see emitted diagnostics for details"))]
25pub struct SyntaxError {
26 #[source_code]
27 pub source_file: Arc<SourceFile>,
28 #[related]
29 pub errors: Vec<SemanticAnalysisError>,
30}
31
32#[derive(Debug, thiserror::Error, Diagnostic)]
38#[error("one or more warnings were emitted")]
39#[diagnostic(help("see below for details"))]
40#[cfg_attr(not(feature = "std"), expect(unused))]
41pub struct SyntaxWarning {
42 #[source_code]
43 pub source_file: Arc<SourceFile>,
44 #[related]
45 pub errors: Vec<SemanticAnalysisError>,
46}
47
48#[derive(Debug, thiserror::Error, Diagnostic)]
50pub enum SemanticAnalysisError {
51 #[error("invalid program: no entrypoint defined")]
52 #[diagnostic(help(
53 "ensure you define an entrypoint somewhere in the body with `begin`..`end`"
54 ))]
55 MissingEntrypoint,
56 #[error("invalid module: unexpected entrypoint definition")]
57 #[diagnostic(help("library modules cannot contain `begin`..`end` blocks"))]
58 UnexpectedEntrypoint {
59 #[label]
60 span: SourceSpan,
61 },
62 #[error("invalid module: multiple conflicting entrypoints defined")]
63 #[diagnostic(help("an executable module can only have a single `begin`..`end` block"))]
64 MultipleEntrypoints {
65 #[label]
66 span: SourceSpan,
67 #[label]
68 prev_span: SourceSpan,
69 },
70 #[error("invalid invocation target")]
71 #[diagnostic(help("path contains an invalid component"))]
72 InvalidInvokePath {
73 #[label]
74 span: SourceSpan,
75 },
76 #[error("invalid program: procedure exports are not allowed")]
77 #[diagnostic(help("perhaps you meant to use `proc` instead of `export`?"))]
78 UnexpectedExport {
79 #[label]
80 span: SourceSpan,
81 },
82 #[error("invalid enum type representation: underlying type must be an integral or felt type")]
83 #[diagnostic()]
84 InvalidEnumRepr {
85 #[label]
86 span: SourceSpan,
87 },
88 #[error("invalid enum discriminant: value is not a valid instance of the {repr} type")]
89 #[diagnostic()]
90 InvalidEnumDiscriminant {
91 #[label]
92 span: SourceSpan,
93 repr: crate::ast::types::Type,
94 },
95 #[error("invalid enum discriminant: value conflicts with another variant of the same enum")]
96 #[diagnostic()]
97 EnumDiscriminantConflict {
98 #[label("this discriminant value conflicts with a previous variant")]
99 span: SourceSpan,
100 #[label("discriminant previously observed here")]
101 prev: SourceSpan,
102 },
103 #[error("symbol conflict: found duplicate definitions of the same name")]
104 #[diagnostic()]
105 SymbolConflict {
106 #[label("conflict occurs here")]
107 span: SourceSpan,
108 #[label("previously defined here")]
109 prev_span: SourceSpan,
110 },
111 #[error("unused import")]
112 #[diagnostic(severity(Warning), help("this import is never used and can be safely removed"))]
113 UnusedImport {
114 #[label]
115 span: SourceSpan,
116 },
117 #[error("missing import: the referenced module has not been imported")]
118 #[diagnostic()]
119 MissingImport {
120 #[label("this reference is invalid without a corresponding import")]
121 span: SourceSpan,
122 },
123 #[error("symbol conflict: import would shadow a previous import of the same name")]
124 #[diagnostic(help(
125 "imports must have unique names within a module, \
126 try aliasing one of the imports if both are needed"
127 ))]
128 ImportConflict {
129 #[label("caused by this import")]
130 span: SourceSpan,
131 #[label("previously imported here")]
132 prev_span: SourceSpan,
133 },
134 #[error(
135 "invalid re-exported procedure: kernel modules may not re-export procedures from other modules"
136 )]
137 #[diagnostic()]
138 ReexportFromKernel {
139 #[label]
140 span: SourceSpan,
141 },
142 #[error("invalid syscall: callee must be resolvable to kernel module")]
143 #[diagnostic()]
144 InvalidSyscallTarget {
145 #[label]
146 span: SourceSpan,
147 },
148 #[error("invalid procedure path: not an item")]
149 #[diagnostic()]
150 InvalidInvokeTargetViaImport {
151 #[label("call occurs here")]
152 span: SourceSpan,
153 #[label("expected this to resolve to a module, but got a module item")]
154 import: SourceSpan,
155 },
156 #[error("invalid recursive procedure call")]
157 #[diagnostic(help(
158 "this call induces a cycle that returns back to the caller, you must break that cycle"
159 ))]
160 InvalidRecursiveCall {
161 #[label("caused by this call")]
162 span: SourceSpan,
163 },
164 #[error("invalid recursive procedure call")]
165 #[diagnostic(help("this call is self-recursive, which is not allowed"))]
166 SelfRecursive {
167 #[label]
168 span: SourceSpan,
169 },
170 #[error("invalid repeat count")]
171 #[diagnostic(help("repeat count must be in the range {min}..={max}"))]
172 InvalidRepeatCount {
173 #[label]
174 span: SourceSpan,
175 min: u32,
176 max: u32,
177 },
178 #[error("invalid immediate: value is larger than expected range")]
179 #[diagnostic()]
180 ImmediateOverflow {
181 #[label]
182 span: SourceSpan,
183 },
184 #[error("invalid module: {}", kind)]
185 #[diagnostic(help("try breaking this module up into submodules"))]
186 LimitExceeded {
187 #[label]
188 span: SourceSpan,
189 kind: LimitKind,
190 },
191 #[error("unused docstring")]
192 #[diagnostic(
193 severity(Warning),
194 help(
195 "this docstring is immediately followed by at least one empty line, then another docstring,\
196 if you intended these to be a single docstring, you should remove the empty lines"
197 )
198 )]
199 UnusedDocstring {
200 #[label]
201 span: SourceSpan,
202 },
203 #[error("unused docstring")]
204 #[diagnostic(
205 severity(Warning),
206 help(
207 "module imports cannot have docstrings, you should use line comment syntax here instead"
208 )
209 )]
210 ImportDocstring {
211 #[label]
212 span: SourceSpan,
213 },
214 #[error("advmap key already defined")]
215 #[diagnostic()]
216 AdvMapKeyAlreadyDefined {
217 #[label]
218 span: SourceSpan,
219 },
220 #[error(transparent)]
221 #[diagnostic(transparent)]
222 ConstEvalError(#[from] ConstEvalError),
223 #[error(transparent)]
224 #[diagnostic(transparent)]
225 SymbolResolutionError(#[from] Box<SymbolResolutionError>),
226}
227
228impl From<SymbolResolutionError> for SemanticAnalysisError {
229 fn from(value: SymbolResolutionError) -> Self {
230 Self::SymbolResolutionError(Box::new(value))
231 }
232}
233
234#[derive(Debug, Copy, Clone, PartialEq, Eq)]
236pub enum LimitKind {
237 Procedures,
239 Locals,
241 Imports,
243 CalledImports,
247 Instructions,
249}
250
251impl fmt::Display for LimitKind {
252 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253 match self {
254 Self::Procedures => f.write_str("too many procedures in module"),
255 Self::Locals => f.write_str("too many procedure locals"),
256 Self::Imports => f.write_str("too many imported procedures"),
257 Self::CalledImports => f.write_str("too many calls to imported procedures"),
258 Self::Instructions => f.write_str("too many instructions in block"),
259 }
260 }
261}