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