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