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