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 instruction usage: 'caller' is only valid in kernel modules")]
143 #[diagnostic()]
144 CallerInKernel {
145 #[label]
146 span: SourceSpan,
147 },
148 #[error("invalid syscall: callee must be resolvable to kernel module")]
149 #[diagnostic()]
150 InvalidSyscallTarget {
151 #[label]
152 span: SourceSpan,
153 },
154 #[error("invalid procedure path: not an item")]
155 #[diagnostic()]
156 InvalidInvokeTargetViaImport {
157 #[label("call occurs here")]
158 span: SourceSpan,
159 #[label("expected this to resolve to a module, but got a module item")]
160 import: SourceSpan,
161 },
162 #[error("invalid recursive procedure call")]
163 #[diagnostic(help(
164 "this call induces a cycle that returns back to the caller, you must break that cycle"
165 ))]
166 InvalidRecursiveCall {
167 #[label("caused by this call")]
168 span: SourceSpan,
169 },
170 #[error("invalid recursive procedure call")]
171 #[diagnostic(help("this call is self-recursive, which is not allowed"))]
172 SelfRecursive {
173 #[label]
174 span: SourceSpan,
175 },
176 #[error("invalid repeat count")]
177 #[diagnostic(help("repeat count must be in the range {min}..={max}"))]
178 InvalidRepeatCount {
179 #[label]
180 span: SourceSpan,
181 min: u32,
182 max: u32,
183 },
184 #[error("invalid immediate: value is larger than expected range")]
185 #[diagnostic()]
186 ImmediateOverflow {
187 #[label]
188 span: SourceSpan,
189 },
190 #[error("invalid module: {}", kind)]
191 #[diagnostic(help("try breaking this module up into submodules"))]
192 LimitExceeded {
193 #[label]
194 span: SourceSpan,
195 kind: LimitKind,
196 },
197 #[error("unused docstring")]
198 #[diagnostic(
199 severity(Warning),
200 help(
201 "this docstring is immediately followed by at least one empty line, then another docstring,\
202 if you intended these to be a single docstring, you should remove the empty lines"
203 )
204 )]
205 UnusedDocstring {
206 #[label]
207 span: SourceSpan,
208 },
209 #[error("unused docstring")]
210 #[diagnostic(
211 severity(Warning),
212 help(
213 "module imports cannot have docstrings, you should use line comment syntax here instead"
214 )
215 )]
216 ImportDocstring {
217 #[label]
218 span: SourceSpan,
219 },
220 #[error("advmap key already defined")]
221 #[diagnostic()]
222 AdvMapKeyAlreadyDefined {
223 #[label]
224 span: SourceSpan,
225 },
226 #[error(transparent)]
227 #[diagnostic(transparent)]
228 ConstEvalError(#[from] ConstEvalError),
229 #[error(transparent)]
230 #[diagnostic(transparent)]
231 SymbolResolutionError(#[from] Box<SymbolResolutionError>),
232}
233
234impl From<SymbolResolutionError> for SemanticAnalysisError {
235 fn from(value: SymbolResolutionError) -> Self {
236 Self::SymbolResolutionError(Box::new(value))
237 }
238}
239
240#[derive(Debug, Copy, Clone, PartialEq, Eq)]
242pub enum LimitKind {
243 Procedures,
245 Locals,
247 Imports,
249 CalledImports,
253 Instructions,
255}
256
257impl fmt::Display for LimitKind {
258 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
259 match self {
260 Self::Procedures => f.write_str("too many procedures in module"),
261 Self::Locals => f.write_str("too many procedure locals"),
262 Self::Imports => f.write_str("too many imported procedures"),
263 Self::CalledImports => f.write_str("too many calls to imported procedures"),
264 Self::Instructions => f.write_str("too many instructions in block"),
265 }
266 }
267}