sway_ir/
error.rs

1/// These errors are for internal IR failures, not designed to be useful to a Sway developer, but
2/// more for users of the `sway-ir` crate, i.e., compiler developers.
3///
4/// XXX They're not very rich and could do with a little more verbosity.
5
6#[derive(Debug)]
7pub enum IrError {
8    FunctionLocalClobbered(String, String),
9    InvalidMetadatum(String),
10    InvalidPhi,
11    MisplacedTerminator(String),
12    MissingBlock(String),
13    MissingTerminator(String),
14    ParseFailure(String, String),
15    RemoveMissingBlock(String),
16    ValueNotFound(String),
17    InconsistentParent(String, String, String),
18
19    VerifyArgumentValueIsNotArgument(String),
20    VerifyUnaryOpIncorrectArgType,
21    VerifyBinaryOpIncorrectArgType,
22    VerifyBitcastBetweenInvalidTypes(String, String),
23    VerifyBitcastUnknownSourceType,
24    VerifyEntryBlockHasPredecessors(String, Vec<String>),
25    VerifyBlockArgMalformed,
26    VerifyBranchParamsMismatch,
27    VerifyBranchToMissingBlock(String),
28    VerifyCallArgTypeMismatch(String, String, String),
29    VerifyCallToMissingFunction(String),
30    VerifyCmpBadTypes(String, String),
31    VerifyCmpTypeMismatch(String, String),
32    VerifyCmpUnknownTypes,
33    VerifyConditionExprNotABool,
34    VerifyContractCallBadTypes(String),
35    VerifyGepElementTypeNonPointer,
36    VerifyGepFromNonPointer(String, Option<Value>),
37    VerifyGepInconsistentTypes(String, Option<crate::Value>),
38    VerifyGepOnNonAggregate,
39    VerifyGetNonExistentLocalVarPointer,
40    VerifyGetNonExistentGlobalVarPointer,
41    VerifyGetNonExistentConfigPointer,
42    VerifyGetNonExistentStorageKeyPointer,
43    VerifyGlobalMissingInitializer(String),
44    VerifyInsertElementOfIncorrectType,
45    VerifyInsertValueOfIncorrectType,
46    VerifyIntToPtrFromNonIntegerType(String),
47    VerifyIntToPtrToNonPointer(String),
48    VerifyIntToPtrUnknownSourceType,
49    VerifyAllocCountNotUint64,
50    VerifyInvalidGtfIndexType,
51    VerifyLoadFromNonPointer(String),
52    VerifyLocalMissingInitializer(String, String),
53    VerifyLogId,
54    VerifyLogMismatchedTypes,
55    VerifyLogEventDataVersion(u8),
56    VerifyLogEventDataInvalid(String),
57    VerifyMemcopyNonPointer(String),
58    VerifyMemcopyMismatchedTypes(String, String),
59    VerifyMemClearValNonPointer(String),
60    VerifyPtrCastFromNonPointer(String),
61    VerifyPtrCastToNonPointer(String),
62    VerifyPtrToIntToNonInteger(String),
63    VerifyReturnMismatchedTypes(String),
64    VerifyRevertCodeBadType,
65    VerifySmoBadMessageType,
66    VerifySmoCoins,
67    VerifySmoMessageSize,
68    VerifySmoRecipientNonPointer(String),
69    VerifySmoMessageNonPointer(String),
70    VerifySmoRecipientBadType,
71    VerifyStateAccessNumOfSlots,
72    VerifyStateAccessQuadNonPointer(String),
73    VerifyStateDestBadType(String),
74    VerifyStateKeyBadType,
75    VerifyStateKeyNonPointer(String),
76    VerifyStoreMismatchedTypes(Option<Value>),
77    VerifyStoreToNonPointer(String),
78    VerifyUntypedValuePassedToFunction,
79}
80impl IrError {
81    pub(crate) fn get_problematic_value(&self) -> Option<&Value> {
82        match self {
83            Self::VerifyGepFromNonPointer(_, v) => v.as_ref(),
84            Self::VerifyGepInconsistentTypes(_, v) => v.as_ref(),
85            Self::VerifyStoreMismatchedTypes(v) => v.as_ref(),
86            _ => None,
87        }
88    }
89}
90
91impl std::error::Error for IrError {}
92
93use std::fmt;
94
95use crate::Value;
96use itertools::Itertools;
97
98impl fmt::Display for IrError {
99    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
100        match self {
101            IrError::FunctionLocalClobbered(fn_str, var_str) => write!(
102                f,
103                "Local storage for function {fn_str} already has an entry for variable {var_str}."
104            ),
105            IrError::InvalidMetadatum(why_str) => {
106                write!(f, "Unable to convert from invalid metadatum: {why_str}.")
107            }
108            IrError::InvalidPhi => write!(
109                f,
110                "Phi instruction has invalid block or value reference list."
111            ),
112            IrError::MisplacedTerminator(blk_str) => {
113                write!(f, "Block {blk_str} has a misplaced terminator.")
114            }
115            IrError::MissingBlock(blk_str) => write!(f, "Unable to find block {blk_str}."),
116            IrError::MissingTerminator(blk_str) => {
117                write!(f, "Block {blk_str} is missing its terminator.")
118            }
119            IrError::ParseFailure(expecting, found) => {
120                write!(
121                    f,
122                    "Parse failure: expecting '{expecting}', found '{found}'."
123                )
124            }
125            IrError::RemoveMissingBlock(blk_str) => {
126                write!(f, "Unable to remove block {blk_str}; not found.")
127            }
128            IrError::ValueNotFound(reason) => {
129                write!(f, "Invalid value: {reason}.")
130            }
131            IrError::InconsistentParent(entity, expected_parent, found_parent) => {
132                write!(
133                                    f,
134                                    "For IR Entity (module/function/block) {entity}, expected parent to be {expected_parent}, \
135                    but found {found_parent}."
136                                )
137            }
138            IrError::VerifyArgumentValueIsNotArgument(callee) => write!(
139                f,
140                "Verification failed: Argument specifier for function '{callee}' is not an \
141                argument value."
142            ),
143            IrError::VerifyBitcastUnknownSourceType => write!(
144                f,
145                "Verification failed: Bitcast unable to determine source type."
146            ),
147            IrError::VerifyBitcastBetweenInvalidTypes(from_ty, to_ty) => write!(
148                f,
149                "Verification failed: Bitcast not allowed from a {from_ty} to a {to_ty}."
150            ),
151            IrError::VerifyUnaryOpIncorrectArgType => {
152                write!(
153                    f,
154                    "Verification failed: Incorrect argument type for unary op"
155                )
156            }
157            IrError::VerifyBinaryOpIncorrectArgType => {
158                write!(
159                    f,
160                    "Verification failed: Incorrect argument type(s) for binary op"
161                )
162            }
163            IrError::VerifyBranchToMissingBlock(label) => {
164                write!(
165                    f,
166                    "Verification failed: \
167                    Branch to block '{label}' is not a block in the current function."
168                )
169            }
170            IrError::VerifyCallArgTypeMismatch(callee, caller_ty, callee_ty) => {
171                write!(
172                                    f,
173                                    "Verification failed: Type mismatch found for call to '{callee}': {caller_ty} is not a {callee_ty}."
174                                )
175            }
176            IrError::VerifyCallToMissingFunction(callee) => {
177                write!(
178                    f,
179                    "Verification failed: Call to invalid function '{callee}'."
180                )
181            }
182            IrError::VerifyCmpBadTypes(lhs_ty, rhs_ty) => {
183                write!(
184                    f,
185                    "Verification failed: Cannot compare non-integer types {lhs_ty} and {rhs_ty}."
186                )
187            }
188            IrError::VerifyCmpTypeMismatch(lhs_ty, rhs_ty) => {
189                write!(
190                    f,
191                    "Verification failed: \
192                    Cannot compare values with different widths of {lhs_ty} and {rhs_ty}."
193                )
194            }
195            IrError::VerifyCmpUnknownTypes => {
196                write!(
197                    f,
198                    "Verification failed: Unable to determine type(s) of compared value(s)."
199                )
200            }
201            IrError::VerifyConditionExprNotABool => {
202                write!(
203                    f,
204                    "Verification failed: Expression used for conditional is not a boolean."
205                )
206            }
207            IrError::VerifyContractCallBadTypes(arg_name) => {
208                write!(
209                    f,
210                    "Verification failed: \
211                    Argument {arg_name} passed to contract call has the incorrect type."
212                )
213            }
214            IrError::VerifyGepElementTypeNonPointer => {
215                write!(f, "Verification failed: GEP on a non-pointer.")
216            }
217            IrError::VerifyGepInconsistentTypes(error, _) => {
218                write!(
219                    f,
220                    "Verification failed: Struct field type mismatch: ({error})."
221                )
222            }
223            IrError::VerifyGepFromNonPointer(ty, _) => {
224                write!(
225                    f,
226                    "Verification failed: Struct access must be to a pointer value, not a {ty}."
227                )
228            }
229            IrError::VerifyGepOnNonAggregate => {
230                write!(
231                    f,
232                    "Verification failed: Attempt to access a field from a non struct."
233                )
234            }
235            IrError::VerifyGetNonExistentLocalVarPointer => {
236                write!(
237                    f,
238                    "Verification failed: Attempt to get pointer not found in function local variables."
239                )
240            }
241            IrError::VerifyGetNonExistentGlobalVarPointer => {
242                write!(
243                    f,
244                    "Verification failed: Attempt to get pointer not found in module global variables."
245                )
246            }
247            IrError::VerifyGetNonExistentConfigPointer => {
248                write!(
249                    f,
250                    "Verification failed: Attempt to get pointer not found in module configurables."
251                )
252            }
253            IrError::VerifyGetNonExistentStorageKeyPointer => {
254                write!(
255                    f,
256                    "Verification failed: Attempt to get pointer not found in module storage keys."
257                )
258            }
259            IrError::VerifyInsertElementOfIncorrectType => {
260                write!(
261                    f,
262                    "Verification failed: Attempt to insert value of incorrect type into an array."
263                )
264            }
265            IrError::VerifyInsertValueOfIncorrectType => {
266                write!(
267                    f,
268                    "Verification failed: Attempt to insert value of incorrect type into a struct."
269                )
270            }
271            IrError::VerifyIntToPtrFromNonIntegerType(ty) => {
272                write!(f, "Verification failed: int_to_ptr cannot be from a {ty}.")
273            }
274            IrError::VerifyIntToPtrToNonPointer(ty) => {
275                write!(
276                    f,
277                    "Verification failed: int_to_ptr cannot be to a non-pointer {ty}."
278                )
279            }
280            IrError::VerifyIntToPtrUnknownSourceType => write!(
281                f,
282                "Verification failed: int_to_ptr unable to determine source type."
283            ),
284            IrError::VerifyAllocCountNotUint64 => {
285                write!(
286                    f,
287                    "Verification failed: alloc instruction count must be a u64 integer."
288                )
289            }
290            IrError::VerifyLoadFromNonPointer(ty) => {
291                write!(
292                    f,
293                    "Verification failed: Load cannot be from a non-pointer {ty}."
294                )
295            }
296            IrError::VerifyMemcopyNonPointer(ty) => {
297                write!(
298                    f,
299                    "Verification failed: mem_copy cannot be to or from a non-pointer {ty}.",
300                )
301            }
302            IrError::VerifyMemcopyMismatchedTypes(dst_ty, src_ty) => {
303                write!(
304                    f,
305                    "Verification failed: mem_copy cannot be from {src_ty} pointer to {dst_ty} \
306                    pointer.",
307                )
308            }
309            IrError::VerifyMemClearValNonPointer(ty) => {
310                write!(
311                    f,
312                    "Verification failed: mem_clear_val argument is not a pointer {ty}.",
313                )
314            }
315            IrError::VerifyReturnMismatchedTypes(fn_str) => write!(
316                f,
317                "Verification failed: \
318                Function {fn_str} return type must match its RET instructions."
319            ),
320            IrError::VerifyEntryBlockHasPredecessors(function_name, predecessors) => {
321                let plural_s = if predecessors.len() == 1 { "" } else { "s" };
322                write!(
323                                    f,
324                                    "Verification failed: Entry block of the function \"{function_name}\" has {}predecessor{}. \
325                     The predecessor{} {} {}.",
326                                    if predecessors.len() == 1 {
327                                        "a "
328                                    } else {
329                                        ""
330                                    },
331                                    plural_s,
332                                    plural_s,
333                                    if predecessors.len() == 1 {
334                                        "is"
335                                    } else {
336                                        "are"
337                                    },
338                                    predecessors.iter().map(|block_label| format!("\"{block_label}\"")).collect_vec().join(", ")
339                                )
340            }
341            IrError::VerifyBlockArgMalformed => {
342                write!(f, "Verification failed: Block argument is malformed")
343            }
344            IrError::VerifyBranchParamsMismatch => {
345                write!(
346                    f,
347                    "Verification failed: Block parameter passed in branch is malformed"
348                )
349            }
350            IrError::VerifyPtrCastFromNonPointer(ty) => {
351                write!(
352                    f,
353                    "Verification failed: Pointer cast from non pointer {ty}."
354                )
355            }
356            IrError::VerifyPtrCastToNonPointer(ty) => {
357                write!(f, "Verification failed: Pointer cast to non pointer {ty}.")
358            }
359            IrError::VerifyPtrToIntToNonInteger(ty) => {
360                write!(f, "Verification failed: Pointer cast to non integer {ty}.")
361            }
362            IrError::VerifyStateAccessNumOfSlots => {
363                write!(
364                    f,
365                    "Verification failed: Number of slots for state access must be an integer."
366                )
367            }
368            IrError::VerifyStateAccessQuadNonPointer(ty) => {
369                write!(
370                    f,
371                    "Verification failed: \
372                    State quad access must be to or from a pointer, not a {ty}."
373                )
374            }
375            IrError::VerifyStateKeyBadType => {
376                write!(
377                    f,
378                    "Verification failed: State load or store key must be a b256 pointer."
379                )
380            }
381            IrError::VerifyStateKeyNonPointer(ty) => {
382                write!(
383                    f,
384                    "Verification failed: State load or store key must be a pointer, not a {ty}."
385                )
386            }
387            IrError::VerifyStateDestBadType(ty) => {
388                write!(
389                    f,
390                    "Verification failed: State access operation must be to a {ty} pointer."
391                )
392            }
393            IrError::VerifyStoreMismatchedTypes(_) => {
394                write!(
395                    f,
396                    "Verification failed: Store value and pointer type mismatch."
397                )
398            }
399            IrError::VerifyStoreToNonPointer(ty) => {
400                write!(f, "Store must be to a pointer, not a {ty}.")
401            }
402            IrError::VerifyUntypedValuePassedToFunction => write!(
403                f,
404                "Verification failed: An untyped/void value has been passed to a function call."
405            ),
406            IrError::VerifyInvalidGtfIndexType => write!(
407                f,
408                "Verification failed: An non-integer value has been passed to a 'gtf' instruction."
409            ),
410            IrError::VerifyLogId => {
411                write!(f, "Verification failed: log ID must be an integer.")
412            }
413            IrError::VerifyLogMismatchedTypes => {
414                write!(
415                    f,
416                    "Verification failed: log type must match the type of the value being logged."
417                )
418            }
419            IrError::VerifyLogEventDataVersion(version) => {
420                write!(
421                    f,
422                    "Verification failed: unsupported log event metadata version {version}."
423                )
424            }
425            IrError::VerifyLogEventDataInvalid(reason) => {
426                write!(
427                    f,
428                    "Verification failed: invalid log event metadata ({reason})."
429                )
430            }
431            IrError::VerifyRevertCodeBadType => {
432                write!(
433                    f,
434                    "Verification failed: error code for revert must be a u64."
435                )
436            }
437            IrError::VerifySmoRecipientBadType => {
438                write!(
439                    f,
440                    "Verification failed: the `smo` must have a `b256` as its first argument."
441                )
442            }
443            IrError::VerifySmoBadMessageType => {
444                write!(
445                    f,
446                    "Verification failed: the second arg of of `smo` must be a struct."
447                )
448            }
449            IrError::VerifySmoMessageSize => {
450                write!(
451                    f,
452                    "Verification failed: smo message size must be an integer."
453                )
454            }
455            IrError::VerifySmoRecipientNonPointer(ty) => {
456                write!(
457                    f,
458                    "Verification failed: the first arg of `smo` cannot be a non-pointer of {ty}."
459                )
460            }
461            IrError::VerifySmoMessageNonPointer(ty) => {
462                write!(
463                    f,
464                    "Verification failed: the second arg of `smo` cannot be a non-pointer of {ty}."
465                )
466            }
467            IrError::VerifySmoCoins => {
468                write!(
469                    f,
470                    "Verification failed: smo coins value must be an integer."
471                )
472            }
473            IrError::VerifyGlobalMissingInitializer(global_name) => {
474                write!(
475                    f,
476                    "Verification failed: Immutable global variable {global_name}\
477                    is missing an initializer."
478                )
479            }
480            IrError::VerifyLocalMissingInitializer(local_name, func_name) => {
481                write!(
482                    f,
483                    "Verification failed: Immutable local variable {local_name} in function \
484                    {func_name} is missing an initializer."
485                )
486            }
487        }
488    }
489}