sway_error/
error.rs

1use crate::convert_parse_tree_error::{
2    get_attribute_type, get_expected_attributes_args_multiplicity_msg, AttributeType,
3    ConvertParseTreeError,
4};
5use crate::diagnostic::{Code, Diagnostic, Hint, Issue, Reason, ToDiagnostic};
6use crate::formatting::*;
7use crate::lex_error::LexError;
8use crate::parser_error::{ParseError, ParseErrorKind};
9use crate::type_error::TypeError;
10
11use core::fmt;
12use std::fmt::Formatter;
13use sway_types::style::to_snake_case;
14use sway_types::{BaseIdent, Ident, IdentUnique, SourceEngine, Span, Spanned};
15use thiserror::Error;
16
17use self::ShadowingSource::*;
18use self::StructFieldUsageContext::*;
19
20#[derive(Error, Debug, Clone, PartialEq, Eq, Hash)]
21pub enum InterfaceName {
22    Abi(Ident),
23    Trait(Ident),
24}
25
26impl fmt::Display for InterfaceName {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        match self {
29            InterfaceName::Abi(name) => write!(f, "ABI \"{name}\""),
30            InterfaceName::Trait(name) => write!(f, "trait \"{name}\""),
31        }
32    }
33}
34
35// TODO: Since moving to using Idents instead of strings, there are a lot of redundant spans in
36//       this type. When replacing Strings + Spans with Idents, be aware of the rule explained below.
37
38// When defining error structures that display identifiers, we prefer passing Idents over Strings.
39// The error span can come from that same Ident or can be a different span.
40// We handle those two cases in the following way:
41//   - If the error span equals Ident's span, we use IdentUnique and never the plain Ident.
42//   - If the error span is different then Ident's span, we pass Ident and Span as two separate fields.
43//
44// The reason for this rule is clearly communicating the difference of the two cases in every error,
45// as well as avoiding issues with the error message deduplication explained below.
46//
47// Deduplication of error messages might remove errors that are actually not duplicates because
48// although they point to the same Ident (in terms of the identifier's name), the span can be different.
49// Deduplication works on hashes and Ident's hash contains only the name and not the span.
50// That's why we always use IdentUnique whenever we extract the span from the provided Ident.
51// Using IdentUnique also clearly communicates that we are extracting the span from the
52// provided identifier.
53#[derive(Error, Debug, Clone, PartialEq, Eq, Hash)]
54pub enum CompileError {
55    #[error("\"const generics\" are not supported here.")]
56    ConstGenericNotSupportedHere { span: Span },
57    #[error("This expression is not supported as lengths.")]
58    LengthExpressionNotSupported { span: Span },
59    #[error(
60        "This needs \"{feature}\" to be enabled, but it is currently disabled. For more details go to {url}."
61    )]
62    FeatureIsDisabled {
63        feature: String,
64        url: String,
65        span: Span,
66    },
67    #[error(
68        "There was an error while evaluating the evaluation order for the module dependency graph."
69    )]
70    ModuleDepGraphEvaluationError {},
71    #[error("A cyclic reference was found between the modules: {}.",
72        modules.iter().map(|ident| ident.as_str().to_string())
73    .collect::<Vec<_>>()
74    .join(", "))]
75    ModuleDepGraphCyclicReference { modules: Vec<BaseIdent> },
76
77    #[error("Variable \"{var_name}\" does not exist in this scope.")]
78    UnknownVariable { var_name: Ident, span: Span },
79    #[error("Identifier \"{name}\" was used as a variable, but it is actually a {what_it_is}.")]
80    NotAVariable {
81        name: Ident,
82        what_it_is: &'static str,
83        span: Span,
84    },
85    #[error("{feature} is currently not implemented.")]
86    Unimplemented {
87        /// The description of the unimplemented feature,
88        /// formulated in a way that fits into common ending
89        /// "is currently not implemented."
90        /// E.g., "Using something".
91        feature: String,
92        /// Help lines. Empty if there is no additional help.
93        /// To get an empty line between the help lines,
94        /// insert a [String] containing only a space: `" ".to_string()`.
95        help: Vec<String>,
96        span: Span,
97    },
98    #[error("{0}")]
99    TypeError(TypeError),
100    #[error("Error parsing input: {err:?}")]
101    ParseError { span: Span, err: String },
102    #[error(
103        "Internal compiler error: {0}\nPlease file an issue on the repository and include the \
104         code that triggered this error."
105    )]
106    Internal(&'static str, Span),
107    #[error(
108        "Internal compiler error: {0}\nPlease file an issue on the repository and include the \
109         code that triggered this error."
110    )]
111    InternalOwned(String, Span),
112    #[error(
113        "Predicate declaration contains no main function. Predicates require a main function."
114    )]
115    NoPredicateMainFunction(Span),
116    #[error("A predicate's main function must return a boolean.")]
117    PredicateMainDoesNotReturnBool(Span),
118    #[error("Script declaration contains no main function. Scripts require a main function.")]
119    NoScriptMainFunction(Span),
120    #[error("Fallback function already defined in scope.")]
121    MultipleDefinitionsOfFallbackFunction { name: Ident, span: Span },
122    #[error("Function \"{name}\" was already defined in scope.")]
123    MultipleDefinitionsOfFunction { name: Ident, span: Span },
124    #[error("Name \"{name}\" is defined multiple times.")]
125    MultipleDefinitionsOfName { name: Ident, span: Span },
126    #[error("Constant \"{name}\" was already defined in scope.")]
127    MultipleDefinitionsOfConstant { name: Ident, new: Span, old: Span },
128    #[error("Type \"{name}\" was already defined in scope.")]
129    MultipleDefinitionsOfType { name: Ident, span: Span },
130    #[error("Variable \"{}\" is already defined in match arm.", first_definition.as_str())]
131    MultipleDefinitionsOfMatchArmVariable {
132        match_value: Span,
133        match_type: String,
134        first_definition: Span,
135        first_definition_is_struct_field: bool,
136        duplicate: Span,
137        duplicate_is_struct_field: bool,
138    },
139    #[error(
140        "Assignment to an immutable variable. Variable \"{decl_name} is not declared as mutable."
141    )]
142    AssignmentToNonMutableVariable {
143        /// Variable name pointing to the name in the variable declaration.
144        decl_name: Ident,
145        /// The complete left-hand side of the assignment.
146        lhs_span: Span,
147    },
148    #[error(
149        "Assignment to a {}. {} cannot be assigned to.",
150        if *is_configurable {
151            "configurable"
152        } else {
153            "constant"
154        },
155        if *is_configurable {
156            "Configurables"
157        } else {
158            "Constants"
159        }
160    )]
161    AssignmentToConstantOrConfigurable {
162        /// Constant or configurable name pointing to the name in the constant declaration.
163        decl_name: Ident,
164        is_configurable: bool,
165        /// The complete left-hand side of the assignment.
166        lhs_span: Span,
167    },
168    #[error(
169        "This assignment target cannot be assigned to, because {} is {}{decl_friendly_type_name} and not a mutable variable.",
170        if let Some(decl_name) = decl_name {
171            format!("\"{decl_name}\"")
172        } else {
173            "this".to_string()
174        },
175        a_or_an(decl_friendly_type_name)
176    )]
177    DeclAssignmentTargetCannotBeAssignedTo {
178        /// Name of the declared variant, pointing to the name in the declaration.
179        decl_name: Option<Ident>,
180        /// Friendly name of the type of the declaration. E.g., "function", or "struct".
181        decl_friendly_type_name: &'static str,
182        /// The complete left-hand side of the assignment.
183        lhs_span: Span,
184    },
185    #[error("This reference is not a reference to a mutable value (`&mut`).")]
186    AssignmentViaNonMutableReference {
187        /// Name of the reference, if the left-hand side of the assignment is a reference variable,
188        /// pointing to the name in the reference variable declaration.
189        ///
190        /// `None` if the assignment LHS is an arbitrary expression and not a variable.
191        decl_reference_name: Option<Ident>,
192        /// [Span] of the right-hand side of the reference variable definition,
193        /// if the left-hand side of the assignment is a reference variable.
194        decl_reference_rhs: Option<Span>,
195        /// The type of the reference, if the left-hand side of the assignment is a reference variable,
196        /// expected to start with `&`.
197        decl_reference_type: String,
198        span: Span,
199    },
200    #[error(
201        "Cannot call method \"{method_name}\" on variable \"{variable_name}\" because \
202            \"{variable_name}\" is not declared as mutable."
203    )]
204    MethodRequiresMutableSelf {
205        method_name: Ident,
206        variable_name: Ident,
207        span: Span,
208    },
209    #[error(
210        "This parameter was declared as mutable, which is not supported yet, did you mean to use ref mut?"
211    )]
212    MutableParameterNotSupported { param_name: Ident, span: Span },
213    #[error("Cannot pass immutable argument to mutable parameter.")]
214    ImmutableArgumentToMutableParameter { span: Span },
215    #[error("ref mut or mut parameter is not allowed for contract ABI function.")]
216    RefMutableNotAllowedInContractAbi { param_name: Ident, span: Span },
217    #[error("Reference to a mutable value cannot reference a constant.")]
218    RefMutCannotReferenceConstant {
219        /// Constant, as accessed in code. E.g.:
220        ///  - `MY_CONST`
221        ///  - `LIB_CONST_ALIAS`
222        ///  - `::lib::module::SOME_CONST`
223        constant: String,
224        span: Span,
225    },
226    #[error("Reference to a mutable value cannot reference an immutable variable.")]
227    RefMutCannotReferenceImmutableVariable {
228        /// Variable name pointing to the name in the variable declaration.
229        decl_name: Ident,
230        span: Span,
231    },
232    #[error(
233        "Cannot call associated function \"{fn_name}\" as a method. Use associated function \
234        syntax instead."
235    )]
236    AssociatedFunctionCalledAsMethod { fn_name: Ident, span: Span },
237    #[error(
238        "Generic type \"{name}\" is not in scope. Perhaps you meant to specify type parameters in \
239         the function signature? For example: \n`fn \
240         {fn_name}<{comma_separated_generic_params}>({args}) -> ... `"
241    )]
242    TypeParameterNotInTypeScope {
243        name: Ident,
244        span: Span,
245        comma_separated_generic_params: String,
246        fn_name: Ident,
247        args: String,
248    },
249    #[error(
250        "expected: {expected} \n\
251         found:    {given} \n\
252         help:     The definition of this {decl_type} must \
253         match the one in the {interface_name} declaration."
254    )]
255    MismatchedTypeInInterfaceSurface {
256        interface_name: InterfaceName,
257        span: Span,
258        decl_type: String,
259        given: String,
260        expected: String,
261    },
262    #[error("Trait \"{name}\" cannot be found in the current scope.")]
263    UnknownTrait { span: Span, name: Ident },
264    #[error("Function \"{name}\" is not a part of {interface_name}'s interface surface.")]
265    FunctionNotAPartOfInterfaceSurface {
266        name: Ident,
267        interface_name: InterfaceName,
268        span: Span,
269    },
270    #[error("Constant \"{name}\" is not a part of {interface_name}'s interface surface.")]
271    ConstantNotAPartOfInterfaceSurface {
272        name: Ident,
273        interface_name: InterfaceName,
274        span: Span,
275    },
276    #[error("Type \"{name}\" is not a part of {interface_name}'s interface surface.")]
277    TypeNotAPartOfInterfaceSurface {
278        name: Ident,
279        interface_name: InterfaceName,
280        span: Span,
281    },
282    #[error("Constants are missing from this trait implementation: {}",
283        missing_constants.iter().map(|ident| ident.as_str().to_string())
284        .collect::<Vec<_>>()
285        .join("\n"))]
286    MissingInterfaceSurfaceConstants {
287        missing_constants: Vec<BaseIdent>,
288        span: Span,
289    },
290    #[error("Associated types are missing from this trait implementation: {}",
291        missing_types.iter().map(|ident| ident.as_str().to_string())
292        .collect::<Vec<_>>()
293        .join("\n"))]
294    MissingInterfaceSurfaceTypes {
295        missing_types: Vec<BaseIdent>,
296        span: Span,
297    },
298    #[error("Functions are missing from this trait implementation: {}",
299        missing_functions.iter().map(|ident| ident.as_str().to_string())
300        .collect::<Vec<_>>()
301        .join("\n"))]
302    MissingInterfaceSurfaceMethods {
303        missing_functions: Vec<BaseIdent>,
304        span: Span,
305    },
306    #[error("Expected {} type {} for \"{name}\", but instead found {}.", expected, if *expected == 1usize { "argument" } else { "arguments" }, given)]
307    IncorrectNumberOfTypeArguments {
308        name: Ident,
309        given: usize,
310        expected: usize,
311        span: Span,
312    },
313    #[error("\"{name}\" does not take type arguments.")]
314    DoesNotTakeTypeArguments { name: Ident, span: Span },
315    #[error("\"{name}\" does not take type arguments as prefix.")]
316    DoesNotTakeTypeArgumentsAsPrefix { name: Ident, span: Span },
317    #[error("Type arguments are not allowed for this type.")]
318    TypeArgumentsNotAllowed { span: Span },
319    #[error("\"{name}\" needs type arguments.")]
320    NeedsTypeArguments { name: Ident, span: Span },
321    #[error(
322        "Enum with name \"{name}\" could not be found in this scope. Perhaps you need to import \
323         it?"
324    )]
325    EnumNotFound { name: Ident, span: Span },
326    /// This error is used only for error recovery and is not emitted as a compiler
327    /// error to the final compilation output. The compiler emits the cumulative error
328    /// [CompileError::StructInstantiationMissingFields] given below, and that one also
329    /// only if the struct can actually be instantiated.
330    #[error("Instantiation of the struct \"{struct_name}\" is missing field \"{field_name}\".")]
331    StructInstantiationMissingFieldForErrorRecovery {
332        field_name: Ident,
333        /// Original, non-aliased struct name.
334        struct_name: Ident,
335        span: Span,
336    },
337    #[error("Instantiation of the struct \"{struct_name}\" is missing {} {}.",
338        if field_names.len() == 1 { "field" } else { "fields" },
339        field_names.iter().map(|name| format!("\"{name}\"")).collect::<Vec::<_>>().join(", "))]
340    StructInstantiationMissingFields {
341        field_names: Vec<Ident>,
342        /// Original, non-aliased struct name.
343        struct_name: Ident,
344        span: Span,
345        struct_decl_span: Span,
346        total_number_of_fields: usize,
347    },
348    #[error("Struct \"{struct_name}\" cannot be instantiated here because it has private fields.")]
349    StructCannotBeInstantiated {
350        /// Original, non-aliased struct name.
351        struct_name: Ident,
352        span: Span,
353        struct_decl_span: Span,
354        private_fields: Vec<Ident>,
355        /// All available public constructors if `is_in_storage_declaration` is false,
356        /// or only the public constructors that potentially evaluate to a constant
357        /// if `is_in_storage_declaration` is true.
358        constructors: Vec<String>,
359        /// True if the struct has only private fields.
360        all_fields_are_private: bool,
361        is_in_storage_declaration: bool,
362        struct_can_be_changed: bool,
363    },
364    #[error("Field \"{field_name}\" of the struct \"{struct_name}\" is private.")]
365    StructFieldIsPrivate {
366        field_name: IdentUnique,
367        /// Original, non-aliased struct name.
368        struct_name: Ident,
369        field_decl_span: Span,
370        struct_can_be_changed: bool,
371        usage_context: StructFieldUsageContext,
372    },
373    #[error("Field \"{field_name}\" does not exist in struct \"{struct_name}\".")]
374    StructFieldDoesNotExist {
375        field_name: IdentUnique,
376        /// Only public fields if `is_public_struct_access` is true.
377        available_fields: Vec<Ident>,
378        is_public_struct_access: bool,
379        /// Original, non-aliased struct name.
380        struct_name: Ident,
381        struct_decl_span: Span,
382        struct_is_empty: bool,
383        usage_context: StructFieldUsageContext,
384    },
385    #[error("Field \"{field_name}\" has multiple definitions.")]
386    StructFieldDuplicated { field_name: Ident, duplicate: Ident },
387    #[error("No method \"{method}\" found for type \"{type_name}\".{}", 
388        if matching_method_strings.is_empty() {
389            "".to_string()
390        } else {
391            format!("  \nMatching method{}:\n{}", if matching_method_strings.len()> 1 {"s"} else {""},
392            matching_method_strings.iter().map(|m| format!("    {m}")).collect::<Vec<_>>().join("\n"))
393        }
394    )]
395    MethodNotFound {
396        method: String,
397        type_name: String,
398        matching_method_strings: Vec<String>,
399        span: Span,
400    },
401    #[error("Module \"{name}\" could not be found.")]
402    ModuleNotFound { span: Span, name: String },
403    #[error("This expression has type \"{actually}\", which is not a struct. Fields can only be accessed on structs.")]
404    FieldAccessOnNonStruct {
405        actually: String,
406        /// Name of the storage variable, if the field access
407        /// happens within the access to a storage variable.
408        storage_variable: Option<String>,
409        /// Name of the field that is tried to be accessed.
410        field_name: IdentUnique,
411        span: Span,
412    },
413    #[error("This expression has type \"{actually}\", which is not a tuple. Elements can only be accessed on tuples.")]
414    TupleElementAccessOnNonTuple {
415        actually: String,
416        span: Span,
417        index: usize,
418        index_span: Span,
419    },
420    #[error("This expression has type \"{actually}\", which is not an indexable type.")]
421    NotIndexable { actually: String, span: Span },
422    #[error("\"{name}\" is a {actually}, not an enum.")]
423    NotAnEnum {
424        name: String,
425        span: Span,
426        actually: String,
427    },
428    #[error("This is a {actually}, not a struct.")]
429    NotAStruct { span: Span, actually: String },
430    #[error("This is a {actually}, not an enum.")]
431    DeclIsNotAnEnum { actually: String, span: Span },
432    #[error("This is a {actually}, not a struct.")]
433    DeclIsNotAStruct { actually: String, span: Span },
434    #[error("This is a {actually}, not a function.")]
435    DeclIsNotAFunction { actually: String, span: Span },
436    #[error("This is a {actually}, not a variable.")]
437    DeclIsNotAVariable { actually: String, span: Span },
438    #[error("This is a {actually}, not an ABI.")]
439    DeclIsNotAnAbi { actually: String, span: Span },
440    #[error("This is a {actually}, not a trait.")]
441    DeclIsNotATrait { actually: String, span: Span },
442    #[error("This is a {actually}, not an impl block.")]
443    DeclIsNotAnImplTrait { actually: String, span: Span },
444    #[error("This is a {actually}, not a trait function.")]
445    DeclIsNotATraitFn { actually: String, span: Span },
446    #[error("This is a {actually}, not storage.")]
447    DeclIsNotStorage { actually: String, span: Span },
448    #[error("This is a {actually}, not a constant")]
449    DeclIsNotAConstant { actually: String, span: Span },
450    #[error("This is a {actually}, not a type alias")]
451    DeclIsNotATypeAlias { actually: String, span: Span },
452    #[error("Could not find symbol \"{name}\" in this scope.")]
453    SymbolNotFound { name: Ident, span: Span },
454    #[error("Found multiple bindings for \"{name}\" in this scope.")]
455    SymbolWithMultipleBindings {
456        name: Ident,
457        paths: Vec<String>,
458        span: Span,
459    },
460    #[error("Symbol \"{name}\" is private.")]
461    ImportPrivateSymbol { name: Ident, span: Span },
462    #[error("Module \"{name}\" is private.")]
463    ImportPrivateModule { name: Ident, span: Span },
464    #[error(
465        "Because this if expression's value is used, an \"else\" branch is required and it must \
466         return type \"{r#type}\""
467    )]
468    NoElseBranch { span: Span, r#type: String },
469    #[error(
470        "Symbol \"{name}\" does not refer to a type, it refers to a {actually_is}. It cannot be \
471         used in this position."
472    )]
473    NotAType {
474        span: Span,
475        name: String,
476        actually_is: &'static str,
477    },
478    #[error(
479        "This enum variant requires an instantiation expression. Try initializing it with \
480         arguments in parentheses."
481    )]
482    MissingEnumInstantiator { span: Span },
483    #[error(
484        "This path must return a value of type \"{ty}\" from function \"{function_name}\", but it \
485         does not."
486    )]
487    PathDoesNotReturn {
488        span: Span,
489        ty: String,
490        function_name: Ident,
491    },
492    #[error(
493        "This register was not initialized in the initialization section of the ASM expression. \
494         Initialized registers are: {initialized_registers}"
495    )]
496    UnknownRegister {
497        span: Span,
498        initialized_registers: String,
499    },
500    #[error("This opcode takes an immediate value but none was provided.")]
501    MissingImmediate { span: Span },
502    #[error("This immediate value is invalid.")]
503    InvalidImmediateValue { span: Span },
504    #[error("Variant \"{variant_name}\" does not exist on enum \"{enum_name}\"")]
505    UnknownEnumVariant {
506        enum_name: Ident,
507        variant_name: Ident,
508        span: Span,
509    },
510    #[error("Unknown opcode: \"{op_name}\".")]
511    UnrecognizedOp { op_name: Ident, span: Span },
512    #[error("Cannot infer type for type parameter \"{ty}\". Insufficient type information provided. Try annotating its type.")]
513    UnableToInferGeneric { ty: String, span: Span },
514    #[error("The generic type parameter \"{ty}\" is unconstrained.")]
515    UnconstrainedGenericParameter { ty: String, span: Span },
516    #[error("Trait \"{trait_name}\" is not implemented for type \"{ty}\".")]
517    TraitConstraintNotSatisfied {
518        type_id: usize, // Used to filter errors in method application type check.
519        ty: String,
520        trait_name: String,
521        span: Span,
522    },
523    #[error(
524        "Expects trait constraint \"{param}: {trait_name}\" which is missing from type parameter \"{param}\"."
525    )]
526    TraitConstraintMissing {
527        param: String,
528        trait_name: String,
529        span: Span,
530    },
531    #[error("The value \"{val}\" is too large to fit in this 6-bit immediate spot.")]
532    Immediate06TooLarge { val: u64, span: Span },
533    #[error("The value \"{val}\" is too large to fit in this 12-bit immediate spot.")]
534    Immediate12TooLarge { val: u64, span: Span },
535    #[error("The value \"{val}\" is too large to fit in this 18-bit immediate spot.")]
536    Immediate18TooLarge { val: u64, span: Span },
537    #[error("The value \"{val}\" is too large to fit in this 24-bit immediate spot.")]
538    Immediate24TooLarge { val: u64, span: Span },
539    #[error(
540        "This op expects {expected} register(s) as arguments, but you provided {received} register(s)."
541    )]
542    IncorrectNumberOfAsmRegisters {
543        span: Span,
544        expected: usize,
545        received: usize,
546    },
547    #[error("This op does not take an immediate value.")]
548    UnnecessaryImmediate { span: Span },
549    #[error("This reference is ambiguous, and could refer to a module, enum, or function of the same name. Try qualifying the name with a path.")]
550    AmbiguousPath { span: Span },
551    #[error("This is a module path, and not an expression.")]
552    ModulePathIsNotAnExpression { module_path: String, span: Span },
553    #[error("Unknown type name.")]
554    UnknownType { span: Span },
555    #[error("Unknown type name \"{name}\".")]
556    UnknownTypeName { name: String, span: Span },
557    #[error("The file {file_path} could not be read: {stringified_error}")]
558    FileCouldNotBeRead {
559        span: Span,
560        file_path: String,
561        stringified_error: String,
562    },
563    #[error("This imported file must be a library. It must start with \"library;\"")]
564    ImportMustBeLibrary { span: Span },
565    #[error("An enum instantiaton cannot contain more than one value. This should be a single value of type {ty}.")]
566    MoreThanOneEnumInstantiator { span: Span, ty: String },
567    #[error("This enum variant represents the unit type, so it should not be instantiated with any value.")]
568    UnnecessaryEnumInstantiator { span: Span },
569    #[error("The enum variant `{ty}` is of type `unit`, so its constructor does not take arguments or parentheses. Try removing the ().")]
570    UnitVariantWithParenthesesEnumInstantiator { span: Span, ty: String },
571    #[error("Cannot find trait \"{name}\" in this scope.")]
572    TraitNotFound { name: String, span: Span },
573    #[error("Trait \"{trait_name}\" is not imported when calling \"{function_name}\".\nThe import is needed because \"{function_name}\" uses \"{trait_name}\" in one of its trait constraints.")]
574    TraitNotImportedAtFunctionApplication {
575        trait_name: String,
576        function_name: String,
577        function_call_site_span: Span,
578        trait_constraint_span: Span,
579        trait_candidates: Vec<String>,
580    },
581    #[error("This expression is not valid on the left hand side of a reassignment.")]
582    InvalidExpressionOnLhs { span: Span },
583    #[error("This code cannot be evaluated to a constant")]
584    CannotBeEvaluatedToConst { span: Span },
585    #[error(
586        "This code cannot be evaluated to a configurable because its size is not always limited."
587    )]
588    CannotBeEvaluatedToConfigurableSizeUnknown { span: Span },
589    #[error("{} \"{method_name}\" expects {expected} {} but you provided {received}.",
590        if *dot_syntax_used { "Method" } else { "Function" },
591        if *expected == 1usize { "argument" } else {"arguments"},
592    )]
593    TooManyArgumentsForFunction {
594        span: Span,
595        method_name: Ident,
596        dot_syntax_used: bool,
597        expected: usize,
598        received: usize,
599    },
600    #[error("{} \"{method_name}\" expects {expected} {} but you provided {received}.",
601        if *dot_syntax_used { "Method" } else { "Function" },
602        if *expected == 1usize { "argument" } else {"arguments"},
603    )]
604    TooFewArgumentsForFunction {
605        span: Span,
606        method_name: Ident,
607        dot_syntax_used: bool,
608        expected: usize,
609        received: usize,
610    },
611    #[error("The function \"{method_name}\" was called without parentheses. Try adding ().")]
612    MissingParenthesesForFunction { span: Span, method_name: Ident },
613    #[error("This type is invalid in a function selector. A contract ABI function selector must be a known sized type, not generic.")]
614    InvalidAbiType { span: Span },
615    #[error("This is a {actually_is}, not an ABI. An ABI cast requires a valid ABI to cast the address to.")]
616    NotAnAbi {
617        span: Span,
618        actually_is: &'static str,
619    },
620    #[error("An ABI can only be implemented for the `Contract` type, so this implementation of an ABI for type \"{ty}\" is invalid.")]
621    ImplAbiForNonContract { span: Span, ty: String },
622    #[error("Conflicting implementations of trait \"{trait_name}\" for type \"{type_implementing_for}\".")]
623    ConflictingImplsForTraitAndType {
624        trait_name: String,
625        type_implementing_for: String,
626        type_implementing_for_unaliased: String,
627        existing_impl_span: Span,
628        second_impl_span: Span,
629    },
630    #[error(
631        "\"{marker_trait_full_name}\" is a marker trait and cannot be explicitly implemented."
632    )]
633    MarkerTraitExplicitlyImplemented {
634        marker_trait_full_name: String,
635        span: Span,
636    },
637    #[error("Duplicate definitions for the {decl_kind} \"{decl_name}\" for type \"{type_implementing_for}\".")]
638    DuplicateDeclDefinedForType {
639        decl_kind: String,
640        decl_name: String,
641        type_implementing_for: String,
642        type_implementing_for_unaliased: String,
643        existing_impl_span: Span,
644        second_impl_span: Span,
645    },
646    #[error("The function \"{fn_name}\" in {interface_name} is defined with {num_parameters} parameters, but the provided implementation has {provided_parameters} parameters.")]
647    IncorrectNumberOfInterfaceSurfaceFunctionParameters {
648        fn_name: Ident,
649        interface_name: InterfaceName,
650        num_parameters: usize,
651        provided_parameters: usize,
652        span: Span,
653    },
654    #[error("This parameter was declared as type {should_be}, but argument of type {provided} was provided.")]
655    ArgumentParameterTypeMismatch {
656        span: Span,
657        should_be: String,
658        provided: String,
659    },
660    #[error("Function {fn_name} is recursive, which is unsupported at this time.")]
661    RecursiveCall { fn_name: Ident, span: Span },
662    #[error(
663        "Function {fn_name} is recursive via {call_chain}, which is unsupported at this time."
664    )]
665    RecursiveCallChain {
666        fn_name: Ident,
667        call_chain: String, // Pretty list of symbols, e.g., "a, b and c".
668        span: Span,
669    },
670    #[error("Type {name} is recursive, which is unsupported at this time.")]
671    RecursiveType { name: Ident, span: Span },
672    #[error("Type {name} is recursive via {type_chain}, which is unsupported at this time.")]
673    RecursiveTypeChain {
674        name: Ident,
675        type_chain: String, // Pretty list of symbols, e.g., "a, b and c".
676        span: Span,
677    },
678    #[error("The GM (get-metadata) opcode, when called from an external context, will cause the VM to panic.")]
679    GMFromExternalContext { span: Span },
680    #[error("The MINT opcode cannot be used in an external context.")]
681    MintFromExternalContext { span: Span },
682    #[error("The BURN opcode cannot be used in an external context.")]
683    BurnFromExternalContext { span: Span },
684    #[error("Contract storage cannot be used in an external context.")]
685    ContractStorageFromExternalContext { span: Span },
686    #[error("The {opcode} opcode cannot be used in a predicate.")]
687    InvalidOpcodeFromPredicate { opcode: String, span: Span },
688    #[error("Index out of bounds; the length is {count} but the index is {index}.")]
689    ArrayOutOfBounds { index: u64, count: u64, span: Span },
690    #[error(
691        "Invalid range; the range end at index {end} is smaller than its start at index {start}"
692    )]
693    InvalidRangeEndGreaterThanStart { start: u64, end: u64, span: Span },
694    #[error("Tuple index {index} is out of bounds. The tuple has {count} element{}.", plural_s(*count))]
695    TupleIndexOutOfBounds {
696        index: usize,
697        count: usize,
698        tuple_type: String,
699        span: Span,
700        prefix_span: Span,
701    },
702    #[error("Constant requires expression.")]
703    ConstantRequiresExpression { span: Span },
704    #[error("Constants cannot be shadowed. {shadowing_source} \"{name}\" shadows constant of the same name.")]
705    ConstantsCannotBeShadowed {
706        /// Defines what shadows the constant.
707        ///
708        /// Although being ready in the diagnostic, the `PatternMatchingStructFieldVar` option
709        /// is currently not used. Getting the information about imports and aliases while
710        /// type checking match branches is too much effort at the moment, compared to gained
711        /// additional clarity of the error message. We might add support for this option in
712        /// the future.
713        shadowing_source: ShadowingSource,
714        name: IdentUnique,
715        constant_span: Span,
716        constant_decl_span: Span,
717        is_alias: bool,
718    },
719    #[error("Configurables cannot be shadowed. {shadowing_source} \"{name}\" shadows configurable of the same name.")]
720    ConfigurablesCannotBeShadowed {
721        /// Defines what shadows the configurable.
722        ///
723        /// Using configurable in pattern matching, expecting to behave same as a constant,
724        /// will result in [CompileError::ConfigurablesCannotBeMatchedAgainst].
725        /// Otherwise, we would end up with a very confusing error message that
726        /// a configurable cannot be shadowed by a variable.
727        /// In the, unlikely but equally confusing, case of a struct field pattern variable
728        /// named same as the configurable we also want to provide a better explanation
729        /// and `shadowing_source` helps us distinguish that case as well.
730        shadowing_source: ShadowingSource,
731        name: IdentUnique,
732        configurable_span: Span,
733    },
734    #[error("Configurables cannot be matched against. Configurable \"{name}\" cannot be used in pattern matching.")]
735    ConfigurablesCannotBeMatchedAgainst {
736        name: IdentUnique,
737        configurable_span: Span,
738    },
739    #[error(
740        "Constants cannot shadow variables. Constant \"{name}\" shadows variable of the same name."
741    )]
742    ConstantShadowsVariable {
743        name: IdentUnique,
744        variable_span: Span,
745    },
746    #[error("{existing_constant_or_configurable} of the name \"{name}\" already exists.")]
747    ConstantDuplicatesConstantOrConfigurable {
748        /// Text "Constant" or "Configurable". Denotes already declared constant or configurable.
749        existing_constant_or_configurable: &'static str,
750        /// Text "Constant" or "Configurable". Denotes constant or configurable attempted to be declared.
751        new_constant_or_configurable: &'static str,
752        name: IdentUnique,
753        existing_span: Span,
754    },
755    #[error("Imported symbol \"{name}\" shadows another symbol of the same name.")]
756    ShadowsOtherSymbol { name: IdentUnique },
757    #[error("The name \"{name}\" is already used for a generic parameter in this scope.")]
758    GenericShadowsGeneric { name: IdentUnique },
759    #[error("Non-exhaustive match expression. Missing patterns {missing_patterns}")]
760    MatchExpressionNonExhaustive {
761        missing_patterns: String,
762        span: Span,
763    },
764    #[error("Struct pattern is missing the {}field{} {}.",
765        if *missing_fields_are_public { "public " } else { "" },
766        plural_s(missing_fields.len()),
767        sequence_to_str(missing_fields, Enclosing::DoubleQuote, 2)
768    )]
769    MatchStructPatternMissingFields {
770        missing_fields: Vec<Ident>,
771        missing_fields_are_public: bool,
772        /// Original, non-aliased struct name.
773        struct_name: Ident,
774        struct_decl_span: Span,
775        total_number_of_fields: usize,
776        span: Span,
777    },
778    #[error("Struct pattern must ignore inaccessible private field{} {}.",
779        plural_s(private_fields.len()),
780        sequence_to_str(private_fields, Enclosing::DoubleQuote, 2))]
781    MatchStructPatternMustIgnorePrivateFields {
782        private_fields: Vec<Ident>,
783        /// Original, non-aliased struct name.
784        struct_name: Ident,
785        struct_decl_span: Span,
786        all_fields_are_private: bool,
787        span: Span,
788    },
789    #[error("Variable \"{variable}\" is not defined in all alternatives.")]
790    MatchArmVariableNotDefinedInAllAlternatives {
791        match_value: Span,
792        match_type: String,
793        variable: Ident,
794        missing_in_alternatives: Vec<Span>,
795    },
796    #[error(
797        "Variable \"{variable}\" is expected to be of type \"{expected}\", but is \"{received}\"."
798    )]
799    MatchArmVariableMismatchedType {
800        match_value: Span,
801        match_type: String,
802        variable: Ident,
803        first_definition: Span,
804        expected: String,
805        received: String,
806    },
807    #[error("This cannot be matched.")]
808    MatchedValueIsNotValid {
809        /// Common message describing which Sway types
810        /// are currently supported in match expressions.
811        supported_types_message: Vec<&'static str>,
812        span: Span,
813    },
814    #[error(
815        "The function \"{fn_name}\" in {interface_name} is pure, but this \
816        implementation is not.  The \"storage\" annotation must be \
817        removed, or the trait declaration must be changed to \
818        \"#[storage({attrs})]\"."
819    )]
820    TraitDeclPureImplImpure {
821        fn_name: Ident,
822        interface_name: InterfaceName,
823        attrs: String,
824        span: Span,
825    },
826    #[error(
827        "Storage attribute access mismatch. The function \"{fn_name}\" in \
828        {interface_name} requires the storage attribute(s) #[storage({attrs})]."
829    )]
830    TraitImplPurityMismatch {
831        fn_name: Ident,
832        interface_name: InterfaceName,
833        attrs: String,
834        span: Span,
835    },
836    #[error("Impure function inside of non-contract. Contract storage is only accessible from contracts.")]
837    ImpureInNonContract { span: Span },
838    #[error(
839        "This function performs storage access but does not have the required storage \
840        attribute(s). Try adding \"#[storage({suggested_attributes})]\" to the function \
841        declaration."
842    )]
843    StorageAccessMismatched {
844        /// True if the function with mismatched access is pure.
845        is_pure: bool,
846        storage_access_violations: Vec<(Span, StorageAccess)>,
847        suggested_attributes: String,
848        /// Span pointing to the name of the function in the function declaration,
849        /// whose storage attributes mismatch the storage access patterns.
850        span: Span,
851    },
852    #[error(
853        "Parameter reference type or mutability mismatch between the trait function declaration and its implementation."
854    )]
855    ParameterRefMutabilityMismatch { span: Span },
856    #[error("Literal value is too large for type {ty}.")]
857    IntegerTooLarge { span: Span, ty: String },
858    #[error("Literal value underflows type {ty}.")]
859    IntegerTooSmall { span: Span, ty: String },
860    #[error("Literal value contains digits which are not valid for type {ty}.")]
861    IntegerContainsInvalidDigit { span: Span, ty: String },
862    #[error("A trait cannot be a subtrait of an ABI.")]
863    AbiAsSupertrait { span: Span },
864    #[error(
865        "Implementation of trait \"{supertrait_name}\" is required by this bound in \"{trait_name}\""
866    )]
867    SupertraitImplRequired {
868        supertrait_name: String,
869        trait_name: Ident,
870        span: Span,
871    },
872    #[error(
873        "Contract ABI method parameter \"{param_name}\" is set multiple times for this contract ABI method call"
874    )]
875    ContractCallParamRepeated { param_name: String, span: Span },
876    #[error(
877        "Unrecognized contract ABI method parameter \"{param_name}\". The only available parameters are \"gas\", \"coins\", and \"asset_id\""
878    )]
879    UnrecognizedContractParam { param_name: String, span: Span },
880    #[error("Attempting to specify a contract method parameter for a non-contract function call")]
881    CallParamForNonContractCallMethod { span: Span },
882    #[error("Storage field \"{field_name}\" does not exist.")]
883    StorageFieldDoesNotExist {
884        field_name: IdentUnique,
885        available_fields: Vec<(Vec<Ident>, Ident)>,
886        storage_decl_span: Span,
887    },
888    #[error("No storage has been declared")]
889    NoDeclaredStorage { span: Span },
890    #[error("Multiple storage declarations were found")]
891    MultipleStorageDeclarations { span: Span },
892    #[error("Type {ty} can only be declared directly as a storage field")]
893    InvalidStorageOnlyTypeDecl { ty: String, span: Span },
894    #[error(
895        "Internal compiler error: Unexpected {decl_type} declaration found.\n\
896        Please file an issue on the repository and include the code that triggered this error."
897    )]
898    UnexpectedDeclaration { decl_type: &'static str, span: Span },
899    #[error("This contract caller has no known address. Try instantiating a contract caller with a known contract address instead.")]
900    ContractAddressMustBeKnown { span: Span },
901    #[error("{}", error)]
902    ConvertParseTree {
903        #[from]
904        error: ConvertParseTreeError,
905    },
906    #[error("{}", error)]
907    Lex { error: LexError },
908    #[error("{}", error)]
909    Parse { error: ParseError },
910    #[error("Could not evaluate initializer to a const declaration.")]
911    NonConstantDeclValue { span: Span },
912    #[error("Declaring storage in a {program_kind} is not allowed.")]
913    StorageDeclarationInNonContract { program_kind: String, span: Span },
914    #[error("Unsupported argument type to intrinsic \"{name}\".{}", if hint.is_empty() { "".to_string() } else { format!(" Hint: {hint}") })]
915    IntrinsicUnsupportedArgType {
916        name: String,
917        span: Span,
918        hint: String,
919    },
920    #[error("Call to \"{name}\" expects {expected} argument(s)")]
921    IntrinsicIncorrectNumArgs {
922        name: String,
923        expected: u64,
924        span: Span,
925    },
926    #[error("Call to \"{name}\" expects {expected} type arguments")]
927    IntrinsicIncorrectNumTArgs {
928        name: String,
929        expected: u64,
930        span: Span,
931    },
932    #[error("Expected string literal")]
933    ExpectedStringLiteral { span: Span },
934    #[error("\"break\" used outside of a loop")]
935    BreakOutsideLoop { span: Span },
936    #[error("\"continue\" used outside of a loop")]
937    ContinueOutsideLoop { span: Span },
938    /// This will be removed once loading contract IDs in a dependency namespace is refactored and no longer manual:
939    /// https://github.com/FuelLabs/sway/issues/3077
940    #[error("Contract ID value is not a literal.")]
941    ContractIdValueNotALiteral { span: Span },
942
943    #[error("{reason}")]
944    TypeNotAllowed {
945        reason: TypeNotAllowedReason,
946        span: Span,
947    },
948    #[error("ref mut parameter not allowed for main()")]
949    RefMutableNotAllowedInMain { param_name: Ident, span: Span },
950    #[error(
951        "Register \"{name}\" is initialized and later reassigned which is not allowed. \
952            Consider assigning to a different register inside the ASM block."
953    )]
954    InitializedRegisterReassignment { name: String, span: Span },
955    #[error("Control flow VM instructions are not allowed in assembly blocks.")]
956    DisallowedControlFlowInstruction { name: String, span: Span },
957    #[error("Calling private library method {name} is not allowed.")]
958    CallingPrivateLibraryMethod { name: String, span: Span },
959    #[error("Using intrinsic \"{intrinsic}\" in a predicate is not allowed.")]
960    DisallowedIntrinsicInPredicate { intrinsic: String, span: Span },
961    #[error("Possibly non-zero amount of coins transferred to non-payable contract method \"{fn_name}\".")]
962    CoinsPassedToNonPayableMethod { fn_name: Ident, span: Span },
963    #[error(
964        "Payable attribute mismatch. The \"{fn_name}\" method implementation \
965         {} in its signature in {interface_name}.",
966        if *missing_impl_attribute {
967            "is missing #[payable] attribute specified"
968        } else {
969            "has extra #[payable] attribute not mentioned"
970        }
971    )]
972    TraitImplPayabilityMismatch {
973        fn_name: Ident,
974        interface_name: InterfaceName,
975        missing_impl_attribute: bool,
976        span: Span,
977    },
978    #[error("Configurable constants are not allowed in libraries.")]
979    ConfigurableInLibrary { span: Span },
980    #[error("Multiple applicable items in scope. {}", {
981        let mut candidates = "".to_string();
982        let mut as_traits = as_traits.clone();
983        // Make order deterministic
984        as_traits.sort_by_key(|a| a.0.to_lowercase());
985        for (index, as_trait) in as_traits.iter().enumerate() {
986            candidates = format!("{candidates}\n  Disambiguate the associated {item_kind} for candidate #{index}\n    <{} as {}>::{item_name}", as_trait.1, as_trait.0);
987        }
988        candidates
989    })]
990    MultipleApplicableItemsInScope {
991        span: Span,
992        item_name: String,
993        item_kind: String,
994        as_traits: Vec<(String, String)>,
995    },
996    #[error("Provided generic type is not of type str.")]
997    NonStrGenericType { span: Span },
998    #[error("A contract method cannot call methods belonging to the same ABI")]
999    ContractCallsItsOwnMethod { span: Span },
1000    #[error("ABI cannot define a method of the same name as its super-ABI \"{superabi}\"")]
1001    AbiShadowsSuperAbiMethod { span: Span, superabi: Ident },
1002    #[error("ABI cannot inherit samely named method (\"{method_name}\") from several super-ABIs: \"{superabi1}\" and \"{superabi2}\"")]
1003    ConflictingSuperAbiMethods {
1004        span: Span,
1005        method_name: String,
1006        superabi1: String,
1007        superabi2: String,
1008    },
1009    #[error("Associated types not supported in ABI.")]
1010    AssociatedTypeNotSupportedInAbi { span: Span },
1011    #[error("Cannot call ABI supertrait's method as a contract method: \"{fn_name}\"")]
1012    AbiSupertraitMethodCallAsContractCall { fn_name: Ident, span: Span },
1013    #[error(
1014        "Methods {method_name} and {other_method_name} name have clashing function selectors."
1015    )]
1016    FunctionSelectorClash {
1017        method_name: Ident,
1018        span: Span,
1019        other_method_name: Ident,
1020        other_span: Span,
1021    },
1022    #[error("{invalid_type} is not a valid type in the self type of an impl block.")]
1023    TypeIsNotValidAsImplementingFor {
1024        invalid_type: InvalidImplementingForType,
1025        /// Name of the trait if the impl implements a trait, `None` otherwise.
1026        trait_name: Option<String>,
1027        span: Span,
1028    },
1029    #[error("Uninitialized register is being read before being written")]
1030    UninitRegisterInAsmBlockBeingRead { span: Span },
1031    #[error("Expression of type \"{expression_type}\" cannot be dereferenced.")]
1032    ExpressionCannotBeDereferenced { expression_type: String, span: Span },
1033    #[error("Fallback functions can only exist in contracts")]
1034    FallbackFnsAreContractOnly { span: Span },
1035    #[error("Fallback functions cannot have parameters")]
1036    FallbackFnsCannotHaveParameters { span: Span },
1037    #[error("Could not generate the entry method. See errors above for more details.")]
1038    CouldNotGenerateEntry { span: Span },
1039    #[error("Missing `std` in dependencies.")]
1040    CouldNotGenerateEntryMissingStd { span: Span },
1041    #[error("Type \"{ty}\" does not implement AbiEncode or AbiDecode.")]
1042    CouldNotGenerateEntryMissingImpl { ty: String, span: Span },
1043    #[error("Only bool, u8, u16, u32, u64, u256, b256, string arrays and string slices can be used here.")]
1044    EncodingUnsupportedType { span: Span },
1045    #[error("Configurables need a function named \"abi_decode_in_place\" to be in scope.")]
1046    ConfigurableMissingAbiDecodeInPlace { span: Span },
1047    #[error("Invalid name found for renamed ABI type.\n")]
1048    ABIInvalidName { span: Span, name: String },
1049    #[error("Duplicated name found for renamed ABI type.\n")]
1050    ABIDuplicateName {
1051        span: Span,
1052        other_span: Span,
1053        is_attribute: bool,
1054    },
1055    #[error("Collision detected between two different types.\n  Shared hash:{hash}\n  First type:{first_type}\n  Second type:{second_type}")]
1056    ABIHashCollision {
1057        span: Span,
1058        hash: String,
1059        first_type: String,
1060        second_type: String,
1061    },
1062    #[error("Type must be known at this point")]
1063    TypeMustBeKnownAtThisPoint { span: Span, internal: String },
1064    #[error("Multiple impls satisfying trait for type.")]
1065    MultipleImplsSatisfyingTraitForType {
1066        span: Span,
1067        type_annotation: String,
1068        trait_names: Vec<String>,
1069        trait_types_and_names: Vec<(String, String)>,
1070    },
1071    #[error("Multiple contracts methods with the same name.")]
1072    MultipleContractsMethodsWithTheSameName { spans: Vec<Span> },
1073    #[error("Error type enum \"{enum_name}\" has non-error variant{} {}. All variants must be marked as `#[error]`.",
1074        plural_s(non_error_variants.len()),
1075        sequence_to_str(non_error_variants, Enclosing::DoubleQuote, 2)
1076    )]
1077    ErrorTypeEnumHasNonErrorVariants {
1078        enum_name: IdentUnique,
1079        non_error_variants: Vec<IdentUnique>,
1080    },
1081    #[error("Enum variant \"{enum_variant_name}\" is marked as `#[error]`, but \"{enum_name}\" is not an `#[error_type]` enum.")]
1082    ErrorAttributeInNonErrorEnum {
1083        enum_name: IdentUnique,
1084        enum_variant_name: IdentUnique,
1085    },
1086    #[error("This expression has type \"{argument_type}\", which does not implement \"std::marker::Error\". Panic expression arguments must implement \"Error\".")]
1087    PanicExpressionArgumentIsNotError { argument_type: String, span: Span },
1088    #[error("Coherence violation: only traits defined in this crate can be implemented for external types.")]
1089    IncoherentImplDueToOrphanRule {
1090        trait_name: String,
1091        type_name: String,
1092        span: Span,
1093    },
1094}
1095
1096impl std::convert::From<TypeError> for CompileError {
1097    fn from(other: TypeError) -> CompileError {
1098        CompileError::TypeError(other)
1099    }
1100}
1101
1102impl Spanned for CompileError {
1103    fn span(&self) -> Span {
1104        use CompileError::*;
1105        match self {
1106            ConstGenericNotSupportedHere { span } => span.clone(),
1107            LengthExpressionNotSupported { span } => span.clone(),
1108            FeatureIsDisabled { span, .. } => span.clone(),
1109            ModuleDepGraphEvaluationError { .. } => Span::dummy(),
1110            ModuleDepGraphCyclicReference { .. } => Span::dummy(),
1111            UnknownVariable { span, .. } => span.clone(),
1112            NotAVariable { span, .. } => span.clone(),
1113            Unimplemented { span, .. } => span.clone(),
1114            TypeError(err) => err.span(),
1115            ParseError { span, .. } => span.clone(),
1116            Internal(_, span) => span.clone(),
1117            InternalOwned(_, span) => span.clone(),
1118            NoPredicateMainFunction(span) => span.clone(),
1119            PredicateMainDoesNotReturnBool(span) => span.clone(),
1120            NoScriptMainFunction(span) => span.clone(),
1121            MultipleDefinitionsOfFunction { span, .. } => span.clone(),
1122            MultipleDefinitionsOfName { span, .. } => span.clone(),
1123            MultipleDefinitionsOfConstant { new: span, .. } => span.clone(),
1124            MultipleDefinitionsOfType { span, .. } => span.clone(),
1125            MultipleDefinitionsOfMatchArmVariable { duplicate, .. } => duplicate.clone(),
1126            MultipleDefinitionsOfFallbackFunction { span, .. } => span.clone(),
1127            AssignmentToNonMutableVariable { lhs_span, .. } => lhs_span.clone(),
1128            AssignmentToConstantOrConfigurable { lhs_span, .. } => lhs_span.clone(),
1129            DeclAssignmentTargetCannotBeAssignedTo { lhs_span, .. } => lhs_span.clone(),
1130            AssignmentViaNonMutableReference { span, .. } => span.clone(),
1131            MutableParameterNotSupported { span, .. } => span.clone(),
1132            ImmutableArgumentToMutableParameter { span } => span.clone(),
1133            RefMutableNotAllowedInContractAbi { span, .. } => span.clone(),
1134            RefMutCannotReferenceConstant { span, .. } => span.clone(),
1135            RefMutCannotReferenceImmutableVariable { span, .. } => span.clone(),
1136            MethodRequiresMutableSelf { span, .. } => span.clone(),
1137            AssociatedFunctionCalledAsMethod { span, .. } => span.clone(),
1138            TypeParameterNotInTypeScope { span, .. } => span.clone(),
1139            MismatchedTypeInInterfaceSurface { span, .. } => span.clone(),
1140            UnknownTrait { span, .. } => span.clone(),
1141            FunctionNotAPartOfInterfaceSurface { span, .. } => span.clone(),
1142            ConstantNotAPartOfInterfaceSurface { span, .. } => span.clone(),
1143            TypeNotAPartOfInterfaceSurface { span, .. } => span.clone(),
1144            MissingInterfaceSurfaceConstants { span, .. } => span.clone(),
1145            MissingInterfaceSurfaceTypes { span, .. } => span.clone(),
1146            MissingInterfaceSurfaceMethods { span, .. } => span.clone(),
1147            IncorrectNumberOfTypeArguments { span, .. } => span.clone(),
1148            DoesNotTakeTypeArguments { span, .. } => span.clone(),
1149            DoesNotTakeTypeArgumentsAsPrefix { span, .. } => span.clone(),
1150            TypeArgumentsNotAllowed { span } => span.clone(),
1151            NeedsTypeArguments { span, .. } => span.clone(),
1152            StructInstantiationMissingFieldForErrorRecovery { span, .. } => span.clone(),
1153            StructInstantiationMissingFields { span, .. } => span.clone(),
1154            StructCannotBeInstantiated { span, .. } => span.clone(),
1155            StructFieldIsPrivate { field_name, .. } => field_name.span(),
1156            StructFieldDoesNotExist { field_name, .. } => field_name.span(),
1157            StructFieldDuplicated { field_name, .. } => field_name.span(),
1158            MethodNotFound { span, .. } => span.clone(),
1159            ModuleNotFound { span, .. } => span.clone(),
1160            TupleElementAccessOnNonTuple { span, .. } => span.clone(),
1161            NotAStruct { span, .. } => span.clone(),
1162            NotIndexable { span, .. } => span.clone(),
1163            FieldAccessOnNonStruct { span, .. } => span.clone(),
1164            SymbolNotFound { span, .. } => span.clone(),
1165            SymbolWithMultipleBindings { span, .. } => span.clone(),
1166            ImportPrivateSymbol { span, .. } => span.clone(),
1167            ImportPrivateModule { span, .. } => span.clone(),
1168            NoElseBranch { span, .. } => span.clone(),
1169            NotAType { span, .. } => span.clone(),
1170            MissingEnumInstantiator { span, .. } => span.clone(),
1171            PathDoesNotReturn { span, .. } => span.clone(),
1172            UnknownRegister { span, .. } => span.clone(),
1173            MissingImmediate { span, .. } => span.clone(),
1174            InvalidImmediateValue { span, .. } => span.clone(),
1175            UnknownEnumVariant { span, .. } => span.clone(),
1176            UnrecognizedOp { span, .. } => span.clone(),
1177            UnableToInferGeneric { span, .. } => span.clone(),
1178            UnconstrainedGenericParameter { span, .. } => span.clone(),
1179            TraitConstraintNotSatisfied { span, .. } => span.clone(),
1180            TraitConstraintMissing { span, .. } => span.clone(),
1181            Immediate06TooLarge { span, .. } => span.clone(),
1182            Immediate12TooLarge { span, .. } => span.clone(),
1183            Immediate18TooLarge { span, .. } => span.clone(),
1184            Immediate24TooLarge { span, .. } => span.clone(),
1185            IncorrectNumberOfAsmRegisters { span, .. } => span.clone(),
1186            UnnecessaryImmediate { span, .. } => span.clone(),
1187            AmbiguousPath { span } => span.clone(),
1188            ModulePathIsNotAnExpression { span, .. } => span.clone(),
1189            UnknownType { span, .. } => span.clone(),
1190            UnknownTypeName { span, .. } => span.clone(),
1191            FileCouldNotBeRead { span, .. } => span.clone(),
1192            ImportMustBeLibrary { span, .. } => span.clone(),
1193            MoreThanOneEnumInstantiator { span, .. } => span.clone(),
1194            UnnecessaryEnumInstantiator { span, .. } => span.clone(),
1195            UnitVariantWithParenthesesEnumInstantiator { span, .. } => span.clone(),
1196            TraitNotFound { span, .. } => span.clone(),
1197            TraitNotImportedAtFunctionApplication {
1198                function_call_site_span,
1199                ..
1200            } => function_call_site_span.clone(),
1201            InvalidExpressionOnLhs { span, .. } => span.clone(),
1202            TooManyArgumentsForFunction { span, .. } => span.clone(),
1203            TooFewArgumentsForFunction { span, .. } => span.clone(),
1204            MissingParenthesesForFunction { span, .. } => span.clone(),
1205            InvalidAbiType { span, .. } => span.clone(),
1206            NotAnAbi { span, .. } => span.clone(),
1207            ImplAbiForNonContract { span, .. } => span.clone(),
1208            ConflictingImplsForTraitAndType {
1209                second_impl_span, ..
1210            } => second_impl_span.clone(),
1211            MarkerTraitExplicitlyImplemented { span, .. } => span.clone(),
1212            DuplicateDeclDefinedForType {
1213                second_impl_span, ..
1214            } => second_impl_span.clone(),
1215            IncorrectNumberOfInterfaceSurfaceFunctionParameters { span, .. } => span.clone(),
1216            ArgumentParameterTypeMismatch { span, .. } => span.clone(),
1217            RecursiveCall { span, .. } => span.clone(),
1218            RecursiveCallChain { span, .. } => span.clone(),
1219            RecursiveType { span, .. } => span.clone(),
1220            RecursiveTypeChain { span, .. } => span.clone(),
1221            GMFromExternalContext { span, .. } => span.clone(),
1222            MintFromExternalContext { span, .. } => span.clone(),
1223            BurnFromExternalContext { span, .. } => span.clone(),
1224            ContractStorageFromExternalContext { span, .. } => span.clone(),
1225            InvalidOpcodeFromPredicate { span, .. } => span.clone(),
1226            ArrayOutOfBounds { span, .. } => span.clone(),
1227            ConstantRequiresExpression { span, .. } => span.clone(),
1228            ConstantsCannotBeShadowed { name, .. } => name.span(),
1229            ConfigurablesCannotBeShadowed { name, .. } => name.span(),
1230            ConfigurablesCannotBeMatchedAgainst { name, .. } => name.span(),
1231            ConstantShadowsVariable { name, .. } => name.span(),
1232            ConstantDuplicatesConstantOrConfigurable { name, .. } => name.span(),
1233            ShadowsOtherSymbol { name } => name.span(),
1234            GenericShadowsGeneric { name } => name.span(),
1235            MatchExpressionNonExhaustive { span, .. } => span.clone(),
1236            MatchStructPatternMissingFields { span, .. } => span.clone(),
1237            MatchStructPatternMustIgnorePrivateFields { span, .. } => span.clone(),
1238            MatchArmVariableNotDefinedInAllAlternatives { variable, .. } => variable.span(),
1239            MatchArmVariableMismatchedType { variable, .. } => variable.span(),
1240            MatchedValueIsNotValid { span, .. } => span.clone(),
1241            NotAnEnum { span, .. } => span.clone(),
1242            TraitDeclPureImplImpure { span, .. } => span.clone(),
1243            TraitImplPurityMismatch { span, .. } => span.clone(),
1244            DeclIsNotAnEnum { span, .. } => span.clone(),
1245            DeclIsNotAStruct { span, .. } => span.clone(),
1246            DeclIsNotAFunction { span, .. } => span.clone(),
1247            DeclIsNotAVariable { span, .. } => span.clone(),
1248            DeclIsNotAnAbi { span, .. } => span.clone(),
1249            DeclIsNotATrait { span, .. } => span.clone(),
1250            DeclIsNotAnImplTrait { span, .. } => span.clone(),
1251            DeclIsNotATraitFn { span, .. } => span.clone(),
1252            DeclIsNotStorage { span, .. } => span.clone(),
1253            DeclIsNotAConstant { span, .. } => span.clone(),
1254            DeclIsNotATypeAlias { span, .. } => span.clone(),
1255            ImpureInNonContract { span, .. } => span.clone(),
1256            StorageAccessMismatched { span, .. } => span.clone(),
1257            ParameterRefMutabilityMismatch { span, .. } => span.clone(),
1258            IntegerTooLarge { span, .. } => span.clone(),
1259            IntegerTooSmall { span, .. } => span.clone(),
1260            IntegerContainsInvalidDigit { span, .. } => span.clone(),
1261            AbiAsSupertrait { span, .. } => span.clone(),
1262            SupertraitImplRequired { span, .. } => span.clone(),
1263            ContractCallParamRepeated { span, .. } => span.clone(),
1264            UnrecognizedContractParam { span, .. } => span.clone(),
1265            CallParamForNonContractCallMethod { span, .. } => span.clone(),
1266            StorageFieldDoesNotExist { field_name, .. } => field_name.span(),
1267            InvalidStorageOnlyTypeDecl { span, .. } => span.clone(),
1268            NoDeclaredStorage { span, .. } => span.clone(),
1269            MultipleStorageDeclarations { span, .. } => span.clone(),
1270            UnexpectedDeclaration { span, .. } => span.clone(),
1271            ContractAddressMustBeKnown { span, .. } => span.clone(),
1272            ConvertParseTree { error } => error.span(),
1273            Lex { error } => error.span(),
1274            Parse { error } => error.span.clone(),
1275            EnumNotFound { span, .. } => span.clone(),
1276            TupleIndexOutOfBounds { span, .. } => span.clone(),
1277            NonConstantDeclValue { span, .. } => span.clone(),
1278            StorageDeclarationInNonContract { span, .. } => span.clone(),
1279            IntrinsicUnsupportedArgType { span, .. } => span.clone(),
1280            IntrinsicIncorrectNumArgs { span, .. } => span.clone(),
1281            IntrinsicIncorrectNumTArgs { span, .. } => span.clone(),
1282            BreakOutsideLoop { span } => span.clone(),
1283            ContinueOutsideLoop { span } => span.clone(),
1284            ContractIdValueNotALiteral { span } => span.clone(),
1285            RefMutableNotAllowedInMain { span, .. } => span.clone(),
1286            InitializedRegisterReassignment { span, .. } => span.clone(),
1287            DisallowedControlFlowInstruction { span, .. } => span.clone(),
1288            CallingPrivateLibraryMethod { span, .. } => span.clone(),
1289            DisallowedIntrinsicInPredicate { span, .. } => span.clone(),
1290            CoinsPassedToNonPayableMethod { span, .. } => span.clone(),
1291            TraitImplPayabilityMismatch { span, .. } => span.clone(),
1292            ConfigurableInLibrary { span } => span.clone(),
1293            MultipleApplicableItemsInScope { span, .. } => span.clone(),
1294            NonStrGenericType { span } => span.clone(),
1295            CannotBeEvaluatedToConst { span } => span.clone(),
1296            ContractCallsItsOwnMethod { span } => span.clone(),
1297            AbiShadowsSuperAbiMethod { span, .. } => span.clone(),
1298            ConflictingSuperAbiMethods { span, .. } => span.clone(),
1299            AssociatedTypeNotSupportedInAbi { span, .. } => span.clone(),
1300            AbiSupertraitMethodCallAsContractCall { span, .. } => span.clone(),
1301            FunctionSelectorClash { span, .. } => span.clone(),
1302            TypeNotAllowed { span, .. } => span.clone(),
1303            ExpectedStringLiteral { span } => span.clone(),
1304            TypeIsNotValidAsImplementingFor { span, .. } => span.clone(),
1305            UninitRegisterInAsmBlockBeingRead { span } => span.clone(),
1306            ExpressionCannotBeDereferenced { span, .. } => span.clone(),
1307            FallbackFnsAreContractOnly { span } => span.clone(),
1308            FallbackFnsCannotHaveParameters { span } => span.clone(),
1309            CouldNotGenerateEntry { span } => span.clone(),
1310            CouldNotGenerateEntryMissingStd { span } => span.clone(),
1311            CouldNotGenerateEntryMissingImpl { span, .. } => span.clone(),
1312            CannotBeEvaluatedToConfigurableSizeUnknown { span } => span.clone(),
1313            EncodingUnsupportedType { span } => span.clone(),
1314            ConfigurableMissingAbiDecodeInPlace { span } => span.clone(),
1315            ABIInvalidName { span, .. } => span.clone(),
1316            ABIDuplicateName { span, .. } => span.clone(),
1317            ABIHashCollision { span, .. } => span.clone(),
1318            InvalidRangeEndGreaterThanStart { span, .. } => span.clone(),
1319            TypeMustBeKnownAtThisPoint { span, .. } => span.clone(),
1320            MultipleImplsSatisfyingTraitForType { span, .. } => span.clone(),
1321            MultipleContractsMethodsWithTheSameName { spans } => spans[0].clone(),
1322            ErrorTypeEnumHasNonErrorVariants { enum_name, .. } => enum_name.span(),
1323            ErrorAttributeInNonErrorEnum {
1324                enum_variant_name, ..
1325            } => enum_variant_name.span(),
1326            PanicExpressionArgumentIsNotError { span, .. } => span.clone(),
1327            IncoherentImplDueToOrphanRule { span, .. } => span.clone(),
1328        }
1329    }
1330}
1331
1332// When implementing diagnostics, follow these two guidelines outlined in the Expressive Diagnostics RFC:
1333// - Guide-level explanation: https://github.com/FuelLabs/sway-rfcs/blob/master/rfcs/0011-expressive-diagnostics.md#guide-level-explanation
1334// - Wording guidelines: https://github.com/FuelLabs/sway-rfcs/blob/master/rfcs/0011-expressive-diagnostics.md#wording-guidelines
1335// For concrete examples, look at the existing diagnostics.
1336//
1337// The issue and the hints are not displayed if set to `Span::dummy()`.
1338//
1339// NOTE: Issue level should actually be the part of the reason. But it would complicate handling of labels in the transitional
1340//       period when we still have "old-style" diagnostics.
1341//       Let's leave it like this. Refactoring currently doesn't pay off.
1342//       And our #[error] macro will anyhow encapsulate it and ensure consistency.
1343impl ToDiagnostic for CompileError {
1344    fn to_diagnostic(&self, source_engine: &SourceEngine) -> Diagnostic {
1345        let code = Code::semantic_analysis;
1346        use CompileError::*;
1347        match self {
1348            ConstantsCannotBeShadowed { shadowing_source, name, constant_span, constant_decl_span, is_alias } => Diagnostic {
1349                reason: Some(Reason::new(code(1), "Constants cannot be shadowed".to_string())),
1350                issue: Issue::error(
1351                    source_engine,
1352                    name.span(),
1353                    format!(
1354                        // Variable "x" shadows constant with of same name.
1355                        //  or
1356                        // Constant "x" shadows imported constant of the same name.
1357                        //  or
1358                        // ...
1359                        "{shadowing_source} \"{name}\" shadows {}constant of the same name.",
1360                        if constant_decl_span.clone() != Span::dummy() { "imported " } else { "" }
1361                    )
1362                ),
1363                hints: vec![
1364                    Hint::info(
1365                        source_engine,
1366                        constant_span.clone(),
1367                        format!(
1368                            // Shadowed constant "x" is declared here.
1369                            //  or
1370                            // Shadowed constant "x" gets imported here.
1371                            //  or
1372                            // ...
1373                            "Shadowed constant \"{name}\" {} here{}.",
1374                            if constant_decl_span.clone() != Span::dummy() { "gets imported" } else { "is declared" },
1375                            if *is_alias { " as alias" } else { "" }
1376                        )
1377                    ),
1378                    if matches!(shadowing_source, PatternMatchingStructFieldVar) {
1379                        Hint::help(
1380                            source_engine,
1381                            name.span(),
1382                            format!("\"{name}\" is a struct field that defines a pattern variable of the same name.")
1383                        )
1384                    } else {
1385                        Hint::none()
1386                    },
1387                    Hint::info( // Ignored if the `constant_decl_span` is `Span::dummy()`.
1388                        source_engine,
1389                        constant_decl_span.clone(),
1390                        format!("This is the original declaration of the imported constant \"{name}\".")
1391                    ),
1392                ],
1393                help: vec![
1394                    "Unlike variables, constants cannot be shadowed by other constants or variables.".to_string(),
1395                    match (shadowing_source, *constant_decl_span != Span::dummy()) {
1396                        (LetVar | PatternMatchingStructFieldVar, false) => format!("Consider renaming either the {} \"{name}\" or the constant \"{name}\".", 
1397                            format!("{shadowing_source}").to_lowercase(),
1398                        ),
1399                        (Const, false) => "Consider renaming one of the constants.".to_string(),
1400                        (shadowing_source, true) => format!(
1401                            "Consider renaming the {} \"{name}\" or using {} for the imported constant.",
1402                            format!("{shadowing_source}").to_lowercase(),
1403                            if *is_alias { "a different alias" } else { "an alias" }
1404                        ),
1405                    },
1406                    if matches!(shadowing_source, PatternMatchingStructFieldVar) {
1407                        format!("To rename the pattern variable use the `:`. E.g.: `{name}: some_other_name`.")
1408                    } else {
1409                        Diagnostic::help_none()
1410                    }
1411                ],
1412            },
1413            ConfigurablesCannotBeShadowed { shadowing_source, name, configurable_span } => Diagnostic {
1414                reason: Some(Reason::new(code(1), "Configurables cannot be shadowed".to_string())),
1415                issue: Issue::error(
1416                    source_engine,
1417                    name.span(),
1418                    format!("{shadowing_source} \"{name}\" shadows configurable of the same name.")
1419                ),
1420                hints: vec![
1421                    Hint::info(
1422                        source_engine,
1423                        configurable_span.clone(),
1424                        format!("Shadowed configurable \"{name}\" is declared here.")
1425                    ),
1426                    if matches!(shadowing_source, PatternMatchingStructFieldVar) {
1427                        Hint::help(
1428                            source_engine,
1429                            name.span(),
1430                            format!("\"{name}\" is a struct field that defines a pattern variable of the same name.")
1431                        )
1432                    } else {
1433                        Hint::none()
1434                    },
1435                ],
1436                help: vec![
1437                    "Unlike variables, configurables cannot be shadowed by constants or variables.".to_string(),
1438                    format!(
1439                        "Consider renaming either the {} \"{name}\" or the configurable \"{name}\".",
1440                        format!("{shadowing_source}").to_lowercase()
1441                    ),
1442                    if matches!(shadowing_source, PatternMatchingStructFieldVar) {
1443                        format!("To rename the pattern variable use the `:`. E.g.: `{name}: some_other_name`.")
1444                    } else {
1445                        Diagnostic::help_none()
1446                    }
1447                ],
1448            },
1449            ConfigurablesCannotBeMatchedAgainst { name, configurable_span } => Diagnostic {
1450                reason: Some(Reason::new(code(1), "Configurables cannot be matched against".to_string())),
1451                issue: Issue::error(
1452                    source_engine,
1453                    name.span(),
1454                    format!("\"{name}\" is a configurable and configurables cannot be matched against.")
1455                ),
1456                hints: {
1457                    let mut hints = vec![
1458                        Hint::info(
1459                            source_engine,
1460                            configurable_span.clone(),
1461                            format!("Configurable \"{name}\" is declared here.")
1462                        ),
1463                    ];
1464
1465                    hints.append(&mut Hint::multi_help(source_engine, &name.span(), vec![
1466                        format!("Are you trying to define a pattern variable named \"{name}\"?"),
1467                        format!("In that case, use some other name for the pattern variable,"),
1468                        format!("or consider renaming the configurable \"{name}\"."),
1469                    ]));
1470
1471                    hints
1472                },
1473                help: vec![
1474                    "Unlike constants, configurables cannot be matched against in pattern matching.".to_string(),
1475                    "That's not possible, because patterns to match against must be compile-time constants.".to_string(),
1476                    "Configurables are run-time constants. Their values are defined during the deployment.".to_string(),
1477                    Diagnostic::help_empty_line(),
1478                    "To test against a configurable, consider:".to_string(),
1479                    format!("{}- replacing the `match` expression with `if-else`s altogether.", Indent::Single),
1480                    format!("{}- matching against a variable and comparing that variable afterwards with the configurable.", Indent::Single),
1481                    format!("{}  E.g., instead of:", Indent::Single),
1482                    Diagnostic::help_empty_line(),
1483                    format!("{}  SomeStruct {{ x: A_CONFIGURABLE, y: 42 }} => {{", Indent::Double),
1484                    format!("{}      do_something();", Indent::Double),
1485                    format!("{}  }}", Indent::Double),
1486                    Diagnostic::help_empty_line(),
1487                    format!("{}  to have:", Indent::Single),
1488                    Diagnostic::help_empty_line(),
1489                    format!("{}  SomeStruct {{ x, y: 42 }} => {{", Indent::Double),
1490                    format!("{}      if x == A_CONFIGURABLE {{", Indent::Double),
1491                    format!("{}          do_something();", Indent::Double),
1492                    format!("{}      }}", Indent::Double),
1493                    format!("{}  }}", Indent::Double),
1494                ],
1495            },
1496            ConstantShadowsVariable { name , variable_span } => Diagnostic {
1497                reason: Some(Reason::new(code(1), "Constants cannot shadow variables".to_string())),
1498                issue: Issue::error(
1499                    source_engine,
1500                    name.span(),
1501                    format!("Constant \"{name}\" shadows variable of the same name.")
1502                ),
1503                hints: vec![
1504                    Hint::info(
1505                        source_engine,
1506                        variable_span.clone(),
1507                        format!("This is the shadowed variable \"{name}\".")
1508                    ),
1509                ],
1510                help: vec![
1511                    format!("Variables can shadow other variables, but constants cannot."),
1512                    format!("Consider renaming either the variable or the constant."),
1513                ],
1514            },
1515            ConstantDuplicatesConstantOrConfigurable { existing_constant_or_configurable, new_constant_or_configurable, name, existing_span } => Diagnostic {
1516                reason: Some(Reason::new(code(1), match (*existing_constant_or_configurable, *new_constant_or_configurable) {
1517                    ("Constant", "Constant") => "Constant of the same name already exists".to_string(),
1518                    ("Constant", "Configurable") => "Constant of the same name as configurable already exists".to_string(),
1519                    ("Configurable", "Constant") => "Configurable of the same name as constant already exists".to_string(),
1520                    _ => unreachable!("We can have only the listed combinations. Configurable duplicating configurable is not a valid combination.")
1521                })),
1522                issue: Issue::error(
1523                    source_engine,
1524                    name.span(),
1525                    format!("{new_constant_or_configurable} \"{name}\" has the same name as an already declared {}.",
1526                        existing_constant_or_configurable.to_lowercase()
1527                    )
1528                ),
1529                hints: vec![
1530                    Hint::info(
1531                        source_engine,
1532                        existing_span.clone(),
1533                        format!("{existing_constant_or_configurable} \"{name}\" is {}declared here.",
1534                            // If a constant clashes with an already declared constant.
1535                            if existing_constant_or_configurable == new_constant_or_configurable {
1536                                "already "
1537                            } else {
1538                                ""
1539                            }
1540                        )
1541                    ),
1542                ],
1543                help: vec![
1544                    match (*existing_constant_or_configurable, *new_constant_or_configurable) {
1545                        ("Constant", "Constant") => "Consider renaming one of the constants, or in case of imported constants, using an alias.".to_string(),
1546                        _ => "Consider renaming either the configurable or the constant, or in case of an imported constant, using an alias.".to_string(),
1547                    },
1548                ],
1549            },
1550            MultipleDefinitionsOfMatchArmVariable { match_value, match_type, first_definition, first_definition_is_struct_field, duplicate, duplicate_is_struct_field } => Diagnostic {
1551                reason: Some(Reason::new(code(1), "Match pattern variable is already defined".to_string())),
1552                issue: Issue::error(
1553                    source_engine,
1554                    duplicate.clone(),
1555                    format!("Variable \"{}\" is already defined in this match arm.", first_definition.as_str())
1556                ),
1557                hints: vec![
1558                    Hint::help(
1559                        source_engine,
1560                        if *duplicate_is_struct_field {
1561                            duplicate.clone()
1562                        }
1563                        else {
1564                            Span::dummy()
1565                        },
1566                        format!("Struct field \"{0}\" is just a shorthand notation for `{0}: {0}`. It defines a variable \"{0}\".", first_definition.as_str())
1567                    ),
1568                    Hint::info(
1569                        source_engine,
1570                        first_definition.clone(),
1571                        format!(
1572                            "This {}is the first definition of the variable \"{}\".",
1573                            if *first_definition_is_struct_field {
1574                                format!("struct field \"{}\" ", first_definition.as_str())
1575                            }
1576                            else {
1577                                "".to_string()
1578                            },
1579                            first_definition.as_str(),
1580                        )
1581                    ),
1582                    Hint::help(
1583                        source_engine,
1584                        if *first_definition_is_struct_field && !*duplicate_is_struct_field {
1585                            first_definition.clone()
1586                        }
1587                        else {
1588                            Span::dummy()
1589                        },
1590                        format!("Struct field \"{0}\" is just a shorthand notation for `{0}: {0}`. It defines a variable \"{0}\".", first_definition.as_str()),
1591                    ),
1592                    Hint::info(
1593                        source_engine,
1594                        match_value.clone(),
1595                        format!("The expression to match on is of type \"{match_type}\".")
1596                    ),
1597                ],
1598                help: vec![
1599                    format!("Variables used in match arm patterns must be unique within a pattern, except in alternatives."),
1600                    match (*first_definition_is_struct_field, *duplicate_is_struct_field) {
1601                        (true, true) => format!("Consider declaring a variable with different name for either of the fields. E.g., `{0}: var_{0}`.", first_definition.as_str()),
1602                        (true, false) | (false, true) => format!("Consider declaring a variable for the field \"{0}\" (e.g., `{0}: var_{0}`), or renaming the variable \"{0}\".", first_definition.as_str()),
1603                        (false, false) => "Consider renaming either of the variables.".to_string(),
1604                    },
1605                ],
1606            },
1607            MatchArmVariableMismatchedType { match_value, match_type, variable, first_definition, expected, received } => Diagnostic {
1608                reason: Some(Reason::new(code(1), "Match pattern variable has mismatched type".to_string())),
1609                issue: Issue::error(
1610                    source_engine,
1611                    variable.span(),
1612                    format!("Variable \"{variable}\" is expected to be of type \"{expected}\", but is \"{received}\".")
1613                ),
1614                hints: vec![
1615                    Hint::info(
1616                        source_engine,
1617                        first_definition.clone(),
1618                        format!("\"{variable}\" is first defined here with type \"{expected}\".")
1619                    ),
1620                    Hint::info(
1621                        source_engine,
1622                        match_value.clone(),
1623                        format!("The expression to match on is of type \"{match_type}\".")
1624                    ),
1625                ],
1626                help: vec![
1627                    format!("In the same match arm, a variable must have the same type in all alternatives."),
1628                ],
1629            },
1630            MatchArmVariableNotDefinedInAllAlternatives { match_value, match_type, variable, missing_in_alternatives} => Diagnostic {
1631                reason: Some(Reason::new(code(1), "Match pattern variable is not defined in all alternatives".to_string())),
1632                issue: Issue::error(
1633                    source_engine,
1634                    variable.span(),
1635                    format!("Variable \"{variable}\" is not defined in all alternatives.")
1636                ),
1637                hints: {
1638                    let mut hints = vec![
1639                        Hint::info(
1640                            source_engine,
1641                            match_value.clone(),
1642                            format!("The expression to match on is of type \"{match_type}\".")
1643                        ),
1644                    ];
1645
1646                    for (i, alternative) in missing_in_alternatives.iter().enumerate() {
1647                        hints.push(
1648                            Hint::info(
1649                                source_engine,
1650                                alternative.clone(),
1651                                format!("\"{variable}\" is {}missing in this alternative.", if i != 0 { "also " } else { "" }),
1652                            )
1653                        )
1654                    }
1655
1656                    hints
1657                },
1658                help: vec![
1659                    format!("Consider removing the variable \"{variable}\" altogether, or adding it to all alternatives."),
1660                ],
1661            },
1662            MatchStructPatternMissingFields { missing_fields, missing_fields_are_public, struct_name, struct_decl_span, total_number_of_fields, span } => Diagnostic {
1663                reason: Some(Reason::new(code(1), "Struct pattern has missing fields".to_string())),
1664                issue: Issue::error(
1665                    source_engine,
1666                    span.clone(),
1667                    format!("Struct pattern is missing the {}field{} {}.",
1668                        if *missing_fields_are_public { "public " } else { "" },
1669                        plural_s(missing_fields.len()),
1670                        sequence_to_str(missing_fields, Enclosing::DoubleQuote, 2)
1671                    )
1672                ),
1673                hints: vec![
1674                    Hint::help(
1675                        source_engine,
1676                        span.clone(),
1677                        "Struct pattern must either contain or ignore each struct field.".to_string()
1678                    ),
1679                    Hint::info(
1680                        source_engine,
1681                        struct_decl_span.clone(),
1682                        format!("Struct \"{struct_name}\" is declared here, and has {} field{}.",
1683                            num_to_str(*total_number_of_fields),
1684                            plural_s(*total_number_of_fields),
1685                        )
1686                    ),
1687                ],
1688                help: vec![
1689                    // Consider ignoring the field "x_1" by using the `_` pattern: `x_1: _`.
1690                    //  or
1691                    // Consider ignoring individual fields by using the `_` pattern. E.g, `x_1: _`.
1692                    format!("Consider ignoring {} field{} {}by using the `_` pattern{} `{}: _`.",
1693                        singular_plural(missing_fields.len(), "the", "individual"),
1694                        plural_s(missing_fields.len()),
1695                        singular_plural(missing_fields.len(), &format!("\"{}\" ", missing_fields[0]), ""),
1696                        singular_plural(missing_fields.len(), ":", ". E.g.,"),
1697                        missing_fields[0]
1698                    ),
1699                    "Alternatively, consider ignoring all the missing fields by ending the struct pattern with `..`.".to_string(),
1700                ],
1701            },
1702            MatchStructPatternMustIgnorePrivateFields { private_fields, struct_name, struct_decl_span, all_fields_are_private, span } => Diagnostic {
1703                reason: Some(Reason::new(code(1), "Struct pattern must ignore inaccessible private fields".to_string())),
1704                issue: Issue::error(
1705                    source_engine,
1706                    span.clone(),
1707                    format!("Struct pattern must ignore inaccessible private field{} {}.",
1708                        plural_s(private_fields.len()),
1709                        sequence_to_str(private_fields, Enclosing::DoubleQuote, 2)
1710                    )
1711                ),
1712                hints: vec![
1713                    Hint::help(
1714                        source_engine,
1715                        span.clone(),
1716                        format!("To ignore the private field{}, end the struct pattern with `..`.",
1717                            plural_s(private_fields.len()),
1718                        )
1719                    ),
1720                    Hint::info(
1721                        source_engine,
1722                        struct_decl_span.clone(),
1723                        format!("Struct \"{struct_name}\" is declared here, and has {}.",
1724                            if *all_fields_are_private {
1725                                "all private fields".to_string()
1726                            } else {
1727                                format!("private field{} {}",
1728                                    plural_s(private_fields.len()),
1729                                    sequence_to_str(private_fields, Enclosing::DoubleQuote, 2)
1730                                )
1731                            }
1732                        )
1733                    ),
1734                ],
1735                help: vec![],
1736            },
1737            TraitNotImportedAtFunctionApplication { trait_name, function_name, function_call_site_span, trait_constraint_span, trait_candidates } => {
1738                // Make candidates order deterministic.
1739                let mut trait_candidates = trait_candidates.clone();
1740                trait_candidates.sort();
1741                let trait_candidates = &trait_candidates; // Remove mutability.
1742
1743                Diagnostic {
1744                    reason: Some(Reason::new(code(1), "Trait is not imported".to_string())),
1745                    issue: Issue::error(
1746                        source_engine,
1747                        function_call_site_span.clone(),
1748                        format!(
1749                            "Trait \"{trait_name}\" is not imported {}when calling \"{function_name}\".",
1750                            get_file_name(source_engine, function_call_site_span.source_id())
1751                                .map_or("".to_string(), |file_name| format!("into \"{file_name}\" "))
1752                        )
1753                    ),
1754                    hints: {
1755                        let mut hints = vec![
1756                            Hint::help(
1757                                source_engine,
1758                                function_call_site_span.clone(),
1759                                format!("This import is needed because \"{function_name}\" requires \"{trait_name}\" in one of its trait constraints.")
1760                            ),
1761                            Hint::info(
1762                                source_engine,
1763                                trait_constraint_span.clone(),
1764                                format!("In the definition of \"{function_name}\", \"{trait_name}\" is used in this trait constraint.")
1765                            ),
1766                        ];
1767
1768                        match trait_candidates.len() {
1769                            // If no candidates are found, that means that an alias was used in the trait constraint definition.
1770                            // The way how constraint checking works now, the trait will not be found when we try to check if
1771                            // the trait constraints are satisfied for type, and we will never end up in this case here.
1772                            // So we will simply ignore it.
1773                            0 => (),
1774                            // The most common case. Exactly one known trait with the given name.
1775                            1 => hints.push(Hint::help(
1776                                    source_engine,
1777                                    function_call_site_span.clone(),
1778                                    format!(
1779                                        "Import the \"{trait_name}\" trait {}by using: `use {};`.",
1780                                        get_file_name(source_engine, function_call_site_span.source_id())
1781                                            .map_or("".to_string(), |file_name| format!("into \"{file_name}\" ")),
1782                                        trait_candidates[0]
1783                                    )
1784                                )),
1785                            // Unlikely (for now) case of having several traits with the same name.
1786                            _ => hints.push(Hint::help(
1787                                    source_engine,
1788                                    function_call_site_span.clone(),
1789                                    format!(
1790                                        "To import the proper \"{trait_name}\" {}follow the detailed instructions given below.",
1791                                        get_file_name(source_engine, function_call_site_span.source_id())
1792                                            .map_or("".to_string(), |file_name| format!("into \"{file_name}\" "))
1793                                    )
1794                                )),
1795                        }
1796
1797                        hints
1798                    },
1799                    help: {
1800                        let mut help = vec![];
1801
1802                        if trait_candidates.len() > 1 {
1803                            help.push(format!("There are these {} traits with the name \"{trait_name}\" available in the modules:", num_to_str(trait_candidates.len())));
1804                            for trait_candidate in trait_candidates.iter() {
1805                                help.push(format!("{}- {trait_candidate}", Indent::Single));
1806                            }
1807                            help.push("To import the proper one follow these steps:".to_string());
1808                            help.push(format!(
1809                                "{}1. Look at the definition of the \"{function_name}\"{}.",
1810                                    Indent::Single,
1811                                    get_file_name(source_engine, trait_constraint_span.source_id())
1812                                        .map_or("".to_string(), |file_name| format!(" in the \"{file_name}\""))
1813                            ));
1814                            help.push(format!(
1815                                "{}2. Detect which exact \"{trait_name}\" is used in the trait constraint in the \"{function_name}\".",
1816                                Indent::Single
1817                            ));
1818                            help.push(format!(
1819                                "{}3. Import that \"{trait_name}\"{}.",
1820                                Indent::Single,
1821                                get_file_name(source_engine, function_call_site_span.source_id())
1822                                    .map_or("".to_string(), |file_name| format!(" into \"{file_name}\""))
1823                            ));
1824                            help.push(format!("{} E.g., assuming it is the first one on the list, use: `use {};`", Indent::Double, trait_candidates[0]));
1825                        }
1826
1827                        help
1828                    },
1829                }
1830            },
1831            // TODO: (REFERENCES) Extend error messages to pointers, once typed pointers are defined and can be dereferenced.
1832            ExpressionCannotBeDereferenced { expression_type, span } => Diagnostic {
1833                reason: Some(Reason::new(code(1), "Expression cannot be dereferenced".to_string())),
1834                issue: Issue::error(
1835                    source_engine,
1836                    span.clone(),
1837                    format!("This expression cannot be dereferenced, because it is of type \"{expression_type}\", which is not a reference type.")
1838                ),
1839                hints: vec![
1840                    Hint::help(
1841                        source_engine,
1842                        span.clone(),
1843                        "In Sway, only references can be dereferenced.".to_string()
1844                    ),
1845                    Hint::help(
1846                        source_engine,
1847                        span.clone(),
1848                        "Are you missing the reference operator `&` somewhere in the code?".to_string()
1849                    ),
1850                ],
1851                help: vec![],
1852            },
1853            StructInstantiationMissingFields { field_names, struct_name, span, struct_decl_span, total_number_of_fields } => Diagnostic {
1854                reason: Some(Reason::new(code(1), "Struct instantiation has missing fields".to_string())),
1855                issue: Issue::error(
1856                    source_engine,
1857                    span.clone(),
1858                    format!("Instantiation of the struct \"{struct_name}\" is missing the field{} {}.",
1859                            plural_s(field_names.len()),
1860                            sequence_to_str(field_names, Enclosing::DoubleQuote, 2)
1861                        )
1862                ),
1863                hints: vec![
1864                    Hint::help(
1865                        source_engine,
1866                        span.clone(),
1867                        "Struct instantiation must initialize all the fields of the struct.".to_string()
1868                    ),
1869                    Hint::info(
1870                        source_engine,
1871                        struct_decl_span.clone(),
1872                        format!("Struct \"{struct_name}\" is declared here, and has {} field{}.",
1873                            num_to_str(*total_number_of_fields),
1874                            plural_s(*total_number_of_fields),
1875                        )
1876                    ),
1877                ],
1878                help: vec![],
1879            },
1880            StructCannotBeInstantiated { struct_name, span, struct_decl_span, private_fields, constructors, all_fields_are_private, is_in_storage_declaration, struct_can_be_changed } => Diagnostic {
1881                reason: Some(Reason::new(code(1), "Struct cannot be instantiated due to inaccessible private fields".to_string())),
1882                issue: Issue::error(
1883                    source_engine,
1884                    span.clone(),
1885                    format!("\"{struct_name}\" cannot be {}instantiated in this {}, due to {}inaccessible private field{}.",
1886                        if *is_in_storage_declaration { "" } else { "directly " },
1887                        if *is_in_storage_declaration { "storage declaration" } else { "module" },
1888                        singular_plural(private_fields.len(), "an ", ""),
1889                        plural_s(private_fields.len())
1890                    )
1891                ),
1892                hints: vec![
1893                    Hint::help(
1894                        source_engine,
1895                        span.clone(),
1896                        format!("Inaccessible field{} {} {}.",
1897                            plural_s(private_fields.len()),
1898                            is_are(private_fields.len()),
1899                            sequence_to_str(private_fields, Enclosing::DoubleQuote, 5)
1900                        )
1901                    ),
1902                    Hint::help(
1903                        source_engine,
1904                        span.clone(),
1905                        if *is_in_storage_declaration {
1906                            "Structs with private fields can be instantiated in storage declarations only if they are declared in the same module as the storage.".to_string()
1907                        } else {
1908                            "Structs with private fields can be instantiated only within the module in which they are declared.".to_string()
1909                        }
1910                    ),
1911                    if *is_in_storage_declaration {
1912                        Hint::help(
1913                            source_engine,
1914                            span.clone(),
1915                            "They can still be initialized in storage declarations if they have public constructors that evaluate to a constant.".to_string()
1916                        )
1917                    } else {
1918                        Hint::none()
1919                    },
1920                    if *is_in_storage_declaration {
1921                        Hint::help(
1922                            source_engine,
1923                            span.clone(),
1924                            "They can always be stored in storage by using the `read` and `write` functions provided in the `std::storage::storage_api`.".to_string()
1925                        )
1926                    } else {
1927                        Hint::none()
1928                    },
1929                    if !*is_in_storage_declaration && !constructors.is_empty() {
1930                        Hint::help(
1931                            source_engine,
1932                            span.clone(),
1933                            format!("\"{struct_name}\" can be instantiated via public constructors suggested below.")
1934                        )
1935                    } else {
1936                        Hint::none()
1937                    },
1938                    Hint::info(
1939                        source_engine,
1940                        struct_decl_span.clone(),
1941                        format!("Struct \"{struct_name}\" is declared here, and has {}.",
1942                            if *all_fields_are_private {
1943                                "all private fields".to_string()
1944                            } else {
1945                                format!("private field{} {}",
1946                                    plural_s(private_fields.len()),
1947                                    sequence_to_str(private_fields, Enclosing::DoubleQuote, 2)
1948                                )
1949                            }
1950                        )
1951                    ),
1952                ],
1953                help: {
1954                    let mut help = vec![];
1955
1956                    if *is_in_storage_declaration {
1957                        help.push(format!("Consider initializing \"{struct_name}\" by finding an available constructor that evaluates to a constant{}.",
1958                            if *struct_can_be_changed {
1959                                ", or implement a new one"
1960                            } else {
1961                                ""
1962                            }
1963                        ));
1964
1965                        if !constructors.is_empty() {
1966                            help.push("Check these already available constructors. They might evaluate to a constant:".to_string());
1967                            // We always expect a very few candidates here. So let's list all of them by using `usize::MAX`.
1968                            for constructor in sequence_to_list(constructors, Indent::Single, usize::MAX) {
1969                                help.push(constructor);
1970                            }
1971                        };
1972
1973                        help.push(Diagnostic::help_empty_line());
1974
1975                        help.push(format!("Or you can always store instances of \"{struct_name}\" in the contract storage, by using the `std::storage::storage_api`:"));
1976                        help.push(format!("{}use std::storage::storage_api::{{read, write}};", Indent::Single));
1977                        help.push(format!("{}write(STORAGE_KEY, 0, my_{});", Indent::Single, to_snake_case(struct_name.as_str())));
1978                        help.push(format!("{}let my_{}_option = read::<{struct_name}>(STORAGE_KEY, 0);", Indent::Single, to_snake_case(struct_name.as_str())));
1979                    }
1980                    else if !constructors.is_empty() {
1981                        help.push(format!("Consider instantiating \"{struct_name}\" by using one of the available constructors{}:",
1982                            if *struct_can_be_changed {
1983                                ", or implement a new one"
1984                            } else {
1985                                ""
1986                            }
1987                        ));
1988                        for constructor in sequence_to_list(constructors, Indent::Single, 5) {
1989                            help.push(constructor);
1990                        }
1991                    }
1992
1993                    if *struct_can_be_changed {
1994                        if *is_in_storage_declaration || !constructors.is_empty() {
1995                            help.push(Diagnostic::help_empty_line());
1996                        }
1997
1998                        if !*is_in_storage_declaration && constructors.is_empty() {
1999                            help.push(format!("Consider implementing a public constructor for \"{struct_name}\"."));
2000                        };
2001
2002                        help.push(
2003                            // Alternatively, consider declaring the field "f" as public in "Struct": `pub f: ...,`.
2004                            //  or
2005                            // Alternatively, consider declaring the fields "f" and "g" as public in "Struct": `pub <field>: ...,`.
2006                            //  or
2007                            // Alternatively, consider declaring all fields as public in "Struct": `pub <field>: ...,`.
2008                            format!("Alternatively, consider declaring {} as public in \"{struct_name}\": `pub {}: ...,`.",
2009                                if *all_fields_are_private {
2010                                    "all fields".to_string()
2011                                } else {
2012                                    format!("{} {}",
2013                                        singular_plural(private_fields.len(), "the field", "the fields"),
2014                                        sequence_to_str(private_fields, Enclosing::DoubleQuote, 2)
2015                                    )
2016                                },
2017                                if *all_fields_are_private {
2018                                    "<field>".to_string()
2019                                } else {
2020                                    match &private_fields[..] {
2021                                        [field] => format!("{field}"),
2022                                        _ => "<field>".to_string(),
2023                                    }
2024                                },
2025                            )
2026                        )
2027                    };
2028
2029                    help
2030                }
2031            },
2032            StructFieldIsPrivate { field_name, struct_name, field_decl_span, struct_can_be_changed, usage_context } => Diagnostic {
2033                reason: Some(Reason::new(code(1), "Private struct field is inaccessible".to_string())),
2034                issue: Issue::error(
2035                    source_engine,
2036                    field_name.span(),
2037                    format!("Private field \"{field_name}\" {}is inaccessible in this module.",
2038                        match usage_context {
2039                            StructInstantiation { .. } | StorageDeclaration { .. } | PatternMatching { .. } => "".to_string(),
2040                            StorageAccess | StructFieldAccess => format!("of the struct \"{struct_name}\" "),
2041                        }
2042                    )
2043                ),
2044                hints: vec![
2045                    Hint::help(
2046                        source_engine,
2047                        field_name.span(),
2048                        format!("Private fields can only be {} within the module in which their struct is declared.",
2049                            match usage_context {
2050                                StructInstantiation { .. } | StorageDeclaration { .. } => "initialized",
2051                                StorageAccess | StructFieldAccess => "accessed",
2052                                PatternMatching { .. } => "matched",
2053                            }
2054                        )
2055                    ),
2056                    if matches!(usage_context, PatternMatching { has_rest_pattern } if !has_rest_pattern) {
2057                        Hint::help(
2058                            source_engine,
2059                            field_name.span(),
2060                            "Otherwise, they must be ignored by ending the struct pattern with `..`.".to_string()
2061                        )
2062                    } else {
2063                        Hint::none()
2064                    },
2065                    Hint::info(
2066                        source_engine,
2067                        field_decl_span.clone(),
2068                        format!("Field \"{field_name}\" {}is declared here as private.",
2069                            match usage_context {
2070                                StructInstantiation { .. } | StorageDeclaration { .. } | PatternMatching { .. } => format!("of the struct \"{struct_name}\" "),
2071                                StorageAccess | StructFieldAccess => "".to_string(),
2072                            }
2073                        )
2074                    ),
2075                ],
2076                help: vec![
2077                    if matches!(usage_context, PatternMatching { has_rest_pattern } if !has_rest_pattern) {
2078                        format!("Consider removing the field \"{field_name}\" from the struct pattern, and ending the pattern with `..`.")
2079                    } else {
2080                        Diagnostic::help_none()
2081                    },
2082                    if *struct_can_be_changed {
2083                        match usage_context {
2084                            StorageAccess | StructFieldAccess | PatternMatching { .. } => {
2085                                format!("{} declaring the field \"{field_name}\" as public in \"{struct_name}\": `pub {field_name}: ...,`.",
2086                                    if matches!(usage_context, PatternMatching { has_rest_pattern } if !has_rest_pattern) {
2087                                        "Alternatively, consider"
2088                                    } else {
2089                                        "Consider"
2090                                    }
2091                                )
2092                            },
2093                            // For all other usages, detailed instructions are already given in specific messages.
2094                            _ => Diagnostic::help_none(),
2095                        }
2096                    } else {
2097                        Diagnostic::help_none()
2098                    },
2099                ],
2100            },
2101            StructFieldDoesNotExist { field_name, available_fields, is_public_struct_access, struct_name, struct_decl_span, struct_is_empty, usage_context } => Diagnostic {
2102                reason: Some(Reason::new(code(1), "Struct field does not exist".to_string())),
2103                issue: Issue::error(
2104                    source_engine,
2105                    field_name.span(),
2106                    format!("Field \"{field_name}\" does not exist in the struct \"{struct_name}\".")
2107                ),
2108                hints: {
2109                    let public = if *is_public_struct_access { "public " } else { "" };
2110
2111                    let (hint, show_struct_decl) = if *struct_is_empty {
2112                        (Some(format!("\"{struct_name}\" is an empty struct. It doesn't have any fields.")), false)
2113                    }
2114                    // If the struct anyhow cannot be instantiated (in the struct instantiation or storage declaration),
2115                    // we don't show any additional hints.
2116                    // Showing any available fields would be inconsistent and misleading, because they anyhow cannot be used.
2117                    // Besides, "Struct cannot be instantiated" error will provide all the explanations and suggestions.
2118                    else if (matches!(usage_context, StorageAccess) && *is_public_struct_access && available_fields.is_empty())
2119                            ||
2120                            (matches!(usage_context, StructInstantiation { struct_can_be_instantiated: false } | StorageDeclaration { struct_can_be_instantiated: false })) {
2121                        // If the struct anyhow cannot be instantiated in the storage, don't show any additional hint
2122                        // if there is an attempt to access a non existing field of such non-instantiable struct.
2123                        //   or
2124                        // Likewise, if we are in the struct instantiation or storage declaration and the struct
2125                        // cannot be instantiated.
2126                        (None, false)
2127                    } else if !available_fields.is_empty() {
2128                        // In all other cases, show the available fields.
2129                        const NUM_OF_FIELDS_TO_DISPLAY: usize = 4;
2130                        match &available_fields[..] {
2131                            [field] => (Some(format!("Only available {public}field is \"{field}\".")), false),
2132                            _ => (Some(format!("Available {public}fields are {}.", sequence_to_str(available_fields, Enclosing::DoubleQuote, NUM_OF_FIELDS_TO_DISPLAY))),
2133                                    available_fields.len() > NUM_OF_FIELDS_TO_DISPLAY
2134                                ),
2135                        }
2136                    }
2137                    else {
2138                        (None, false)
2139                    };
2140
2141                    let mut hints = vec![];
2142
2143                    if let Some(hint) = hint {
2144                        hints.push(Hint::help(source_engine, field_name.span(), hint));
2145                    };
2146
2147                    if show_struct_decl {
2148                        hints.push(Hint::info(
2149                            source_engine,
2150                            struct_decl_span.clone(),
2151                            format!("Struct \"{struct_name}\" is declared here, and has {} {public}fields.",
2152                                num_to_str(available_fields.len())
2153                            )
2154                        ));
2155                    }
2156
2157                    hints
2158                },
2159                help: vec![],
2160            },
2161            StructFieldDuplicated { field_name, duplicate } => Diagnostic {
2162                reason: Some(Reason::new(code(1), "Struct field has multiple definitions".to_string())),
2163                issue: Issue::error(
2164                    source_engine,
2165                    field_name.span(),
2166                    format!("Field \"{field_name}\" has multiple definitions.")
2167                ),
2168                hints: {
2169                    vec![
2170                        Hint::info(
2171                            source_engine,
2172                            duplicate.span(),
2173                            "Field definition duplicated here.".into(),
2174                        )
2175                   ]
2176                },
2177                help: vec![],
2178            },
2179            NotIndexable { actually, span } => Diagnostic {
2180                reason: Some(Reason::new(code(1), "Type is not indexable".to_string())),
2181                issue: Issue::error(
2182                    source_engine,
2183                    span.clone(),
2184                    format!("This expression has type \"{actually}\", which is not an indexable type.")
2185                ),
2186                hints: vec![],
2187                help: vec![
2188                    "Index operator `[]` can be used only on indexable types.".to_string(),
2189                    "In Sway, indexable types are:".to_string(),
2190                    format!("{}- arrays. E.g., `[u64;3]`.", Indent::Single),
2191                    format!("{}- references, direct or indirect, to arrays. E.g., `&[u64;3]` or `&&&[u64;3]`.", Indent::Single),
2192                ],
2193            },
2194            FieldAccessOnNonStruct { actually, storage_variable, field_name, span } => Diagnostic {
2195                reason: Some(Reason::new(code(1), "Field access requires a struct".to_string())),
2196                issue: Issue::error(
2197                    source_engine,
2198                    span.clone(),
2199                    format!("{} has type \"{actually}\", which is not a struct{}.",
2200                        if let Some(storage_variable) = storage_variable {
2201                            format!("Storage variable \"{storage_variable}\"")
2202                        } else {
2203                            "This expression".to_string()
2204                        },
2205                        if storage_variable.is_some() {
2206                            ""
2207                        } else {
2208                            " or a reference to a struct"
2209                        }
2210                    )
2211                ),
2212                hints: vec![
2213                    Hint::info(
2214                        source_engine,
2215                        field_name.span(),
2216                        format!("Field access happens here, on \"{field_name}\".")
2217                    )
2218                ],
2219                help: if storage_variable.is_some() {
2220                    vec![
2221                        "Fields can only be accessed on storage variables that are structs.".to_string(),
2222                    ]
2223                } else {
2224                    vec![
2225                        "In Sway, fields can be accessed on:".to_string(),
2226                        format!("{}- structs. E.g., `my_struct.field`.", Indent::Single),
2227                        format!("{}- references, direct or indirect, to structs. E.g., `(&my_struct).field` or `(&&&my_struct).field`.", Indent::Single),
2228                    ]
2229                }
2230            },
2231            SymbolWithMultipleBindings { name, paths, span } => Diagnostic {
2232                reason: Some(Reason::new(code(1), "Multiple bindings exist for symbol in the scope".to_string())),
2233                issue: Issue::error(
2234                    source_engine,
2235                    span.clone(),
2236                    format!("The following paths are all valid bindings for symbol \"{}\": {}.", name, sequence_to_str(&paths.iter().map(|path| format!("{path}::{name}")).collect::<Vec<_>>(), Enclosing::DoubleQuote, 2)),
2237                ),
2238                hints: vec![],
2239                help: vec![format!("Consider using a fully qualified name, e.g., `{}::{}`.", paths[0], name)],
2240            },
2241            StorageFieldDoesNotExist { field_name, available_fields, storage_decl_span } => Diagnostic {
2242                reason: Some(Reason::new(code(1), "Storage field does not exist".to_string())),
2243                issue: Issue::error(
2244                    source_engine,
2245                    field_name.span(),
2246                    format!("Storage field \"{field_name}\" does not exist in the storage.")
2247                ),
2248                hints: {
2249                    let (hint, show_storage_decl) = if available_fields.is_empty() {
2250                        ("The storage is empty. It doesn't have any fields.".to_string(), false)
2251                    } else {
2252                        const NUM_OF_FIELDS_TO_DISPLAY: usize = 4;
2253                        let display_fields = available_fields.iter().map(|(path, field_name)| {
2254                            let path = path.iter().map(ToString::to_string).collect::<Vec<_>>().join("::");
2255                            if path.is_empty() {
2256                                format!("storage.{field_name}")
2257                            } else {
2258                                format!("storage::{path}.{field_name}")
2259                            }
2260                        }).collect::<Vec<_>>();
2261                        match &display_fields[..] {
2262                            [field] => (format!("Only available storage field is \"{field}\"."), false),
2263                            _ => (format!("Available storage fields are {}.", sequence_to_str(&display_fields, Enclosing::DoubleQuote, NUM_OF_FIELDS_TO_DISPLAY)),
2264                                    available_fields.len() > NUM_OF_FIELDS_TO_DISPLAY
2265                                ),
2266                        }
2267                    };
2268
2269                    let mut hints = vec![];
2270
2271                    hints.push(Hint::help(source_engine, field_name.span(), hint));
2272
2273                    if show_storage_decl {
2274                        hints.push(Hint::info(
2275                            source_engine,
2276                            storage_decl_span.clone(),
2277                            format!("Storage is declared here, and has {} fields.",
2278                                num_to_str(available_fields.len())
2279                            )
2280                        ));
2281                    }
2282
2283                    hints
2284                },
2285                help: vec![],
2286            },
2287            TupleIndexOutOfBounds { index, count, tuple_type, span, prefix_span } => Diagnostic {
2288                reason: Some(Reason::new(code(1), "Tuple index is out of bounds".to_string())),
2289                issue: Issue::error(
2290                    source_engine,
2291                    span.clone(),
2292                    format!("Tuple index {index} is out of bounds. The tuple has only {count} element{}.", plural_s(*count))
2293                ),
2294                hints: vec![
2295                    Hint::info(
2296                        source_engine,
2297                        prefix_span.clone(),
2298                        format!("This expression has type \"{tuple_type}\".")
2299                    ),
2300                ],
2301                help: vec![],
2302            },
2303            TupleElementAccessOnNonTuple { actually, span, index, index_span } => Diagnostic {
2304                reason: Some(Reason::new(code(1), "Tuple element access requires a tuple".to_string())),
2305                issue: Issue::error(
2306                    source_engine,
2307                    span.clone(),
2308                    format!("This expression has type \"{actually}\", which is not a tuple or a reference to a tuple.")
2309                ),
2310                hints: vec![
2311                    Hint::info(
2312                        source_engine,
2313                        index_span.clone(),
2314                        format!("Tuple element access happens here, on the index {index}.")
2315                    )
2316                ],
2317                help: vec![
2318                    "In Sway, tuple elements can be accessed on:".to_string(),
2319                    format!("{}- tuples. E.g., `my_tuple.1`.", Indent::Single),
2320                    format!("{}- references, direct or indirect, to tuples. E.g., `(&my_tuple).1` or `(&&&my_tuple).1`.", Indent::Single),
2321                ],
2322            },
2323            RefMutCannotReferenceConstant { constant, span } => Diagnostic {
2324                reason: Some(Reason::new(code(1), "References to mutable values cannot reference constants".to_string())),
2325                issue: Issue::error(
2326                    source_engine,
2327                    span.clone(),
2328                    format!("\"{constant}\" is a constant. `&mut` cannot reference constants.")
2329                ),
2330                hints: vec![],
2331                help: vec![
2332                    "Consider:".to_string(),
2333                    format!("{}- taking a reference without `mut`: `&{constant}`.", Indent::Single),
2334                    format!("{}- referencing a mutable copy of the constant, by returning it from a block: `&mut {{ {constant} }}`.", Indent::Single)
2335                ],
2336            },
2337            RefMutCannotReferenceImmutableVariable { decl_name, span } => Diagnostic {
2338                reason: Some(Reason::new(code(1), "References to mutable values cannot reference immutable variables".to_string())),
2339                issue: Issue::error(
2340                    source_engine,
2341                    span.clone(),
2342                    format!("\"{decl_name}\" is an immutable variable. `&mut` cannot reference immutable variables.")
2343                ),
2344                hints: vec![
2345                    Hint::info(
2346                        source_engine,
2347                        decl_name.span(),
2348                        format!("Variable \"{decl_name}\" is declared here as immutable.")
2349                    ),
2350                ],
2351                help: vec![
2352                    "Consider:".to_string(),
2353                    // TODO: (REFERENCES) Once desugaring information becomes available, do not show the first suggestion if declaring variable as mutable is not possible.
2354                    format!("{}- declaring \"{decl_name}\" as mutable.", Indent::Single),
2355                    format!("{}- taking a reference without `mut`: `&{decl_name}`.", Indent::Single),
2356                    format!("{}- referencing a mutable copy of \"{decl_name}\", by returning it from a block: `&mut {{ {decl_name} }}`.", Indent::Single)
2357                ],
2358            },
2359            ConflictingImplsForTraitAndType { trait_name, type_implementing_for, type_implementing_for_unaliased, existing_impl_span, second_impl_span } => Diagnostic {
2360                reason: Some(Reason::new(code(1), "Trait is already implemented for type".to_string())),
2361                issue: Issue::error(
2362                    source_engine,
2363                    second_impl_span.clone(),
2364                    if type_implementing_for == type_implementing_for_unaliased {
2365                        format!("Trait \"{trait_name}\" is already implemented for type \"{type_implementing_for}\".")
2366                    } else {
2367                        format!("Trait \"{trait_name}\" is already implemented for type \"{type_implementing_for}\" (which is an alias for \"{type_implementing_for_unaliased}\").")
2368                    }
2369                ),
2370                hints: vec![
2371                    Hint::info(
2372                        source_engine,
2373                        existing_impl_span.clone(),
2374                        if type_implementing_for == type_implementing_for_unaliased {
2375                            format!("This is the already existing implementation of \"{}\" for \"{type_implementing_for}\".",
2376                                    call_path_suffix_with_args(trait_name)
2377                            )
2378                        } else {
2379                            format!("This is the already existing implementation of \"{}\" for \"{type_implementing_for}\" (which is an alias for \"{type_implementing_for_unaliased}\").",
2380                                    call_path_suffix_with_args(trait_name)
2381                            )
2382                        }
2383                    ),
2384                ],
2385                help: vec![
2386                    "In Sway, there can be at most one implementation of a trait for any given type.".to_string(),
2387                    "This property is called \"trait coherence\".".to_string(),
2388                ],
2389            },
2390            DuplicateDeclDefinedForType { decl_kind, decl_name, type_implementing_for, type_implementing_for_unaliased, existing_impl_span, second_impl_span } => {
2391                let decl_kind_snake_case = sway_types::style::to_upper_camel_case(decl_kind);
2392                Diagnostic {
2393                    reason: Some(Reason::new(code(1), "Type contains duplicate declarations".to_string())),
2394                    issue: Issue::error(
2395                        source_engine,
2396                        second_impl_span.clone(),
2397                        if type_implementing_for == type_implementing_for_unaliased {
2398                            format!("{decl_kind_snake_case} \"{decl_name}\" already declared in type \"{type_implementing_for}\".")
2399                        } else {
2400                            format!("{decl_kind_snake_case} \"{decl_name}\" already declared in type \"{type_implementing_for}\" (which is an alias for \"{type_implementing_for_unaliased}\").")
2401                        }
2402                    ),
2403                    hints: vec![
2404                        Hint::info(
2405                            source_engine,
2406                            existing_impl_span.clone(),
2407                            format!("\"{decl_name}\" previously defined here.")
2408                        )
2409                    ],
2410                    help: vec![
2411                        "A type may not contain two or more declarations of the same name".to_string(),
2412                    ],
2413                }
2414            },
2415            MarkerTraitExplicitlyImplemented { marker_trait_full_name, span} => Diagnostic {
2416                reason: Some(Reason::new(code(1), "Marker traits cannot be explicitly implemented".to_string())),
2417                issue: Issue::error(
2418                    source_engine,
2419                    span.clone(),
2420                    format!("Trait \"{marker_trait_full_name}\" is a marker trait and cannot be explicitly implemented.")
2421                ),
2422                hints: vec![],
2423                help: match marker_trait_name(marker_trait_full_name) {
2424                    "Error" => error_marker_trait_help_msg(),
2425                    "Enum" => vec![
2426                        "\"Enum\" marker trait is automatically implemented by the compiler for all enum types.".to_string(),
2427                    ],
2428                    _ => vec![],
2429                }
2430            },
2431            AssignmentToNonMutableVariable { lhs_span, decl_name } => Diagnostic {
2432                reason: Some(Reason::new(code(1), "Immutable variables cannot be assigned to".to_string())),
2433                issue: Issue::error(
2434                    source_engine,
2435                    lhs_span.clone(),
2436                    // "x" cannot be assigned to, because it is an immutable variable.
2437                    //  or
2438                    // This expression cannot be assigned to, because "x" is an immutable variable.
2439                    format!("{} cannot be assigned to, because {} is an immutable variable.",
2440                        if decl_name.as_str() == lhs_span.as_str() { // We have just a single variable in the expression.
2441                            format!("\"{decl_name}\"")
2442                        } else {
2443                            "This expression".to_string()
2444                        },
2445                        if decl_name.as_str() == lhs_span.as_str() {
2446                            "it".to_string()
2447                        } else {
2448                            format!("\"{decl_name}\"")
2449                        }
2450                    )
2451                ),
2452                hints: vec![
2453                    Hint::info(
2454                        source_engine,
2455                        decl_name.span(),
2456                        format!("Variable \"{decl_name}\" is declared here as immutable.")
2457                    ),
2458                ],
2459                help: vec![
2460                    // TODO: (DESUGARING) Once desugaring information becomes available, do not show this suggestion if declaring variable as mutable is not possible.
2461                    format!("Consider declaring \"{decl_name}\" as mutable."),
2462                ],
2463            },
2464            AssignmentToConstantOrConfigurable { lhs_span, is_configurable, decl_name } => Diagnostic {
2465                reason: Some(Reason::new(code(1), format!("{} cannot be assigned to",
2466                    if *is_configurable {
2467                        "Configurables"
2468                    } else {
2469                        "Constants"
2470                    }
2471                ))),
2472                issue: Issue::error(
2473                    source_engine,
2474                    lhs_span.clone(),
2475                    // "x" cannot be assigned to, because it is a constant/configurable.
2476                    //  or
2477                    // This expression cannot be assigned to, because "x" is a constant/configurable.
2478                    format!("{} cannot be assigned to, because {} is a {}.",
2479                        if decl_name.as_str() == lhs_span.as_str() { // We have just the constant in the expression.
2480                            format!("\"{decl_name}\"")
2481                        } else {
2482                            "This expression".to_string()
2483                        },
2484                        if decl_name.as_str() == lhs_span.as_str() {
2485                            "it".to_string()
2486                        } else {
2487                            format!("\"{decl_name}\"")
2488                        },
2489                        if *is_configurable {
2490                            "configurable"
2491                        } else {
2492                            "constant"
2493                        }
2494                    )
2495                ),
2496                hints: vec![
2497                    Hint::info(
2498                        source_engine,
2499                        decl_name.span(),
2500                        format!("{} \"{decl_name}\" is declared here.",
2501                            if *is_configurable {
2502                                "Configurable"
2503                            } else {
2504                                "Constant"
2505                            }
2506                        )
2507                    ),
2508                ],
2509                help: vec![],
2510            },
2511            DeclAssignmentTargetCannotBeAssignedTo { decl_name, decl_friendly_type_name, lhs_span } => Diagnostic {
2512                reason: Some(Reason::new(code(1), "Assignment target cannot be assigned to".to_string())),
2513                issue: Issue::error(
2514                    source_engine,
2515                    lhs_span.clone(),
2516                    // "x" cannot be assigned to, because it is a trait/function/ etc and not a mutable variable.
2517                    //  or
2518                    // This cannot be assigned to, because "x" is a trait/function/ etc and not a mutable variable.
2519                    format!("{} cannot be assigned to, because {} is {}{decl_friendly_type_name} and not a mutable variable.",
2520                        match decl_name {
2521                            Some(decl_name) if decl_name.as_str() == lhs_span.as_str() => // We have just the decl name in the expression.
2522                                format!("\"{decl_name}\""),
2523                            _ => "This".to_string(),
2524                        },
2525                        match decl_name {
2526                            Some(decl_name) if decl_name.as_str() == lhs_span.as_str() =>
2527                                "it".to_string(),
2528                            Some(decl_name) => format!("\"{}\"", decl_name.as_str()),
2529                            _ => "it".to_string(),
2530                        },
2531                        a_or_an(decl_friendly_type_name)
2532                    )
2533                ),
2534                hints: vec![
2535                    match decl_name {
2536                        Some(decl_name) => Hint::info(
2537                            source_engine,
2538                            decl_name.span(),
2539                            format!("{} \"{decl_name}\" is declared here.", ascii_sentence_case(&decl_friendly_type_name.to_string()))
2540                        ),
2541                        _ => Hint::none(),
2542                    }
2543                ],
2544                help: vec![],
2545            },
2546            AssignmentViaNonMutableReference { decl_reference_name, decl_reference_rhs, decl_reference_type, span } => Diagnostic {
2547                reason: Some(Reason::new(code(1), "Reference is not a reference to a mutable value (`&mut`)".to_string())),
2548                issue: Issue::error(
2549                    source_engine,
2550                    span.clone(),
2551                    // This reference expression is not a reference to a mutable value (`&mut`).
2552                    //  or
2553                    // Reference "ref_xyz" is not a reference to a mutable value (`&mut`).
2554                    format!("{} is not a reference to a mutable value (`&mut`).",
2555                        match decl_reference_name {
2556                            Some(decl_reference_name) => format!("Reference \"{decl_reference_name}\""),
2557                            _ => "This reference expression".to_string(),
2558                        }
2559                    )
2560                ),
2561                hints: vec![
2562                    match decl_reference_name {
2563                        Some(decl_reference_name) => Hint::info(
2564                            source_engine,
2565                            decl_reference_name.span(),
2566                            format!("Reference \"{decl_reference_name}\" is declared here as a reference to immutable value.")
2567                        ),
2568                        _ => Hint::none(),
2569                    },
2570                    match decl_reference_rhs {
2571                        Some(decl_reference_rhs) => Hint::info(
2572                            source_engine,
2573                            decl_reference_rhs.clone(),
2574                            format!("This expression has type \"{decl_reference_type}\" instead of \"&mut {}\".",
2575                                &decl_reference_type[1..]
2576                            )
2577                        ),
2578                        _ => Hint::info(
2579                            source_engine,
2580                            span.clone(),
2581                            format!("It has type \"{decl_reference_type}\" instead of \"&mut {}\".",
2582                                &decl_reference_type[1..]
2583                            )
2584                        ),
2585                    },
2586                    match decl_reference_rhs {
2587                        Some(decl_reference_rhs) if decl_reference_rhs.as_str().starts_with('&') => Hint::help(
2588                            source_engine,
2589                            decl_reference_rhs.clone(),
2590                            format!("Consider taking here a reference to a mutable value: `&mut {}`.",
2591                                first_line(decl_reference_rhs.as_str()[1..].trim(), true)
2592                            )
2593                        ),
2594                        _ => Hint::none(),
2595                    },
2596                ],
2597                help: vec![
2598                    format!("{} dereferenced in assignment targets must {} references to mutable values (`&mut`).",
2599                        if decl_reference_name.is_some() {
2600                            "References"
2601                        } else {
2602                            "Reference expressions"
2603                        },
2604                        if decl_reference_name.is_some() {
2605                            "be"
2606                        } else {
2607                            "result in"
2608                        }
2609                    ),
2610                ],
2611            },
2612            Unimplemented { feature, help, span } => Diagnostic {
2613                reason: Some(Reason::new(code(1), "Used feature is currently not implemented".to_string())),
2614                issue: Issue::error(
2615                    source_engine,
2616                    span.clone(),
2617                    format!("{feature} is currently not implemented.")
2618                ),
2619                hints: vec![],
2620                help: help.clone(),
2621            },
2622            MatchedValueIsNotValid { supported_types_message, span } => Diagnostic {
2623                reason: Some(Reason::new(code(1), "Matched value is not valid".to_string())),
2624                issue: Issue::error(
2625                    source_engine,
2626                    span.clone(),
2627                    "This cannot be matched.".to_string()
2628                ),
2629                hints: vec![],
2630                help: {
2631                    let mut help = vec![];
2632
2633                    help.push("Matched value must be an expression whose result is of one of the types supported in pattern matching.".to_string());
2634                    help.push(Diagnostic::help_empty_line());
2635                    for msg in supported_types_message {
2636                        help.push(msg.to_string());
2637                    }
2638
2639                    help
2640                }
2641            },
2642            TypeIsNotValidAsImplementingFor { invalid_type, trait_name, span } => Diagnostic {
2643                reason: Some(Reason::new(code(1), "Self type of an impl block is not valid".to_string())),
2644                issue: Issue::error(
2645                    source_engine,
2646                    span.clone(),
2647                    format!("{invalid_type} is not a valid type in the self type of {} impl block.",
2648                        match trait_name {
2649                            Some(_) => "a trait",
2650                            None => "an",
2651                        }
2652                    )
2653                ),
2654                hints: vec![
2655                    if matches!(invalid_type, InvalidImplementingForType::SelfType) {
2656                        Hint::help(
2657                            source_engine,
2658                            span.clone(),
2659                            format!("Replace {invalid_type} with the actual type that you want to implement for.")
2660                        )
2661                    } else {
2662                        Hint::none()
2663                    }
2664                ],
2665                help: {
2666                    if matches!(invalid_type, InvalidImplementingForType::Placeholder) {
2667                        vec![
2668                            format!("Are you trying to implement {} for any type?",
2669                                match trait_name {
2670                                    Some(trait_name) => format!("trait \"{trait_name}\""),
2671                                    None => "functionality".to_string(),
2672                                }
2673                            ),
2674                            Diagnostic::help_empty_line(),
2675                            "If so, use generic type parameters instead.".to_string(),
2676                            "E.g., instead of:".to_string(),
2677                            // The trait `trait_name` could represent an arbitrary complex trait.
2678                            // E.g., `with generic arguments, etc. So we don't want to deal
2679                            // with the complexity of representing it properly
2680                            // but rather use a simplified but clearly instructive
2681                            // sample trait name here, `SomeTrait`.
2682                            // impl _
2683                            //   or
2684                            // impl SomeTrait for _
2685                            format!("{}impl {}_",
2686                                Indent::Single,
2687                                match trait_name {
2688                                    Some(_) => "SomeTrait for ",
2689                                    None => "",
2690                                }
2691                            ),
2692                            "use:".to_string(),
2693                            format!("{}impl<T> {}T",
2694                                Indent::Single,
2695                                match trait_name {
2696                                    Some(_) => "SomeTrait for ",
2697                                    None => "",
2698                                }
2699                            ),
2700                        ]
2701                    } else {
2702                        vec![]
2703                    }
2704                }
2705            },
2706            ModulePathIsNotAnExpression { module_path, span } => Diagnostic {
2707                reason: Some(Reason::new(code(1), "Module path is not an expression".to_string())),
2708                issue: Issue::error(
2709                    source_engine,
2710                    span.clone(),
2711                    "This is a module path, and not an expression.".to_string()
2712                ),
2713                hints: vec![
2714                    Hint::help(
2715                        source_engine,
2716                        span.clone(),
2717                        "An expression is expected at this location, but a module path is found.".to_string()
2718                    ),
2719                ],
2720                help: vec![
2721                    "In expressions, module paths can only be used to fully qualify names with a path.".to_string(),
2722                    format!("E.g., `{module_path}::SOME_CONSTANT` or `{module_path}::some_function()`."),
2723                ]
2724            },
2725            Parse { error } => {
2726                match &error.kind {
2727                    ParseErrorKind::MissingColonInEnumTypeField { variant_name, tuple_contents } => Diagnostic {
2728                        reason: Some(Reason::new(code(1), "Enum variant declaration is not valid".to_string())),
2729                        issue: Issue::error(
2730                            source_engine,
2731                            error.span.clone(),
2732                            format!("`{}` is not a valid enum variant declaration.", error.span.as_str()),
2733                        ),
2734                        hints: vec![
2735                            if let Some(tuple_contents) = tuple_contents {
2736                                Hint::help(
2737                                    source_engine,
2738                                    error.span.clone(),
2739                                    format!("Did you mean `{}: ({})`?", variant_name, tuple_contents.as_str())
2740                                )
2741                            } else {
2742                                Hint::none()
2743                            }
2744                        ],
2745                        help: vec![
2746                            "In Sway, enum variants are in the form `Variant: ()`, `Variant: <type>`, or `Variant: (<type1>, ..., <typeN>)`.".to_string(),
2747                            "E.g., `Foo: (), `Bar: u64`, or `Bar: (bool, u32)`.".to_string(),
2748                        ],
2749                    },
2750                    ParseErrorKind::UnassignableExpression { erroneous_expression_kind, erroneous_expression_span } => Diagnostic {
2751                        reason: Some(Reason::new(code(1), "Expression cannot be assigned to".to_string())),
2752                        // A bit of a special handling for parentheses, because they are the only
2753                        // expression kind whose friendly name is in plural. Having it in singular
2754                        // or without this simple special handling gives very odd sounding sentences.
2755                        // Therefore, just a bit of a special handling.
2756                        issue: Issue::error(
2757                            source_engine,
2758                            error.span.clone(),
2759                            format!("This expression cannot be assigned to, because it {} {}{}.",
2760                                if &error.span == erroneous_expression_span { // If the whole expression is erroneous.
2761                                    "is"
2762                                } else {
2763                                    "contains"
2764                                },
2765                                if *erroneous_expression_kind == "parentheses" {
2766                                    ""
2767                                } else {
2768                                    a_or_an(erroneous_expression_kind)
2769                                },
2770                                erroneous_expression_kind
2771                            )
2772                        ),
2773                        hints: vec![
2774                            if &error.span != erroneous_expression_span {
2775                                Hint::info(
2776                                    source_engine,
2777                                    erroneous_expression_span.clone(),
2778                                    format!("{} the contained {erroneous_expression_kind}.",
2779                                        if *erroneous_expression_kind == "parentheses" {
2780                                            "These are"
2781                                        } else {
2782                                            "This is"
2783                                        }
2784                                    )
2785                                )
2786                            } else {
2787                                Hint::none()
2788                            },
2789                        ],
2790                        help: vec![
2791                            format!("{} cannot be {}an assignment target.",
2792                                ascii_sentence_case(&erroneous_expression_kind.to_string()),
2793                                if &error.span == erroneous_expression_span {
2794                                    ""
2795                                } else {
2796                                    "a part of "
2797                                }
2798                            ),
2799                            Diagnostic::help_empty_line(),
2800                            "In Sway, assignment targets must be one of the following:".to_string(),
2801                            format!("{}- Expressions starting with a mutable variable, optionally having", Indent::Single),
2802                            format!("{}  array or tuple element accesses, struct field accesses,", Indent::Single),
2803                            format!("{}  or arbitrary combinations of those.", Indent::Single),
2804                            format!("{}  E.g., `mut_var` or `mut_struct.field` or `mut_array[x + y].field.1`.", Indent::Single),
2805                            Diagnostic::help_empty_line(),
2806                            format!("{}- Dereferencing of an arbitrary expression that results", Indent::Single),
2807                            format!("{}  in a reference to a mutable value.", Indent::Single),
2808                            format!("{}  E.g., `*ref_to_mutable_value` or `*max_mut(&mut x, &mut y)`.", Indent::Single),
2809                        ]
2810                    },
2811                    ParseErrorKind::UnrecognizedOpCode { known_op_codes } => Diagnostic {
2812                        reason: Some(Reason::new(code(1), "Assembly instruction is unknown".to_string())),
2813                        issue: Issue::error(
2814                            source_engine,
2815                            error.span.clone(),
2816                            format!("\"{}\" is not a known assembly instruction.",
2817                                error.span.as_str()
2818                            )
2819                        ),
2820                        hints: vec![did_you_mean_help(source_engine, error.span.clone(), known_op_codes.iter(), 2, Enclosing::DoubleQuote)],
2821                        help: vec![]
2822                    },
2823                    _ => Diagnostic {
2824                                // TODO: Temporary we use `self` here to achieve backward compatibility.
2825                                //       In general, `self` must not be used. All the values for the formatting
2826                                //       of a diagnostic must come from its enum variant parameters.
2827                                issue: Issue::error(source_engine, self.span(), format!("{self}")),
2828                                ..Default::default()
2829                        },
2830                }
2831            },
2832            ConvertParseTree { error } => {
2833                match error {
2834                    ConvertParseTreeError::InvalidAttributeTarget { span, attribute, target_friendly_name, can_only_annotate_help } => Diagnostic {
2835                        reason: Some(Reason::new(code(1), match get_attribute_type(attribute) {
2836                            AttributeType::InnerDocComment => "Inner doc comment (`//!`) cannot document item",
2837                            AttributeType::OuterDocComment => "Outer doc comment (`///`) cannot document item",
2838                            AttributeType::Attribute => "Attribute cannot annotate item",
2839                        }.to_string())),
2840                        issue: Issue::error(
2841                            source_engine,
2842                            span.clone(),
2843                            match get_attribute_type(attribute) {
2844                                AttributeType::InnerDocComment => format!("Inner doc comment (`//!`) cannot document {}{target_friendly_name}.", a_or_an(&target_friendly_name)),
2845                                AttributeType::OuterDocComment => format!("Outer doc comment (`///`) cannot document {}{target_friendly_name}.", a_or_an(&target_friendly_name)),
2846                                AttributeType::Attribute => format!("\"{attribute}\" attribute cannot annotate {}{target_friendly_name}.", a_or_an(&target_friendly_name)),
2847                            }.to_string()
2848                        ),
2849                        hints: vec![],
2850                        help: can_only_annotate_help.iter().map(|help| help.to_string()).collect(),
2851                    },
2852                    ConvertParseTreeError::InvalidAttributeMultiplicity { last_occurrence, previous_occurrences } => Diagnostic {
2853                        reason: Some(Reason::new(code(1), "Attribute can be applied only once".to_string())),
2854                        issue: Issue::error(
2855                            source_engine,
2856                            last_occurrence.span(),
2857                            format!("\"{last_occurrence}\" attribute can be applied only once, but is applied {} times.", num_to_str(previous_occurrences.len() + 1))
2858                        ),
2859                        hints: {
2860                            let (first_occurrence, other_occurrences) = previous_occurrences.split_first().expect("there is at least one previous occurrence in `previous_occurrences`");
2861                            let mut hints = vec![Hint::info(source_engine, first_occurrence.span(), "It is already applied here.".to_string())];
2862                            other_occurrences.iter().for_each(|occurrence| hints.push(Hint::info(source_engine, occurrence.span(), "And here.".to_string())));
2863                            hints
2864                        },
2865                        help: vec![],
2866                    },
2867                    ConvertParseTreeError::InvalidAttributeArgsMultiplicity { span, attribute, args_multiplicity, num_of_args } => Diagnostic {
2868                        reason: Some(Reason::new(code(1), "Number of attribute arguments is invalid".to_string())),
2869                        issue: Issue::error(
2870                            source_engine,
2871                            span.clone(),
2872                            format!("\"{attribute}\" attribute must {}, but has {}.", get_expected_attributes_args_multiplicity_msg(args_multiplicity), num_to_str_or_none(*num_of_args))
2873                        ),
2874                        hints: vec![],
2875                        help: vec![],
2876                    },
2877                    ConvertParseTreeError::InvalidAttributeArg { attribute, arg, expected_args } => Diagnostic {
2878                        reason: Some(Reason::new(code(1), "Attribute argument is invalid".to_string())),
2879                        issue: Issue::error(
2880                            source_engine,
2881                            arg.span(),
2882                            format!("\"{arg}\" is an invalid argument for attribute \"{attribute}\".")
2883                        ),
2884                        hints: {
2885                            let mut hints = vec![did_you_mean_help(source_engine, arg.span(), expected_args, 2, Enclosing::DoubleQuote)];
2886                            if expected_args.len() == 1 {
2887                                hints.push(Hint::help(source_engine, arg.span(), format!("The only valid argument is \"{}\".", expected_args[0])));
2888                            } else if expected_args.len() <= 3 {
2889                                hints.push(Hint::help(source_engine, arg.span(), format!("Valid arguments are {}.", sequence_to_str(expected_args, Enclosing::DoubleQuote, usize::MAX))));
2890                            } else {
2891                                hints.push(Hint::help(source_engine, arg.span(), "Valid arguments are:".to_string()));
2892                                hints.append(&mut Hint::multi_help(source_engine, &arg.span(), sequence_to_list(expected_args, Indent::Single, usize::MAX)))
2893                            }
2894                            hints
2895                        },
2896                        help: vec![],
2897                    },
2898                    ConvertParseTreeError::InvalidAttributeArgExpectsValue { attribute, arg, value_span  } => Diagnostic {
2899                        reason: Some(Reason::new(code(1), format!("Attribute argument must {}have a value",
2900                            match value_span {
2901                                Some(_) => "not ",
2902                                None => "",
2903                            }
2904                        ))),
2905                        issue: Issue::error(
2906                            source_engine,
2907                            arg.span(),
2908                            format!("\"{arg}\" argument of the attribute \"{attribute}\" must {}have a value.",
2909                                match value_span {
2910                                    Some(_) => "not ",
2911                                    None => "",
2912                                }
2913                            )
2914                        ),
2915                        hints: vec![
2916                            match &value_span {
2917                                Some(value_span) => Hint::help(source_engine, value_span.clone(), format!("Remove the value: `= {}`.", value_span.as_str())),
2918                                None => Hint::help(source_engine, arg.span(), format!("To set the value, use the `=` operator: `{arg} = <value>`.")),
2919                            }
2920                        ],
2921                        help: vec![],
2922                    },
2923                    ConvertParseTreeError::InvalidAttributeArgValueType { span, arg, expected_type, received_type } => Diagnostic {
2924                        reason: Some(Reason::new(code(1), "Attribute argument value has a wrong type".to_string())),
2925                        issue: Issue::error(
2926                            source_engine,
2927                            span.clone(),
2928                            format!("\"{arg}\" argument must have a value of type \"{expected_type}\".")
2929                        ),
2930                        hints: vec![
2931                            Hint::help(
2932                                source_engine,
2933                                span.clone(),
2934                                format!("This value has type \"{received_type}\"."),
2935                            )
2936                        ],
2937                        help: vec![],
2938                    },
2939                    ConvertParseTreeError::InvalidAttributeArgValue { span, arg, expected_values } => Diagnostic {
2940                        reason: Some(Reason::new(code(1), "Attribute argument value is invalid".to_string())),
2941                        issue: Issue::error(
2942                            source_engine,
2943                            span.clone(),
2944                            format!("\"{}\" is an invalid value for argument \"{arg}\".", span.as_str())
2945                        ),
2946                        hints: {
2947                            let mut hints = vec![did_you_mean_help(source_engine, span.clone(), expected_values, 2, Enclosing::DoubleQuote)];
2948                            if expected_values.len() == 1 {
2949                                hints.push(Hint::help(source_engine, span.clone(), format!("The only valid argument value is \"{}\".", expected_values[0])));
2950                            } else if expected_values.len() <= 3 {
2951                                hints.push(Hint::help(source_engine, span.clone(), format!("Valid argument values are {}.", sequence_to_str(expected_values, Enclosing::DoubleQuote, usize::MAX))));
2952                            } else {
2953                                hints.push(Hint::help(source_engine, span.clone(), "Valid argument values are:".to_string()));
2954                                hints.append(&mut Hint::multi_help(source_engine, span, sequence_to_list(expected_values, Indent::Single, usize::MAX)))
2955                            }
2956                            hints
2957                        },
2958                        help: vec![],
2959                    },
2960                    _ => Diagnostic {
2961                                // TODO: Temporarily we use `self` here to achieve backward compatibility.
2962                                //       In general, `self` must not be used. All the values for the formatting
2963                                //       of a diagnostic must come from its enum variant parameters.
2964                                issue: Issue::error(source_engine, self.span(), format!("{self}")),
2965                                ..Default::default()
2966                        },
2967                }
2968            }
2969            ConfigurableMissingAbiDecodeInPlace { span } => Diagnostic {
2970                reason: Some(Reason::new(code(1), "Configurables need a function named \"abi_decode_in_place\" to be in scope".to_string())),
2971                issue: Issue::error(
2972                    source_engine,
2973                    span.clone(),
2974                    String::new()
2975                ),
2976                hints: vec![],
2977                help: vec![
2978                    "The function \"abi_decode_in_place\" is usually defined in the standard library module \"std::codec\".".into(),
2979                    "Verify that you are using a version of the \"std\" standard library that contains this function.".into(),
2980                ],
2981            },
2982            StorageAccessMismatched { span, is_pure, suggested_attributes, storage_access_violations } => Diagnostic {
2983                // Pure function cannot access storage
2984                //   or
2985                // Storage read-only function cannot write to storage
2986                reason: Some(Reason::new(code(1), format!("{} function cannot {} storage",
2987                    if *is_pure {
2988                        "Pure"
2989                    } else {
2990                        "Storage read-only"
2991                    },
2992                    if *is_pure {
2993                        "access"
2994                    } else {
2995                        "write to"
2996                    }
2997                ))),
2998                issue: Issue::error(
2999                    source_engine,
3000                    span.clone(),
3001                    format!("Function \"{}\" is {} and cannot {} storage.",
3002                        span.as_str(),
3003                        if *is_pure {
3004                            "pure"
3005                        } else {
3006                            "declared as `#[storage(read)]`"
3007                        },
3008                        if *is_pure {
3009                            "access"
3010                        } else {
3011                            "write to"
3012                        },
3013                    )
3014                ),
3015                hints: storage_access_violations
3016                    .iter()
3017                    .map(|(span, storage_access)| Hint::info(
3018                        source_engine,
3019                        span.clone(),
3020                        format!("{storage_access}")
3021                    ))
3022                    .collect(),
3023                help: vec![
3024                    format!("Consider declaring the function \"{}\" as `#[storage({suggested_attributes})]`,",
3025                        span.as_str()
3026                    ),
3027                    format!("or removing the {} from the function body.",
3028                        if *is_pure {
3029                            "storage access code".to_string()
3030                        } else {
3031                            format!("storage write{}", plural_s(storage_access_violations.len()))
3032                        }
3033                    ),
3034                ],
3035            },
3036            MultipleImplsSatisfyingTraitForType { span, type_annotation , trait_names, trait_types_and_names: trait_types_and_spans } => Diagnostic {
3037                reason: Some(Reason::new(code(1), format!("Multiple impls satisfying {} for {}", trait_names.join("+"), type_annotation))),
3038                issue: Issue::error(
3039                    source_engine,
3040                    span.clone(),
3041                    String::new()
3042                ),
3043                hints: vec![],
3044                help: vec![format!("Trait{} implemented for types:\n{}", if trait_names.len() > 1 {"s"} else {""}, trait_types_and_spans.iter().enumerate().map(|(e, (type_id, name))| 
3045                    format!("#{} {} for {}", e, name, type_id.clone())
3046                ).collect::<Vec<_>>().join("\n"))],
3047            },
3048            MultipleContractsMethodsWithTheSameName { spans } => Diagnostic {
3049                reason: Some(Reason::new(code(1), "Multiple contracts methods with the same name.".into())),
3050                issue: Issue::error(
3051                    source_engine,
3052                    spans[0].clone(),
3053                    "This is the first method".into()
3054                ),
3055                hints: spans.iter().skip(1).map(|span| {
3056                    Hint::error(source_engine, span.clone(), "This is the duplicated method.".into())
3057                }).collect(),
3058                help: vec!["Contract methods names must be unique, even when implementing multiple ABIs.".into()],
3059            },
3060            FunctionSelectorClash { method_name, span, other_method_name, other_span } => Diagnostic {
3061                reason: Some(Reason::new(code(1), format!("Methods {method_name} and {other_method_name} have clashing function selectors."))),
3062                issue: Issue::error(
3063                    source_engine,
3064                    span.clone(),
3065                    String::new()
3066                ),
3067                hints: vec![Hint::error(source_engine, other_span.clone(), format!("The declaration of {other_method_name} is here"))],
3068                help: vec![format!("The methods of a contract must have distinct function selectors, which are computed from the method hash. \nRenaming one of the methods should solve the problem")]
3069            },
3070            ErrorTypeEnumHasNonErrorVariants { enum_name, non_error_variants } => Diagnostic {
3071                reason: Some(Reason::new(code(1), "Error type enum cannot have non-error variants".to_string())),
3072                issue: Issue::error(
3073                    source_engine,
3074                    enum_name.span(),
3075                    format!("Error type enum \"{enum_name}\" has non-error variant{} {}.",
3076                        plural_s(non_error_variants.len()),
3077                        sequence_to_str(non_error_variants, Enclosing::DoubleQuote, 2)
3078                    )
3079                ),
3080                hints: non_error_variants.iter().map(|variant| Hint::underscored_info(source_engine, variant.span())).collect(),
3081                help: vec![
3082                    "All error type enum's variants must be marked as errors.".to_string(),
3083                    "To mark error variants as errors, annotate them with the `#[error]` attribute.".to_string(),
3084                ]
3085            },
3086            ErrorAttributeInNonErrorEnum { enum_name, enum_variant_name } => Diagnostic {
3087                reason: Some(Reason::new(code(1), "Error enum variants must be in error type enums".to_string())),
3088                issue: Issue::error(
3089                    source_engine,
3090                    enum_variant_name.span(),
3091                    format!("Enum variant \"{enum_variant_name}\" is marked as `#[error]`, but its enum is not an error type enum.")
3092                ),
3093                hints: vec![
3094                    Hint::help(
3095                        source_engine,
3096                        enum_name.span(),
3097                        format!("Consider annotating \"{enum_name}\" enum with the `#[error_type]` attribute."),
3098                    )
3099                ],
3100                help: vec![
3101                    "Enum variants can be marked as `#[error]` only if their parent enum is annotated with the `#[error_type]` attribute.".to_string(),
3102                ]
3103            },
3104            PanicExpressionArgumentIsNotError { argument_type, span } => Diagnostic {
3105                reason: Some(Reason::new(code(1), "Panic expression arguments must implement \"Error\" marker trait".into())),
3106                issue: Issue::error(
3107                    source_engine,
3108                    span.clone(),
3109                    format!("This expression has type \"{argument_type}\", which does not implement \"std::marker::Error\" trait."),
3110                ),
3111                hints: vec![],
3112                help: {
3113                    let mut help = vec![
3114                        "Panic expression accepts only arguments that implement \"std::marker::Error\" trait.".to_string(),
3115                        Diagnostic::help_empty_line(),
3116                    ];
3117                    help.append(&mut error_marker_trait_help_msg());
3118                    help
3119                },
3120            },
3121            IncoherentImplDueToOrphanRule { trait_name, type_name, span } => Diagnostic {
3122                reason: Some(Reason::new(
3123                    code(1),
3124                    "coherence violation: only traits defined in this module can be implemented for external types".into()
3125                )),
3126                issue: Issue::error(
3127                    source_engine,
3128                    span.clone(),
3129                    format!(
3130                        "cannot implement `{trait_name}` for `{type_name}`: both originate outside this module"
3131                    ),
3132                ),
3133                hints: vec![],
3134                help: {
3135                    let help = vec![
3136                        "only traits defined in this module can be implemented for external types".to_string(),
3137                        Diagnostic::help_empty_line(),
3138                        format!(
3139                            "move this impl into the module that defines `{type_name}`"
3140                        ),
3141                        format!(
3142                            "or define and use a local trait instead of `{trait_name}` to avoid the orphan rule"
3143                        ),
3144                    ];
3145                    help
3146                },
3147            },
3148            ABIDuplicateName { span, other_span: other, is_attribute } => Diagnostic {
3149                reason: Some(Reason::new(code(1), "Duplicated name found for renamed ABI type".into())),
3150                issue: Issue::error(
3151                    source_engine,
3152                    span.clone(),
3153                    String::new()
3154                ),
3155                hints: vec![
3156                    Hint::help(
3157                        source_engine,
3158                        other.clone(),
3159                        format!("This is the existing {} with conflicting name.", if *is_attribute { "attribute" } else { "type" }),
3160                    )
3161                ],
3162                help: vec![],
3163            },
3164            ABIInvalidName { span, name } => Diagnostic {
3165                reason: Some(Reason::new(code(1), "Invalid name found for renamed ABI type.".into())),
3166                issue: Issue::error(
3167                    source_engine,
3168                    span.clone(),
3169                    String::new()
3170                ),
3171                hints: vec![],
3172                help: vec![format!("The name must be a valid Sway identifier{}.", if name.is_empty() { " and cannot be empty" } else { "" })],
3173            },
3174            MultipleDefinitionsOfConstant { name, old, new } => {
3175                Diagnostic {
3176                    reason: Some(Reason::new(code(1), "Multiple definitions of constant".into())),
3177                    issue: Issue::error(
3178                        source_engine,
3179                        new.clone(),
3180                        format!("Constant \"{name}\" was already defined"),
3181                    ),
3182                    hints:vec![
3183                        Hint::error(
3184                            source_engine,
3185                            old.clone(),
3186                            "Its first definition is here.".into(),
3187                        ),
3188                    ],
3189                    help:vec![],
3190                }
3191            }
3192            _ => Diagnostic {
3193                    // TODO: Temporarily we use `self` here to achieve backward compatibility.
3194                    //       In general, `self` must not be used. All the values for the formatting
3195                    //       of a diagnostic must come from its enum variant parameters.
3196                    issue: Issue::error(source_engine, self.span(), format!("{self}")),
3197                    ..Default::default()
3198            }
3199        }
3200    }
3201}
3202
3203#[derive(Error, Debug, Clone, PartialEq, Eq, Hash)]
3204pub enum TypeNotAllowedReason {
3205    #[error(
3206        "Returning a type containing `raw_slice` from `main()` is not allowed. \
3207            Consider converting it into a flat `raw_slice` first."
3208    )]
3209    NestedSliceReturnNotAllowedInMain,
3210
3211    #[error("The type \"{ty}\" is not allowed in storage.")]
3212    TypeNotAllowedInContractStorage { ty: String },
3213
3214    #[error("`str` or a type containing `str` on `main()` arguments is not allowed.")]
3215    StringSliceInMainParameters,
3216
3217    #[error("Returning `str` or a type containing `str` from `main()` is not allowed.")]
3218    StringSliceInMainReturn,
3219
3220    #[error("`str` or a type containing `str` on `configurables` is not allowed.")]
3221    StringSliceInConfigurables,
3222
3223    #[error("`str` or a type containing `str` on `const` is not allowed.")]
3224    StringSliceInConst,
3225
3226    #[error("slices or types containing slices on `const` are not allowed.")]
3227    SliceInConst,
3228
3229    #[error("references, pointers, slices, string slices or types containing any of these are not allowed.")]
3230    NotAllowedInTransmute,
3231}
3232
3233#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3234pub enum StructFieldUsageContext {
3235    StructInstantiation { struct_can_be_instantiated: bool },
3236    StorageDeclaration { struct_can_be_instantiated: bool },
3237    StorageAccess,
3238    PatternMatching { has_rest_pattern: bool },
3239    StructFieldAccess,
3240    // TODO: Distinguish between struct field access and destructing
3241    //       once https://github.com/FuelLabs/sway/issues/5478 is implemented
3242    //       and provide specific suggestions for these two cases.
3243    //       (Destructing desugars to plain struct field access.)
3244}
3245
3246#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3247pub enum InvalidImplementingForType {
3248    SelfType,
3249    Placeholder,
3250    Other,
3251}
3252
3253impl fmt::Display for InvalidImplementingForType {
3254    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
3255        match self {
3256            Self::SelfType => f.write_str("\"Self\""),
3257            Self::Placeholder => f.write_str("Placeholder `_`"),
3258            Self::Other => f.write_str("This"),
3259        }
3260    }
3261}
3262
3263/// Defines what shadows a constant or a configurable.
3264#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3265pub enum ShadowingSource {
3266    /// A constant or a configurable is shadowed by a constant.
3267    Const,
3268    /// A constant or a configurable is shadowed by a local variable declared with the `let` keyword.
3269    LetVar,
3270    /// A constant or a configurable is shadowed by a variable declared in pattern matching,
3271    /// being a struct field. E.g., `S { some_field }`.
3272    PatternMatchingStructFieldVar,
3273}
3274
3275impl fmt::Display for ShadowingSource {
3276    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
3277        match self {
3278            Self::Const => f.write_str("Constant"),
3279            Self::LetVar => f.write_str("Variable"),
3280            Self::PatternMatchingStructFieldVar => f.write_str("Pattern variable"),
3281        }
3282    }
3283}
3284
3285/// Defines how a storage gets accessed within a function body.
3286/// E.g., calling `__state_clear` intrinsic or using `scwq` ASM instruction
3287/// represent a [StorageAccess::Clear] access.
3288#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3289pub enum StorageAccess {
3290    Clear,
3291    ReadWord,
3292    ReadSlots,
3293    WriteWord,
3294    WriteSlots,
3295    /// Storage access happens via call to an impure function.
3296    /// The parameters are the call path span and if the called function
3297    /// reads from and writes to the storage: (call_path, reads, writes).
3298    ImpureFunctionCall(Span, bool, bool),
3299}
3300
3301impl StorageAccess {
3302    pub fn is_write(&self) -> bool {
3303        matches!(
3304            self,
3305            Self::Clear | Self::WriteWord | Self::WriteSlots | Self::ImpureFunctionCall(_, _, true)
3306        )
3307    }
3308}
3309
3310impl fmt::Display for StorageAccess {
3311    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
3312        match self {
3313            Self::Clear => f.write_str("Clearing the storage happens here."),
3314            Self::ReadWord => f.write_str("Reading a word from the storage happens here."),
3315            Self::ReadSlots => f.write_str("Reading storage slots happens here."),
3316            Self::WriteWord => f.write_str("Writing a word to the storage happens here."),
3317            Self::WriteSlots => f.write_str("Writing to storage slots happens here."),
3318            Self::ImpureFunctionCall(call_path, reads, writes) => f.write_fmt(format_args!(
3319                "Function \"{}\" {} the storage.",
3320                call_path_suffix_with_args(&call_path.as_str().to_string()),
3321                match (reads, writes) {
3322                    (true, true) => "reads from and writes to",
3323                    (true, false) => "reads from",
3324                    (false, true) => "writes to",
3325                    (false, false) => unreachable!(
3326                        "Function \"{}\" is impure, so it must read from or write to the storage.",
3327                        call_path.as_str()
3328                    ),
3329                }
3330            )),
3331        }
3332    }
3333}
3334
3335/// Extracts only the suffix part of the `marker_trait_full_name`, without the arguments.
3336/// E.g.:
3337/// - `std::marker::Error` => `Error`
3338/// - `std::marker::SomeMarkerTrait::<T>` => `SomeMarkerTrait`
3339/// - `std::marker::SomeMarkerTrait<T>` => `SomeMarkerTrait`
3340///
3341/// Panics if the `marker_trait_full_name` does not start with "std::marker::".
3342fn marker_trait_name(marker_trait_full_name: &str) -> &str {
3343    const MARKER_TRAITS_MODULE: &str = "std::marker::";
3344    assert!(
3345        marker_trait_full_name.starts_with(MARKER_TRAITS_MODULE),
3346        "`marker_trait_full_name` must start with \"std::marker::\", but it was \"{marker_trait_full_name}\""
3347    );
3348
3349    let lower_boundary = MARKER_TRAITS_MODULE.len();
3350    let name_part = &marker_trait_full_name[lower_boundary..];
3351
3352    let upper_boundary = marker_trait_full_name.len() - lower_boundary;
3353    let only_name_len = std::cmp::min(
3354        name_part.find(':').unwrap_or(upper_boundary),
3355        name_part.find('<').unwrap_or(upper_boundary),
3356    );
3357    let upper_boundary = lower_boundary + only_name_len;
3358
3359    &marker_trait_full_name[lower_boundary..upper_boundary]
3360}
3361
3362fn error_marker_trait_help_msg() -> Vec<String> {
3363    vec![
3364        "\"Error\" marker trait is automatically implemented by the compiler for the unit type `()`,".to_string(),
3365        "string slices, and enums annotated with the `#[error_type]` attribute.".to_string(),
3366    ]
3367}