Skip to main content

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