miden_assembly_syntax/sema/
errors.rs1use alloc::{sync::Arc, vec::Vec};
2use core::fmt;
3
4use miden_debug_types::{SourceFile, SourceSpan};
5use miden_utils_diagnostics::{Diagnostic, miette};
6
7#[derive(Debug, thiserror::Error, Diagnostic)]
18#[error("syntax error")]
19#[diagnostic(help("see emitted diagnostics for details"))]
20pub struct SyntaxError {
21 #[source_code]
22 pub source_file: Arc<SourceFile>,
23 #[related]
24 pub errors: Vec<SemanticAnalysisError>,
25}
26
27#[derive(Debug, thiserror::Error, Diagnostic)]
33#[error("one or more warnings were emitted")]
34#[diagnostic(help("see below for details"))]
35#[cfg_attr(not(feature = "std"), allow(unused))]
36pub struct SyntaxWarning {
37 #[source_code]
38 pub source_file: Arc<SourceFile>,
39 #[related]
40 pub errors: Vec<SemanticAnalysisError>,
41}
42
43#[derive(Debug, thiserror::Error, Diagnostic)]
45pub enum SemanticAnalysisError {
46 #[error("invalid program: no entrypoint defined")]
47 #[diagnostic(help(
48 "ensure you define an entrypoint somewhere in the body with `begin`..`end`"
49 ))]
50 MissingEntrypoint,
51 #[error("invalid module: unexpected entrypoint definition")]
52 #[diagnostic(help("library modules cannot contain `begin`..`end` blocks"))]
53 UnexpectedEntrypoint {
54 #[label]
55 span: SourceSpan,
56 },
57 #[error("invalid module: multiple conflicting entrypoints defined")]
58 #[diagnostic(help("an executable module can only have a single `begin`..`end` block"))]
59 MultipleEntrypoints {
60 #[label]
61 span: SourceSpan,
62 #[label]
63 prev_span: SourceSpan,
64 },
65 #[error("invalid program: procedure exports are not allowed")]
66 #[diagnostic(help("perhaps you meant to use `proc` instead of `export`?"))]
67 UnexpectedExport {
68 #[label]
69 span: SourceSpan,
70 },
71 #[error("invalid enum type representation: underlying type must be an integral type")]
72 #[diagnostic()]
73 InvalidEnumRepr {
74 #[label]
75 span: SourceSpan,
76 },
77 #[error("invalid enum discriminant: value is not a valid instance of the {repr} type")]
78 #[diagnostic()]
79 InvalidEnumDiscriminant {
80 #[label]
81 span: SourceSpan,
82 repr: crate::ast::types::Type,
83 },
84 #[error("invalid enum discriminant: value conflicts with another variant of the same enum")]
85 #[diagnostic()]
86 EnumDiscriminantConflict {
87 #[label("this discriminant value conflicts with a previous variant")]
88 span: SourceSpan,
89 #[label("discriminant previously observed here")]
90 prev: SourceSpan,
91 },
92 #[error("symbol conflict: found duplicate definitions of the same name")]
93 #[diagnostic()]
94 SymbolConflict {
95 #[label("conflict occurs here")]
96 span: SourceSpan,
97 #[label("previously defined here")]
98 prev_span: SourceSpan,
99 },
100 #[error("symbol undefined: no such name found in scope")]
101 #[diagnostic(help("are you missing an import?"))]
102 SymbolUndefined {
103 #[label]
104 span: SourceSpan,
105 },
106 #[error("unused import")]
107 #[diagnostic(severity(Warning), help("this import is never used and can be safely removed"))]
108 UnusedImport {
109 #[label]
110 span: SourceSpan,
111 },
112 #[error("missing import: the referenced module has not been imported")]
113 #[diagnostic()]
114 MissingImport {
115 #[label("this reference is invalid without a corresponding import")]
116 span: SourceSpan,
117 },
118 #[error("symbol conflict: import would shadow a previous import of the same name")]
119 #[diagnostic(help(
120 "imports must have unique names within a module, \
121 try aliasing one of the imports if both are needed"
122 ))]
123 ImportConflict {
124 #[label("caused by this import")]
125 span: SourceSpan,
126 #[label("previously imported here")]
127 prev_span: SourceSpan,
128 },
129 #[error(
130 "invalid re-exported procedure: kernel modules may not re-export procedures from other modules"
131 )]
132 #[diagnostic()]
133 ReexportFromKernel {
134 #[label]
135 span: SourceSpan,
136 },
137 #[error("invalid syscall: cannot make a syscall from within the kernel")]
138 #[diagnostic(help("syscalls are only valid outside the kernel, you should use exec instead"))]
139 SyscallInKernel {
140 #[label]
141 span: SourceSpan,
142 },
143 #[error("invalid call: kernel modules cannot make calls to external procedures")]
144 #[diagnostic(help(
145 "this call is being made from a kernel module, and may only refer to local procedures"
146 ))]
147 CallInKernel {
148 #[label]
149 span: SourceSpan,
150 },
151 #[error("invalid instruction usage: 'caller' is only valid in kernel modules")]
152 #[diagnostic()]
153 CallerInKernel {
154 #[label]
155 span: SourceSpan,
156 },
157 #[error("invalid syscall: callee must be resolvable to kernel module")]
158 #[diagnostic()]
159 InvalidSyscallTarget {
160 #[label]
161 span: SourceSpan,
162 },
163 #[error("invalid recursive procedure call")]
164 #[diagnostic(help(
165 "this call induces a cycle that returns back to the caller, you must break that cycle"
166 ))]
167 InvalidRecursiveCall {
168 #[label("caused by this call")]
169 span: SourceSpan,
170 },
171 #[error("invalid recursive procedure call")]
172 #[diagnostic(help("this call is self-recursive, which is not allowed"))]
173 SelfRecursive {
174 #[label]
175 span: SourceSpan,
176 },
177 #[error("invalid immediate: value is larger than expected range")]
178 #[diagnostic()]
179 ImmediateOverflow {
180 #[label]
181 span: SourceSpan,
182 },
183 #[error("invalid module: {}", kind)]
184 #[diagnostic(help("try breaking this module up into submodules"))]
185 LimitExceeded {
186 #[label]
187 span: SourceSpan,
188 kind: LimitKind,
189 },
190 #[error("unused docstring")]
191 #[diagnostic(
192 severity(Warning),
193 help(
194 "this docstring is immediately followed by at least one empty line, then another docstring,\
195 if you intended these to be a single docstring, you should remove the empty lines"
196 )
197 )]
198 UnusedDocstring {
199 #[label]
200 span: SourceSpan,
201 },
202 #[error("unused docstring")]
203 #[diagnostic(
204 severity(Warning),
205 help(
206 "module imports cannot have docstrings, you should use line comment syntax here instead"
207 )
208 )]
209 ImportDocstring {
210 #[label]
211 span: SourceSpan,
212 },
213 #[error("invalid constant")]
214 #[diagnostic(help("this constant does not resolve to a value of the right type"))]
215 InvalidConstant {
216 #[label]
217 span: SourceSpan,
218 },
219 #[error("constant evaluation terminated due to infinite recursion")]
220 #[diagnostic(help("dependencies between constants must form an acyclic graph"))]
221 ConstEvalCycle {
222 #[label("occurs while evaluating this expression")]
223 start: SourceSpan,
224 #[label("cycle occurs because we attempt to eval this constant recursively")]
225 detected: SourceSpan,
226 },
227 #[error("advmap key already defined")]
228 AdvMapKeyAlreadyDefined {
229 #[label]
230 span: SourceSpan,
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}