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