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 program: procedure exports are not allowed")]
71 #[diagnostic(help("perhaps you meant to use `proc` instead of `export`?"))]
72 UnexpectedExport {
73 #[label]
74 span: SourceSpan,
75 },
76 #[error("invalid enum type representation: underlying type must be an integral type")]
77 #[diagnostic()]
78 InvalidEnumRepr {
79 #[label]
80 span: SourceSpan,
81 },
82 #[error("invalid enum discriminant: value is not a valid instance of the {repr} type")]
83 #[diagnostic()]
84 InvalidEnumDiscriminant {
85 #[label]
86 span: SourceSpan,
87 repr: crate::ast::types::Type,
88 },
89 #[error("invalid enum discriminant: value conflicts with another variant of the same enum")]
90 #[diagnostic()]
91 EnumDiscriminantConflict {
92 #[label("this discriminant value conflicts with a previous variant")]
93 span: SourceSpan,
94 #[label("discriminant previously observed here")]
95 prev: SourceSpan,
96 },
97 #[error("symbol conflict: found duplicate definitions of the same name")]
98 #[diagnostic()]
99 SymbolConflict {
100 #[label("conflict occurs here")]
101 span: SourceSpan,
102 #[label("previously defined here")]
103 prev_span: SourceSpan,
104 },
105 #[error("unused import")]
106 #[diagnostic(severity(Warning), help("this import is never used and can be safely removed"))]
107 UnusedImport {
108 #[label]
109 span: SourceSpan,
110 },
111 #[error("missing import: the referenced module has not been imported")]
112 #[diagnostic()]
113 MissingImport {
114 #[label("this reference is invalid without a corresponding import")]
115 span: SourceSpan,
116 },
117 #[error("symbol conflict: import would shadow a previous import of the same name")]
118 #[diagnostic(help(
119 "imports must have unique names within a module, \
120 try aliasing one of the imports if both are needed"
121 ))]
122 ImportConflict {
123 #[label("caused by this import")]
124 span: SourceSpan,
125 #[label("previously imported here")]
126 prev_span: SourceSpan,
127 },
128 #[error(
129 "invalid re-exported procedure: kernel modules may not re-export procedures from other modules"
130 )]
131 #[diagnostic()]
132 ReexportFromKernel {
133 #[label]
134 span: SourceSpan,
135 },
136 #[error("invalid instruction usage: 'caller' is only valid in kernel modules")]
137 #[diagnostic()]
138 CallerInKernel {
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 immediate: value is larger than expected range")]
171 #[diagnostic()]
172 ImmediateOverflow {
173 #[label]
174 span: SourceSpan,
175 },
176 #[error("invalid module: {}", kind)]
177 #[diagnostic(help("try breaking this module up into submodules"))]
178 LimitExceeded {
179 #[label]
180 span: SourceSpan,
181 kind: LimitKind,
182 },
183 #[error("unused docstring")]
184 #[diagnostic(
185 severity(Warning),
186 help(
187 "this docstring is immediately followed by at least one empty line, then another docstring,\
188 if you intended these to be a single docstring, you should remove the empty lines"
189 )
190 )]
191 UnusedDocstring {
192 #[label]
193 span: SourceSpan,
194 },
195 #[error("unused docstring")]
196 #[diagnostic(
197 severity(Warning),
198 help(
199 "module imports cannot have docstrings, you should use line comment syntax here instead"
200 )
201 )]
202 ImportDocstring {
203 #[label]
204 span: SourceSpan,
205 },
206 #[error("advmap key already defined")]
207 #[diagnostic()]
208 AdvMapKeyAlreadyDefined {
209 #[label]
210 span: SourceSpan,
211 },
212 #[error(transparent)]
213 #[diagnostic(transparent)]
214 ConstEvalError(#[from] ConstEvalError),
215 #[error(transparent)]
216 #[diagnostic(transparent)]
217 SymbolResolutionError(#[from] Box<SymbolResolutionError>),
218}
219
220impl From<SymbolResolutionError> for SemanticAnalysisError {
221 fn from(value: SymbolResolutionError) -> Self {
222 Self::SymbolResolutionError(Box::new(value))
223 }
224}
225
226#[derive(Debug, Copy, Clone, PartialEq, Eq)]
228pub enum LimitKind {
229 Procedures,
231 Locals,
233 Imports,
235 CalledImports,
239 Instructions,
241}
242
243impl fmt::Display for LimitKind {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 match self {
246 Self::Procedures => f.write_str("too many procedures in module"),
247 Self::Locals => f.write_str("too many procedure locals"),
248 Self::Imports => f.write_str("too many imported procedures"),
249 Self::CalledImports => f.write_str("too many calls to imported procedures"),
250 Self::Instructions => f.write_str("too many instructions in block"),
251 }
252 }
253}