sway_core/language/ty/expression/
expression_variant.rs

1use crate::{
2    decl_engine::*,
3    engine_threading::*,
4    has_changes,
5    language::{ty::*, *},
6    semantic_analysis::{
7        TyNodeDepGraphEdge, TyNodeDepGraphEdgeInfo, TypeCheckAnalysis, TypeCheckAnalysisContext,
8        TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext,
9    },
10    type_system::*,
11};
12use indexmap::IndexMap;
13use serde::{Deserialize, Serialize};
14use std::{
15    collections::VecDeque,
16    fmt::{self, Write},
17    hash::{Hash, Hasher},
18};
19use sway_error::handler::{ErrorEmitted, Handler};
20use sway_types::{Ident, Named, Span, Spanned};
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
23pub enum TyExpressionVariant {
24    Literal(Literal),
25    FunctionApplication {
26        call_path: CallPath,
27        arguments: Vec<(Ident, TyExpression)>,
28        fn_ref: DeclRefFunction,
29        selector: Option<ContractCallParams>,
30        /// optional binding information for the LSP
31        type_binding: Option<TypeBinding<()>>,
32        /// In case it is a method should contain a TypeId to either an enum, struct or a type alias.
33        call_path_typeid: Option<TypeId>,
34        contract_call_params: IndexMap<String, TyExpression>,
35        contract_caller: Option<Box<TyExpression>>,
36    },
37    LazyOperator {
38        op: LazyOp,
39        lhs: Box<TyExpression>,
40        rhs: Box<TyExpression>,
41    },
42    ConstantExpression {
43        span: Span,
44        decl: Box<TyConstantDecl>,
45        call_path: Option<CallPath>,
46    },
47    ConfigurableExpression {
48        span: Span,
49        decl: Box<TyConfigurableDecl>,
50        call_path: Option<CallPath>,
51    },
52    ConstGenericExpression {
53        span: Span,
54        decl: Box<TyConstGenericDecl>,
55        call_path: Option<CallPath>,
56    },
57    VariableExpression {
58        name: Ident,
59        span: Span,
60        mutability: VariableMutability,
61        call_path: Option<CallPath>,
62    },
63    Tuple {
64        fields: Vec<TyExpression>,
65    },
66    ArrayExplicit {
67        elem_type: TypeId,
68        contents: Vec<TyExpression>,
69    },
70    ArrayRepeat {
71        elem_type: TypeId,
72        value: Box<TyExpression>,
73        length: Box<TyExpression>,
74    },
75    ArrayIndex {
76        prefix: Box<TyExpression>,
77        index: Box<TyExpression>,
78    },
79    StructExpression {
80        struct_id: DeclId<TyStructDecl>,
81        fields: Vec<TyStructExpressionField>,
82        instantiation_span: Span,
83        call_path_binding: TypeBinding<CallPath>,
84    },
85    CodeBlock(TyCodeBlock),
86    // a flag that this value will later be provided as a parameter, but is currently unknown
87    FunctionParameter,
88    MatchExp {
89        desugared: Box<TyExpression>,
90        scrutinees: Vec<TyScrutinee>,
91    },
92    IfExp {
93        condition: Box<TyExpression>,
94        then: Box<TyExpression>,
95        r#else: Option<Box<TyExpression>>,
96    },
97    AsmExpression {
98        registers: Vec<TyAsmRegisterDeclaration>,
99        body: Vec<AsmOp>,
100        returns: Option<(AsmRegister, Span)>,
101        whole_block_span: Span,
102    },
103    // like a variable expression but it has multiple parts,
104    // like looking up a field in a struct
105    StructFieldAccess {
106        prefix: Box<TyExpression>,
107        field_to_access: TyStructField,
108        field_instantiation_span: Span,
109        /// Final resolved type of the `prefix` part
110        /// of the expression. This will always be
111        /// a [TypeId] of a struct, never an alias
112        /// or a reference to a struct.
113        /// The original parent might be an alias
114        /// or a direct or indirect reference to a
115        /// struct.
116        resolved_type_of_parent: TypeId,
117    },
118    TupleElemAccess {
119        prefix: Box<TyExpression>,
120        elem_to_access_num: usize,
121        /// Final resolved type of the `prefix` part
122        /// of the expression. This will always be
123        /// a [TypeId] of a tuple, never an alias
124        /// or a reference to a tuple.
125        /// The original parent might be an alias
126        /// or a direct or indirect reference to a
127        /// tuple.
128        resolved_type_of_parent: TypeId,
129        elem_to_access_span: Span,
130    },
131    EnumInstantiation {
132        enum_ref: DeclRef<DeclId<TyEnumDecl>>,
133        /// for printing
134        variant_name: Ident,
135        tag: usize,
136        contents: Option<Box<TyExpression>>,
137        /// If there is an error regarding this instantiation of the enum,
138        /// use these spans as it points to the call site and not the declaration.
139        /// They are also used in the language server.
140        variant_instantiation_span: Span,
141        call_path_binding: TypeBinding<CallPath>,
142        /// The enum type, can be a type alias.
143        call_path_decl: ty::TyDecl,
144    },
145    AbiCast {
146        abi_name: CallPath,
147        address: Box<TyExpression>,
148        #[allow(dead_code)]
149        // this span may be used for errors in the future, although it is not right now.
150        span: Span,
151    },
152    StorageAccess(TyStorageAccess),
153    IntrinsicFunction(TyIntrinsicFunctionKind),
154    /// a zero-sized type-system-only compile-time thing that is used for constructing ABI casts.
155    AbiName(AbiName),
156    /// grabs the enum tag from the particular enum and variant of the `exp`
157    EnumTag {
158        exp: Box<TyExpression>,
159    },
160    /// performs an unsafe cast from the `exp` to the type of the given enum `variant`
161    UnsafeDowncast {
162        exp: Box<TyExpression>,
163        variant: TyEnumVariant,
164        /// Should contain a TyDecl to either an enum or a type alias.
165        call_path_decl: ty::TyDecl,
166    },
167    WhileLoop {
168        condition: Box<TyExpression>,
169        body: TyCodeBlock,
170    },
171    ForLoop {
172        desugared: Box<TyExpression>,
173    },
174    Break,
175    Continue,
176    Reassignment(Box<TyReassignment>),
177    ImplicitReturn(Box<TyExpression>),
178    Return(Box<TyExpression>),
179    Ref(Box<TyExpression>),
180    Deref(Box<TyExpression>),
181}
182
183impl TyExpressionVariant {
184    pub fn as_literal(&self) -> Option<&Literal> {
185        match self {
186            TyExpressionVariant::Literal(v) => Some(v),
187            _ => None,
188        }
189    }
190}
191
192impl EqWithEngines for TyExpressionVariant {}
193impl PartialEqWithEngines for TyExpressionVariant {
194    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
195        let type_engine = ctx.engines().te();
196        match (self, other) {
197            (Self::Literal(l0), Self::Literal(r0)) => l0 == r0,
198            (
199                Self::FunctionApplication {
200                    call_path: l_name,
201                    arguments: l_arguments,
202                    fn_ref: l_fn_ref,
203                    ..
204                },
205                Self::FunctionApplication {
206                    call_path: r_name,
207                    arguments: r_arguments,
208                    fn_ref: r_fn_ref,
209                    ..
210                },
211            ) => {
212                l_name == r_name
213                    && l_arguments.len() == r_arguments.len()
214                    && l_arguments
215                        .iter()
216                        .zip(r_arguments.iter())
217                        .all(|((xa, xb), (ya, yb))| xa == ya && xb.eq(yb, ctx))
218                    && l_fn_ref.eq(r_fn_ref, ctx)
219            }
220            (
221                Self::LazyOperator {
222                    op: l_op,
223                    lhs: l_lhs,
224                    rhs: l_rhs,
225                },
226                Self::LazyOperator {
227                    op: r_op,
228                    lhs: r_lhs,
229                    rhs: r_rhs,
230                },
231            ) => l_op == r_op && (**l_lhs).eq(&(**r_lhs), ctx) && (**l_rhs).eq(&(**r_rhs), ctx),
232            (
233                Self::ConstantExpression {
234                    call_path: l_call_path,
235                    span: l_span,
236                    decl: _,
237                },
238                Self::ConstantExpression {
239                    call_path: r_call_path,
240                    span: r_span,
241                    decl: _,
242                },
243            ) => l_call_path == r_call_path && l_span == r_span,
244            (
245                Self::VariableExpression {
246                    name: l_name,
247                    span: l_span,
248                    mutability: l_mutability,
249                    call_path: _,
250                },
251                Self::VariableExpression {
252                    name: r_name,
253                    span: r_span,
254                    mutability: r_mutability,
255                    call_path: _,
256                },
257            ) => l_name == r_name && l_span == r_span && l_mutability == r_mutability,
258            (Self::Tuple { fields: l_fields }, Self::Tuple { fields: r_fields }) => {
259                l_fields.eq(r_fields, ctx)
260            }
261            (
262                Self::ArrayExplicit {
263                    contents: l_contents,
264                    ..
265                },
266                Self::ArrayExplicit {
267                    contents: r_contents,
268                    ..
269                },
270            ) => l_contents.eq(r_contents, ctx),
271            (
272                Self::ArrayIndex {
273                    prefix: l_prefix,
274                    index: l_index,
275                },
276                Self::ArrayIndex {
277                    prefix: r_prefix,
278                    index: r_index,
279                },
280            ) => (**l_prefix).eq(&**r_prefix, ctx) && (**l_index).eq(&**r_index, ctx),
281            (
282                Self::StructExpression {
283                    struct_id: l_struct_id,
284                    fields: l_fields,
285                    instantiation_span: l_span,
286                    call_path_binding: _,
287                },
288                Self::StructExpression {
289                    struct_id: r_struct_id,
290                    fields: r_fields,
291                    instantiation_span: r_span,
292                    call_path_binding: _,
293                },
294            ) => {
295                PartialEqWithEngines::eq(&l_struct_id, &r_struct_id, ctx)
296                    && l_fields.eq(r_fields, ctx)
297                    && l_span == r_span
298            }
299            (Self::CodeBlock(l0), Self::CodeBlock(r0)) => l0.eq(r0, ctx),
300            (
301                Self::IfExp {
302                    condition: l_condition,
303                    then: l_then,
304                    r#else: l_r,
305                },
306                Self::IfExp {
307                    condition: r_condition,
308                    then: r_then,
309                    r#else: r_r,
310                },
311            ) => {
312                (**l_condition).eq(&**r_condition, ctx)
313                    && (**l_then).eq(&**r_then, ctx)
314                    && if let (Some(l), Some(r)) = (l_r, r_r) {
315                        (**l).eq(&**r, ctx)
316                    } else {
317                        true
318                    }
319            }
320            (
321                Self::AsmExpression {
322                    registers: l_registers,
323                    body: l_body,
324                    returns: l_returns,
325                    ..
326                },
327                Self::AsmExpression {
328                    registers: r_registers,
329                    body: r_body,
330                    returns: r_returns,
331                    ..
332                },
333            ) => {
334                l_registers.eq(r_registers, ctx)
335                    && l_body.clone() == r_body.clone()
336                    && l_returns == r_returns
337            }
338            (
339                Self::StructFieldAccess {
340                    prefix: l_prefix,
341                    field_to_access: l_field_to_access,
342                    resolved_type_of_parent: l_resolved_type_of_parent,
343                    ..
344                },
345                Self::StructFieldAccess {
346                    prefix: r_prefix,
347                    field_to_access: r_field_to_access,
348                    resolved_type_of_parent: r_resolved_type_of_parent,
349                    ..
350                },
351            ) => {
352                (**l_prefix).eq(&**r_prefix, ctx)
353                    && l_field_to_access.eq(r_field_to_access, ctx)
354                    && type_engine
355                        .get(*l_resolved_type_of_parent)
356                        .eq(&type_engine.get(*r_resolved_type_of_parent), ctx)
357            }
358            (
359                Self::TupleElemAccess {
360                    prefix: l_prefix,
361                    elem_to_access_num: l_elem_to_access_num,
362                    resolved_type_of_parent: l_resolved_type_of_parent,
363                    ..
364                },
365                Self::TupleElemAccess {
366                    prefix: r_prefix,
367                    elem_to_access_num: r_elem_to_access_num,
368                    resolved_type_of_parent: r_resolved_type_of_parent,
369                    ..
370                },
371            ) => {
372                (**l_prefix).eq(&**r_prefix, ctx)
373                    && l_elem_to_access_num == r_elem_to_access_num
374                    && type_engine
375                        .get(*l_resolved_type_of_parent)
376                        .eq(&type_engine.get(*r_resolved_type_of_parent), ctx)
377            }
378            (
379                Self::EnumInstantiation {
380                    enum_ref: l_enum_ref,
381                    variant_name: l_variant_name,
382                    tag: l_tag,
383                    contents: l_contents,
384                    ..
385                },
386                Self::EnumInstantiation {
387                    enum_ref: r_enum_ref,
388                    variant_name: r_variant_name,
389                    tag: r_tag,
390                    contents: r_contents,
391                    ..
392                },
393            ) => {
394                l_enum_ref.eq(r_enum_ref, ctx)
395                    && l_variant_name == r_variant_name
396                    && l_tag == r_tag
397                    && if let (Some(l_contents), Some(r_contents)) = (l_contents, r_contents) {
398                        (**l_contents).eq(&**r_contents, ctx)
399                    } else {
400                        true
401                    }
402            }
403            (
404                Self::AbiCast {
405                    abi_name: l_abi_name,
406                    address: l_address,
407                    ..
408                },
409                Self::AbiCast {
410                    abi_name: r_abi_name,
411                    address: r_address,
412                    ..
413                },
414            ) => l_abi_name == r_abi_name && (**l_address).eq(&**r_address, ctx),
415            (Self::IntrinsicFunction(l_kind), Self::IntrinsicFunction(r_kind)) => {
416                l_kind.eq(r_kind, ctx)
417            }
418            (
419                Self::UnsafeDowncast {
420                    exp: l_exp,
421                    variant: l_variant,
422                    call_path_decl: _,
423                },
424                Self::UnsafeDowncast {
425                    exp: r_exp,
426                    variant: r_variant,
427                    call_path_decl: _,
428                },
429            ) => l_exp.eq(r_exp, ctx) && l_variant.eq(r_variant, ctx),
430            (Self::EnumTag { exp: l_exp }, Self::EnumTag { exp: r_exp }) => l_exp.eq(r_exp, ctx),
431            (Self::StorageAccess(l_exp), Self::StorageAccess(r_exp)) => l_exp.eq(r_exp, ctx),
432            (
433                Self::WhileLoop {
434                    body: l_body,
435                    condition: l_condition,
436                },
437                Self::WhileLoop {
438                    body: r_body,
439                    condition: r_condition,
440                },
441            ) => l_body.eq(r_body, ctx) && l_condition.eq(r_condition, ctx),
442            (l, r) => std::mem::discriminant(l) == std::mem::discriminant(r),
443        }
444    }
445}
446
447impl HashWithEngines for TyExpressionVariant {
448    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
449        let type_engine = engines.te();
450        std::mem::discriminant(self).hash(state);
451        match self {
452            Self::Literal(lit) => {
453                lit.hash(state);
454            }
455            Self::FunctionApplication {
456                call_path,
457                arguments,
458                fn_ref,
459                // these fields are not hashed because they aren't relevant/a
460                // reliable source of obj v. obj distinction
461                contract_call_params: _,
462                selector: _,
463                type_binding: _,
464                call_path_typeid: _,
465                ..
466            } => {
467                call_path.hash(state);
468                fn_ref.hash(state, engines);
469                arguments.iter().for_each(|(name, arg)| {
470                    name.hash(state);
471                    arg.hash(state, engines);
472                });
473            }
474            Self::LazyOperator { op, lhs, rhs } => {
475                op.hash(state);
476                lhs.hash(state, engines);
477                rhs.hash(state, engines);
478            }
479            Self::ConstantExpression {
480                decl: const_decl,
481                span: _,
482                call_path: _,
483            } => {
484                const_decl.hash(state, engines);
485            }
486            Self::ConfigurableExpression {
487                decl: const_decl,
488                span: _,
489                call_path: _,
490            } => {
491                const_decl.hash(state, engines);
492            }
493            Self::ConstGenericExpression {
494                decl: const_generic_decl,
495                span: _,
496                call_path: _,
497            } => {
498                const_generic_decl.name().hash(state);
499            }
500            Self::VariableExpression {
501                name,
502                mutability,
503                // these fields are not hashed because they aren't relevant/a
504                // reliable source of obj v. obj distinction
505                call_path: _,
506                span: _,
507            } => {
508                name.hash(state);
509                mutability.hash(state);
510            }
511            Self::Tuple { fields } => {
512                fields.hash(state, engines);
513            }
514            Self::ArrayExplicit {
515                contents,
516                elem_type: _,
517            } => {
518                contents.hash(state, engines);
519            }
520            Self::ArrayRepeat {
521                value,
522                length,
523                elem_type: _,
524            } => {
525                value.hash(state, engines);
526                length.hash(state, engines);
527            }
528            Self::ArrayIndex { prefix, index } => {
529                prefix.hash(state, engines);
530                index.hash(state, engines);
531            }
532            Self::StructExpression {
533                struct_id,
534                fields,
535                // these fields are not hashed because they aren't relevant/a
536                // reliable source of obj v. obj distinction
537                instantiation_span: _,
538                call_path_binding: _,
539            } => {
540                HashWithEngines::hash(&struct_id, state, engines);
541                fields.hash(state, engines);
542            }
543            Self::CodeBlock(contents) => {
544                contents.hash(state, engines);
545            }
546            Self::MatchExp {
547                desugared,
548                // these fields are not hashed because they aren't relevant/a
549                // reliable source of obj v. obj distinction
550                scrutinees: _,
551            } => {
552                desugared.hash(state, engines);
553            }
554            Self::IfExp {
555                condition,
556                then,
557                r#else,
558            } => {
559                condition.hash(state, engines);
560                then.hash(state, engines);
561                if let Some(x) = r#else.as_ref() {
562                    x.hash(state, engines)
563                }
564            }
565            Self::AsmExpression {
566                registers,
567                body,
568                returns,
569                // these fields are not hashed because they aren't relevant/a
570                // reliable source of obj v. obj distinction
571                whole_block_span: _,
572            } => {
573                registers.hash(state, engines);
574                body.hash(state);
575                returns.hash(state);
576            }
577            Self::StructFieldAccess {
578                prefix,
579                field_to_access,
580                resolved_type_of_parent,
581                // these fields are not hashed because they aren't relevant/a
582                // reliable source of obj v. obj distinction
583                field_instantiation_span: _,
584            } => {
585                prefix.hash(state, engines);
586                field_to_access.hash(state, engines);
587                type_engine
588                    .get(*resolved_type_of_parent)
589                    .hash(state, engines);
590            }
591            Self::TupleElemAccess {
592                prefix,
593                elem_to_access_num,
594                resolved_type_of_parent,
595                // these fields are not hashed because they aren't relevant/a
596                // reliable source of obj v. obj distinction
597                elem_to_access_span: _,
598            } => {
599                prefix.hash(state, engines);
600                elem_to_access_num.hash(state);
601                type_engine
602                    .get(*resolved_type_of_parent)
603                    .hash(state, engines);
604            }
605            Self::EnumInstantiation {
606                enum_ref,
607                variant_name,
608                tag,
609                contents,
610                // these fields are not hashed because they aren't relevant/a
611                // reliable source of obj v. obj distinction
612                variant_instantiation_span: _,
613                call_path_binding: _,
614                call_path_decl: _,
615            } => {
616                enum_ref.hash(state, engines);
617                variant_name.hash(state);
618                tag.hash(state);
619                if let Some(x) = contents.as_ref() {
620                    x.hash(state, engines)
621                }
622            }
623            Self::AbiCast {
624                abi_name,
625                address,
626                // these fields are not hashed because they aren't relevant/a
627                // reliable source of obj v. obj distinction
628                span: _,
629            } => {
630                abi_name.hash(state);
631                address.hash(state, engines);
632            }
633            Self::StorageAccess(exp) => {
634                exp.hash(state, engines);
635            }
636            Self::IntrinsicFunction(exp) => {
637                exp.hash(state, engines);
638            }
639            Self::AbiName(name) => {
640                name.hash(state);
641            }
642            Self::EnumTag { exp } => {
643                exp.hash(state, engines);
644            }
645            Self::UnsafeDowncast {
646                exp,
647                variant,
648                call_path_decl: _,
649            } => {
650                exp.hash(state, engines);
651                variant.hash(state, engines);
652            }
653            Self::WhileLoop { condition, body } => {
654                condition.hash(state, engines);
655                body.hash(state, engines);
656            }
657            Self::ForLoop { desugared } => {
658                desugared.hash(state, engines);
659            }
660            Self::Break | Self::Continue | Self::FunctionParameter => {}
661            Self::Reassignment(exp) => {
662                exp.hash(state, engines);
663            }
664            Self::ImplicitReturn(exp) | Self::Return(exp) => {
665                exp.hash(state, engines);
666            }
667            Self::Ref(exp) | Self::Deref(exp) => {
668                exp.hash(state, engines);
669            }
670        }
671    }
672}
673
674impl SubstTypes for TyExpressionVariant {
675    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
676        use TyExpressionVariant::*;
677        match self {
678            Literal(..) => HasChanges::No,
679            FunctionApplication {
680                arguments,
681                ref mut fn_ref,
682                ref mut call_path_typeid,
683                ..
684            } => has_changes! {
685                arguments.subst(ctx);
686                if let Some(new_decl_ref) = fn_ref
687                    .clone()
688                    .subst_types_and_insert_new_with_parent(ctx)
689                {
690                    fn_ref.replace_id(*new_decl_ref.id());
691                    HasChanges::Yes
692                } else {
693                    HasChanges::No
694                };
695                call_path_typeid.subst(ctx);
696            },
697            LazyOperator { lhs, rhs, .. } => has_changes! {
698                lhs.subst(ctx);
699                rhs.subst(ctx);
700            },
701            ConstantExpression { decl, .. } => decl.subst(ctx),
702            ConfigurableExpression { decl, .. } => decl.subst(ctx),
703            ConstGenericExpression { decl, .. } => decl.subst(ctx),
704            VariableExpression { .. } => HasChanges::No,
705            Tuple { fields } => fields.subst(ctx),
706            ArrayExplicit {
707                ref mut elem_type,
708                contents,
709            } => has_changes! {
710                elem_type.subst(ctx);
711                contents.subst(ctx);
712            },
713            ArrayRepeat {
714                ref mut elem_type,
715                value,
716                length,
717            } => has_changes! {
718                elem_type.subst(ctx);
719                value.subst(ctx);
720                length.subst(ctx);
721            },
722            ArrayIndex { prefix, index } => has_changes! {
723                prefix.subst(ctx);
724                index.subst(ctx);
725            },
726            StructExpression {
727                struct_id,
728                fields,
729                instantiation_span: _,
730                call_path_binding: _,
731            } => has_changes! {
732                if let Some(new_struct_ref) = struct_id
733                    .clone()
734                    .subst_types_and_insert_new(ctx) {
735                    struct_id.replace_id(*new_struct_ref.id());
736                    HasChanges::Yes
737                } else {
738                    HasChanges::No
739                };
740                fields.subst(ctx);
741            },
742            CodeBlock(block) => block.subst(ctx),
743            FunctionParameter => HasChanges::No,
744            MatchExp { desugared, .. } => desugared.subst(ctx),
745            IfExp {
746                condition,
747                then,
748                r#else,
749            } => has_changes! {
750                condition.subst(ctx);
751                then.subst(ctx);
752                r#else.subst(ctx);
753            },
754            AsmExpression {
755                registers, //: Vec<TyAsmRegisterDeclaration>,
756                ..
757            } => registers.subst(ctx),
758            // like a variable expression but it has multiple parts,
759            // like looking up a field in a struct
760            StructFieldAccess {
761                prefix,
762                field_to_access,
763                ref mut resolved_type_of_parent,
764                ..
765            } => has_changes! {
766                resolved_type_of_parent.subst(ctx);
767                field_to_access.subst(ctx);
768                prefix.subst(ctx);
769            },
770            TupleElemAccess {
771                prefix,
772                ref mut resolved_type_of_parent,
773                ..
774            } => has_changes! {
775                resolved_type_of_parent.subst(ctx);
776                prefix.subst(ctx);
777            },
778            EnumInstantiation {
779                enum_ref, contents, ..
780            } => has_changes! {
781                if let Some(new_enum_ref) = enum_ref
782                    .clone()
783                    .subst_types_and_insert_new(ctx)
784                {
785                    enum_ref.replace_id(*new_enum_ref.id());
786                    HasChanges::Yes
787                } else {
788                    HasChanges::No
789                };
790                contents.subst(ctx);
791            },
792            AbiCast { address, .. } => address.subst(ctx),
793            // storage is never generic and cannot be monomorphized
794            StorageAccess { .. } => HasChanges::No,
795            IntrinsicFunction(kind) => kind.subst(ctx),
796            EnumTag { exp } => exp.subst(ctx),
797            UnsafeDowncast {
798                exp,
799                variant,
800                call_path_decl: _,
801            } => has_changes! {
802                exp.subst(ctx);
803                variant.subst(ctx);
804            },
805            AbiName(_) => HasChanges::No,
806            WhileLoop {
807                ref mut condition,
808                ref mut body,
809            } => {
810                condition.subst(ctx);
811                body.subst(ctx)
812            }
813            ForLoop { ref mut desugared } => desugared.subst(ctx),
814            Break => HasChanges::No,
815            Continue => HasChanges::No,
816            Reassignment(reassignment) => reassignment.subst(ctx),
817            ImplicitReturn(expr) | Return(expr) => expr.subst(ctx),
818            Ref(exp) | Deref(exp) => exp.subst(ctx),
819        }
820    }
821}
822
823impl ReplaceDecls for TyExpressionVariant {
824    fn replace_decls_inner(
825        &mut self,
826        decl_mapping: &DeclMapping,
827        handler: &Handler,
828        ctx: &mut TypeCheckContext,
829    ) -> Result<bool, ErrorEmitted> {
830        handler.scope(|handler| {
831            use TyExpressionVariant::*;
832            match self {
833                Literal(..) => Ok(false),
834                FunctionApplication {
835                    ref mut fn_ref,
836                    ref mut arguments,
837                    call_path,
838                    ..
839                } => {
840                    let mut has_changes = false;
841
842                    has_changes |= fn_ref.replace_decls(decl_mapping, handler, ctx)?;
843
844                    for (_, arg) in arguments.iter_mut() {
845                        if let Ok(r) = arg.replace_decls(decl_mapping, handler, ctx) {
846                            has_changes |= r;
847                        }
848                    }
849
850                    let decl_engine = ctx.engines().de();
851                    let mut method = (*decl_engine.get(fn_ref)).clone();
852
853                    // Finds method implementation for method dummy and replaces it.
854                    // This is required because dummy methods don't have type parameters from impl traits.
855                    // Thus we use the implemented method that already contains all the required type parameters,
856                    // including those from the impl trait.
857                    if method.is_trait_method_dummy {
858                        if let Some(implementing_for_typeid) = method.implementing_for_typeid {
859                            let implementing_type_method_ref = ctx.find_method_for_type(
860                                handler,
861                                implementing_for_typeid,
862                                &[ctx.namespace().current_package_name().clone()],
863                                &call_path.suffix,
864                                method.return_type.type_id,
865                                &arguments
866                                    .iter()
867                                    .map(|a| a.1.return_type)
868                                    .collect::<VecDeque<_>>(),
869                                None,
870                            )?;
871                            method = (*decl_engine.get(&implementing_type_method_ref)).clone();
872                        }
873                    }
874
875                    // Handle the trait constraints. This includes checking to see if the trait
876                    // constraints are satisfied and replacing old decl ids based on the
877                    let mut inner_decl_mapping =
878                        TypeParameter::gather_decl_mapping_from_trait_constraints(
879                            handler,
880                            ctx.by_ref(),
881                            &method.type_parameters,
882                            method.name.as_str(),
883                            &method.name.span(),
884                        )?;
885
886                    inner_decl_mapping.extend(decl_mapping);
887
888                    if method.replace_decls(&inner_decl_mapping, handler, ctx)? {
889                        decl_engine.replace(*fn_ref.id(), method);
890                        has_changes = true;
891                    }
892
893                    Ok(has_changes)
894                }
895                LazyOperator { lhs, rhs, .. } => {
896                    let mut has_changes = (*lhs).replace_decls(decl_mapping, handler, ctx)?;
897                    has_changes |= (*rhs).replace_decls(decl_mapping, handler, ctx)?;
898                    Ok(has_changes)
899                }
900                ConstantExpression { decl, .. } => decl.replace_decls(decl_mapping, handler, ctx),
901                ConfigurableExpression { decl, .. } => {
902                    decl.replace_decls(decl_mapping, handler, ctx)
903                }
904                ConstGenericExpression { .. } => Ok(false),
905                VariableExpression { .. } => Ok(false),
906                Tuple { fields } => {
907                    let mut has_changes = false;
908                    for item in fields.iter_mut() {
909                        if let Ok(r) = item.replace_decls(decl_mapping, handler, ctx) {
910                            has_changes |= r;
911                        }
912                    }
913                    Ok(has_changes)
914                }
915                ArrayExplicit {
916                    elem_type: _,
917                    contents,
918                } => {
919                    let mut has_changes = false;
920                    for expr in contents.iter_mut() {
921                        if let Ok(r) = expr.replace_decls(decl_mapping, handler, ctx) {
922                            has_changes |= r;
923                        }
924                    }
925                    Ok(has_changes)
926                }
927                ArrayRepeat {
928                    elem_type: _,
929                    value,
930                    length,
931                } => {
932                    let mut has_changes = (*value).replace_decls(decl_mapping, handler, ctx)?;
933                    has_changes |= (*length).replace_decls(decl_mapping, handler, ctx)?;
934                    Ok(has_changes)
935                }
936                ArrayIndex { prefix, index } => {
937                    let mut has_changes = false;
938                    if let Ok(r) = (*prefix).replace_decls(decl_mapping, handler, ctx) {
939                        has_changes |= r;
940                    }
941                    if let Ok(r) = (*index).replace_decls(decl_mapping, handler, ctx) {
942                        has_changes |= r;
943                    }
944                    Ok(has_changes)
945                }
946                StructExpression {
947                    struct_id: _,
948                    fields,
949                    instantiation_span: _,
950                    call_path_binding: _,
951                } => {
952                    let mut has_changes = false;
953                    for field in fields.iter_mut() {
954                        if let Ok(r) = field.replace_decls(decl_mapping, handler, ctx) {
955                            has_changes |= r;
956                        }
957                    }
958                    Ok(has_changes)
959                }
960                CodeBlock(block) => block.replace_decls(decl_mapping, handler, ctx),
961                FunctionParameter => Ok(false),
962                MatchExp { desugared, .. } => desugared.replace_decls(decl_mapping, handler, ctx),
963                IfExp {
964                    condition,
965                    then,
966                    r#else,
967                } => {
968                    let mut has_changes = false;
969                    if let Ok(r) = condition.replace_decls(decl_mapping, handler, ctx) {
970                        has_changes |= r;
971                    }
972                    if let Ok(r) = then.replace_decls(decl_mapping, handler, ctx) {
973                        has_changes |= r;
974                    }
975                    if let Some(r) = r#else
976                        .as_mut()
977                        .and_then(|expr| expr.replace_decls(decl_mapping, handler, ctx).ok())
978                    {
979                        has_changes |= r;
980                    }
981                    Ok(has_changes)
982                }
983                AsmExpression { .. } => Ok(false),
984                StructFieldAccess { prefix, .. } => {
985                    prefix.replace_decls(decl_mapping, handler, ctx)
986                }
987                TupleElemAccess { prefix, .. } => prefix.replace_decls(decl_mapping, handler, ctx),
988                EnumInstantiation {
989                    enum_ref: _,
990                    contents,
991                    ..
992                } => {
993                    // TODO: replace enum decl
994                    //enum_decl.replace_decls(decl_mapping);
995                    if let Some(ref mut contents) = contents {
996                        contents.replace_decls(decl_mapping, handler, ctx)
997                    } else {
998                        Ok(false)
999                    }
1000                }
1001                AbiCast { address, .. } => address.replace_decls(decl_mapping, handler, ctx),
1002                StorageAccess { .. } => Ok(false),
1003                IntrinsicFunction(TyIntrinsicFunctionKind { arguments, .. }) => {
1004                    let mut has_changes = false;
1005                    for expr in arguments.iter_mut() {
1006                        if let Ok(r) = expr.replace_decls(decl_mapping, handler, ctx) {
1007                            has_changes |= r;
1008                        }
1009                    }
1010                    Ok(has_changes)
1011                }
1012                EnumTag { exp } => exp.replace_decls(decl_mapping, handler, ctx),
1013                UnsafeDowncast { exp, .. } => exp.replace_decls(decl_mapping, handler, ctx),
1014                AbiName(_) => Ok(false),
1015                WhileLoop {
1016                    ref mut condition,
1017                    ref mut body,
1018                } => {
1019                    let mut has_changes = false;
1020                    if let Ok(r) = condition.replace_decls(decl_mapping, handler, ctx) {
1021                        has_changes |= r;
1022                    }
1023                    if let Ok(r) = body.replace_decls(decl_mapping, handler, ctx) {
1024                        has_changes |= r;
1025                    }
1026                    Ok(has_changes)
1027                }
1028                ForLoop { ref mut desugared } => {
1029                    desugared.replace_decls(decl_mapping, handler, ctx)
1030                }
1031                Break => Ok(false),
1032                Continue => Ok(false),
1033                Reassignment(reassignment) => {
1034                    reassignment.replace_decls(decl_mapping, handler, ctx)
1035                }
1036                ImplicitReturn(expr) | Return(expr) => {
1037                    expr.replace_decls(decl_mapping, handler, ctx)
1038                }
1039                Ref(exp) | Deref(exp) => exp.replace_decls(decl_mapping, handler, ctx),
1040            }
1041        })
1042    }
1043}
1044
1045impl TypeCheckAnalysis for TyExpressionVariant {
1046    fn type_check_analyze(
1047        &self,
1048        handler: &Handler,
1049        ctx: &mut TypeCheckAnalysisContext,
1050    ) -> Result<(), ErrorEmitted> {
1051        match self {
1052            TyExpressionVariant::Literal(_) => {}
1053            TyExpressionVariant::FunctionApplication {
1054                fn_ref, arguments, ..
1055            } => {
1056                let fn_decl_id = ctx.get_normalized_fn_node_id(fn_ref.id());
1057
1058                let fn_node = ctx.get_node_for_fn_decl(&fn_decl_id);
1059                if let Some(fn_node) = fn_node {
1060                    ctx.add_edge_from_current(
1061                        fn_node,
1062                        TyNodeDepGraphEdge(TyNodeDepGraphEdgeInfo::FnApp),
1063                    );
1064
1065                    if !ctx.node_stack.contains(&fn_node) {
1066                        let _ = fn_decl_id.type_check_analyze(handler, ctx);
1067                    }
1068                }
1069
1070                // Unify arguments that are still not concrete
1071                let decl = ctx.engines.de().get(fn_ref.id());
1072
1073                use crate::type_system::unify::unifier::*;
1074                let unifier = Unifier::new(ctx.engines, "", UnifyKind::Default);
1075
1076                for (decl_param, arg) in decl.parameters.iter().zip(arguments.iter()) {
1077                    unifier.unify(
1078                        handler,
1079                        arg.1.return_type,
1080                        decl_param.type_argument.type_id,
1081                        &Span::dummy(),
1082                        false,
1083                    );
1084                }
1085            }
1086            TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
1087                lhs.type_check_analyze(handler, ctx)?;
1088                rhs.type_check_analyze(handler, ctx)?
1089            }
1090            TyExpressionVariant::ConstantExpression { decl, .. } => {
1091                decl.type_check_analyze(handler, ctx)?
1092            }
1093            TyExpressionVariant::ConfigurableExpression { decl, .. } => {
1094                decl.type_check_analyze(handler, ctx)?
1095            }
1096            TyExpressionVariant::ConstGenericExpression { decl, .. } => {
1097                decl.type_check_analyze(handler, ctx)?
1098            }
1099            TyExpressionVariant::VariableExpression { .. } => {}
1100            TyExpressionVariant::Tuple { fields } => {
1101                for field in fields.iter() {
1102                    field.type_check_analyze(handler, ctx)?
1103                }
1104            }
1105            TyExpressionVariant::ArrayExplicit { contents, .. } => {
1106                for elem in contents.iter() {
1107                    elem.type_check_analyze(handler, ctx)?
1108                }
1109            }
1110            TyExpressionVariant::ArrayRepeat { value, length, .. } => {
1111                value.type_check_analyze(handler, ctx)?;
1112                length.type_check_analyze(handler, ctx)?;
1113            }
1114            TyExpressionVariant::ArrayIndex { prefix, index } => {
1115                prefix.type_check_analyze(handler, ctx)?;
1116                index.type_check_analyze(handler, ctx)?;
1117            }
1118            TyExpressionVariant::StructExpression { fields: _, .. } => {}
1119            TyExpressionVariant::CodeBlock(block) => {
1120                block.type_check_analyze(handler, ctx)?;
1121            }
1122            TyExpressionVariant::FunctionParameter => {}
1123            TyExpressionVariant::MatchExp {
1124                desugared,
1125                scrutinees: _,
1126            } => {
1127                desugared.type_check_analyze(handler, ctx)?;
1128            }
1129            TyExpressionVariant::IfExp {
1130                condition,
1131                then,
1132                r#else,
1133            } => {
1134                condition.type_check_analyze(handler, ctx)?;
1135                then.type_check_analyze(handler, ctx)?;
1136                if let Some(r#else) = r#else {
1137                    r#else.type_check_analyze(handler, ctx)?;
1138                }
1139            }
1140            TyExpressionVariant::AsmExpression { .. } => {}
1141            TyExpressionVariant::StructFieldAccess { prefix, .. } => {
1142                prefix.type_check_analyze(handler, ctx)?;
1143            }
1144            TyExpressionVariant::TupleElemAccess { prefix, .. } => {
1145                prefix.type_check_analyze(handler, ctx)?;
1146            }
1147            TyExpressionVariant::EnumInstantiation { contents, .. } => {
1148                for expr in contents.iter() {
1149                    expr.type_check_analyze(handler, ctx)?
1150                }
1151            }
1152            TyExpressionVariant::AbiCast { address, .. } => {
1153                address.type_check_analyze(handler, ctx)?;
1154            }
1155            TyExpressionVariant::StorageAccess(_node) => {}
1156            TyExpressionVariant::IntrinsicFunction(node) => {
1157                for arg in node.arguments.iter() {
1158                    arg.type_check_analyze(handler, ctx)?
1159                }
1160            }
1161            TyExpressionVariant::AbiName(_node) => {}
1162            TyExpressionVariant::EnumTag { exp } => {
1163                exp.type_check_analyze(handler, ctx)?;
1164            }
1165            TyExpressionVariant::UnsafeDowncast { exp, .. } => {
1166                exp.type_check_analyze(handler, ctx)?;
1167            }
1168            TyExpressionVariant::WhileLoop { condition, body } => {
1169                condition.type_check_analyze(handler, ctx)?;
1170                body.type_check_analyze(handler, ctx)?;
1171            }
1172            TyExpressionVariant::ForLoop { desugared } => {
1173                desugared.type_check_analyze(handler, ctx)?;
1174            }
1175            TyExpressionVariant::Break => {}
1176            TyExpressionVariant::Continue => {}
1177            TyExpressionVariant::Reassignment(node) => {
1178                node.type_check_analyze(handler, ctx)?;
1179            }
1180            TyExpressionVariant::ImplicitReturn(node) | TyExpressionVariant::Return(node) => {
1181                node.type_check_analyze(handler, ctx)?;
1182            }
1183            TyExpressionVariant::Ref(exp) | TyExpressionVariant::Deref(exp) => {
1184                exp.type_check_analyze(handler, ctx)?;
1185            }
1186        }
1187        Ok(())
1188    }
1189}
1190
1191impl TypeCheckFinalization for TyExpressionVariant {
1192    fn type_check_finalize(
1193        &mut self,
1194        handler: &Handler,
1195        ctx: &mut TypeCheckFinalizationContext,
1196    ) -> Result<(), ErrorEmitted> {
1197        handler.scope(|handler| {
1198            match self {
1199                TyExpressionVariant::ConstGenericExpression { .. } => {
1200                    todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
1201                }
1202                TyExpressionVariant::Literal(_) => {}
1203                TyExpressionVariant::FunctionApplication { arguments, .. } => {
1204                    for (_, arg) in arguments.iter_mut() {
1205                        let _ = arg.type_check_finalize(handler, ctx);
1206                    }
1207                }
1208                TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
1209                    lhs.type_check_finalize(handler, ctx)?;
1210                    rhs.type_check_finalize(handler, ctx)?
1211                }
1212                TyExpressionVariant::ConstantExpression { decl, .. } => {
1213                    decl.type_check_finalize(handler, ctx)?
1214                }
1215                TyExpressionVariant::ConfigurableExpression { decl, .. } => {
1216                    decl.type_check_finalize(handler, ctx)?
1217                }
1218                TyExpressionVariant::VariableExpression { .. } => {}
1219                TyExpressionVariant::Tuple { fields } => {
1220                    for field in fields.iter_mut() {
1221                        field.type_check_finalize(handler, ctx)?
1222                    }
1223                }
1224                TyExpressionVariant::ArrayExplicit { contents, .. } => {
1225                    for elem in contents.iter_mut() {
1226                        elem.type_check_finalize(handler, ctx)?
1227                    }
1228                }
1229                TyExpressionVariant::ArrayRepeat { value, length, .. } => {
1230                    value.type_check_finalize(handler, ctx)?;
1231                    length.type_check_finalize(handler, ctx)?;
1232                }
1233                TyExpressionVariant::ArrayIndex { prefix, index } => {
1234                    prefix.type_check_finalize(handler, ctx)?;
1235                    index.type_check_finalize(handler, ctx)?;
1236                }
1237                TyExpressionVariant::StructExpression { fields, .. } => {
1238                    for field in fields.iter_mut() {
1239                        field.type_check_finalize(handler, ctx)?;
1240                    }
1241                }
1242                TyExpressionVariant::CodeBlock(block) => {
1243                    block.type_check_finalize(handler, ctx)?;
1244                }
1245                TyExpressionVariant::FunctionParameter => {}
1246                TyExpressionVariant::MatchExp {
1247                    desugared,
1248                    scrutinees,
1249                } => {
1250                    desugared.type_check_finalize(handler, ctx)?;
1251                    for scrutinee in scrutinees.iter_mut() {
1252                        scrutinee.type_check_finalize(handler, ctx)?
1253                    }
1254                }
1255                TyExpressionVariant::IfExp {
1256                    condition,
1257                    then,
1258                    r#else,
1259                } => {
1260                    condition.type_check_finalize(handler, ctx)?;
1261                    then.type_check_finalize(handler, ctx)?;
1262                    if let Some(ref mut r#else) = r#else {
1263                        r#else.type_check_finalize(handler, ctx)?;
1264                    }
1265                }
1266                TyExpressionVariant::AsmExpression { .. } => {}
1267                TyExpressionVariant::StructFieldAccess { prefix, .. } => {
1268                    prefix.type_check_finalize(handler, ctx)?;
1269                }
1270                TyExpressionVariant::TupleElemAccess { prefix, .. } => {
1271                    prefix.type_check_finalize(handler, ctx)?;
1272                }
1273                TyExpressionVariant::EnumInstantiation { contents, .. } => {
1274                    for expr in contents.iter_mut() {
1275                        expr.type_check_finalize(handler, ctx)?
1276                    }
1277                }
1278                TyExpressionVariant::AbiCast { address, .. } => {
1279                    address.type_check_finalize(handler, ctx)?;
1280                }
1281                TyExpressionVariant::StorageAccess(_) => {
1282                    todo!("")
1283                }
1284                TyExpressionVariant::IntrinsicFunction(kind) => {
1285                    for expr in kind.arguments.iter_mut() {
1286                        expr.type_check_finalize(handler, ctx)?;
1287                    }
1288                }
1289                TyExpressionVariant::AbiName(_) => {
1290                    todo!("")
1291                }
1292                TyExpressionVariant::EnumTag { exp } => {
1293                    exp.type_check_finalize(handler, ctx)?;
1294                }
1295                TyExpressionVariant::UnsafeDowncast { exp, .. } => {
1296                    exp.type_check_finalize(handler, ctx)?;
1297                }
1298                TyExpressionVariant::WhileLoop { condition, body } => {
1299                    condition.type_check_finalize(handler, ctx)?;
1300                    body.type_check_finalize(handler, ctx)?;
1301                }
1302                TyExpressionVariant::ForLoop { desugared } => {
1303                    desugared.type_check_finalize(handler, ctx)?;
1304                }
1305                TyExpressionVariant::Break => {}
1306                TyExpressionVariant::Continue => {}
1307                TyExpressionVariant::Reassignment(node) => {
1308                    node.type_check_finalize(handler, ctx)?;
1309                }
1310                TyExpressionVariant::ImplicitReturn(node) | TyExpressionVariant::Return(node) => {
1311                    node.type_check_finalize(handler, ctx)?;
1312                }
1313                TyExpressionVariant::Ref(exp) | TyExpressionVariant::Deref(exp) => {
1314                    exp.type_check_finalize(handler, ctx)?;
1315                }
1316            }
1317            Ok(())
1318        })
1319    }
1320}
1321
1322impl UpdateConstantExpression for TyExpressionVariant {
1323    fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
1324        use TyExpressionVariant::*;
1325        match self {
1326            Literal(..) => (),
1327            FunctionApplication { .. } => (),
1328            LazyOperator { lhs, rhs, .. } => {
1329                (*lhs).update_constant_expression(engines, implementing_type);
1330                (*rhs).update_constant_expression(engines, implementing_type);
1331            }
1332            ConstantExpression { ref mut decl, .. } => {
1333                if let Some(impl_const) =
1334                    find_const_decl_from_impl(implementing_type, engines.de(), decl)
1335                {
1336                    *decl = Box::new(impl_const);
1337                }
1338            }
1339            ConfigurableExpression { .. } => {
1340                unreachable!()
1341            }
1342            ConstGenericExpression { .. } => {}
1343            VariableExpression { .. } => (),
1344            Tuple { fields } => fields
1345                .iter_mut()
1346                .for_each(|x| x.update_constant_expression(engines, implementing_type)),
1347            ArrayExplicit {
1348                contents,
1349                elem_type: _,
1350            } => contents
1351                .iter_mut()
1352                .for_each(|x| x.update_constant_expression(engines, implementing_type)),
1353            ArrayRepeat {
1354                elem_type: _,
1355                value,
1356                length,
1357            } => {
1358                value.update_constant_expression(engines, implementing_type);
1359                length.update_constant_expression(engines, implementing_type);
1360            }
1361            ArrayIndex { prefix, index } => {
1362                (*prefix).update_constant_expression(engines, implementing_type);
1363                (*index).update_constant_expression(engines, implementing_type);
1364            }
1365            StructExpression { fields, .. } => fields.iter_mut().for_each(|x| {
1366                x.value
1367                    .update_constant_expression(engines, implementing_type)
1368            }),
1369            CodeBlock(block) => {
1370                block.update_constant_expression(engines, implementing_type);
1371            }
1372            FunctionParameter => (),
1373            MatchExp { desugared, .. } => {
1374                desugared.update_constant_expression(engines, implementing_type)
1375            }
1376            IfExp {
1377                condition,
1378                then,
1379                r#else,
1380            } => {
1381                condition.update_constant_expression(engines, implementing_type);
1382                then.update_constant_expression(engines, implementing_type);
1383                if let Some(ref mut r#else) = r#else {
1384                    r#else.update_constant_expression(engines, implementing_type);
1385                }
1386            }
1387            AsmExpression { .. } => {}
1388            StructFieldAccess { prefix, .. } => {
1389                prefix.update_constant_expression(engines, implementing_type);
1390            }
1391            TupleElemAccess { prefix, .. } => {
1392                prefix.update_constant_expression(engines, implementing_type);
1393            }
1394            EnumInstantiation {
1395                enum_ref: _,
1396                contents,
1397                ..
1398            } => {
1399                if let Some(ref mut contents) = contents {
1400                    contents.update_constant_expression(engines, implementing_type);
1401                };
1402            }
1403            AbiCast { address, .. } => {
1404                address.update_constant_expression(engines, implementing_type)
1405            }
1406            StorageAccess { .. } => (),
1407            IntrinsicFunction(_) => {}
1408            EnumTag { exp } => {
1409                exp.update_constant_expression(engines, implementing_type);
1410            }
1411            UnsafeDowncast { exp, .. } => {
1412                exp.update_constant_expression(engines, implementing_type);
1413            }
1414            AbiName(_) => (),
1415            WhileLoop {
1416                ref mut condition,
1417                ref mut body,
1418            } => {
1419                condition.update_constant_expression(engines, implementing_type);
1420                body.update_constant_expression(engines, implementing_type);
1421            }
1422            ForLoop { ref mut desugared } => {
1423                desugared.update_constant_expression(engines, implementing_type);
1424            }
1425            Break => (),
1426            Continue => (),
1427            Reassignment(reassignment) => {
1428                reassignment.update_constant_expression(engines, implementing_type)
1429            }
1430            ImplicitReturn(expr) | Return(expr) => {
1431                expr.update_constant_expression(engines, implementing_type)
1432            }
1433            Ref(exp) | Deref(exp) => exp.update_constant_expression(engines, implementing_type),
1434        }
1435    }
1436}
1437
1438fn find_const_decl_from_impl(
1439    implementing_type: &TyDecl,
1440    decl_engine: &DeclEngine,
1441    const_decl: &TyConstantDecl,
1442) -> Option<TyConstantDecl> {
1443    match implementing_type {
1444        TyDecl::ImplSelfOrTrait(ImplSelfOrTrait { decl_id, .. }) => {
1445            let impl_trait = decl_engine.get_impl_self_or_trait(&decl_id.clone());
1446            impl_trait
1447                .items
1448                .iter()
1449                .find(|item| match item {
1450                    TyTraitItem::Constant(decl_id) => {
1451                        let trait_const_decl =
1452                            (*decl_engine.get_constant(&decl_id.clone())).clone();
1453                        const_decl.name().eq(trait_const_decl.name())
1454                    }
1455                    _ => false,
1456                })
1457                .map(|item| match item {
1458                    TyTraitItem::Constant(decl_id) => (*decl_engine.get_constant(decl_id)).clone(),
1459                    _ => unreachable!(),
1460                })
1461        }
1462        TyDecl::AbiDecl(AbiDecl {
1463            decl_id: _decl_id, ..
1464        }) => todo!(""),
1465        _ => unreachable!(),
1466    }
1467}
1468
1469impl DisplayWithEngines for TyExpressionVariant {
1470    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
1471        // TODO: Implement user-friendly display strings if needed.
1472        DebugWithEngines::fmt(self, f, engines)
1473    }
1474}
1475
1476impl DebugWithEngines for TyExpressionVariant {
1477    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
1478        let s = match self {
1479            TyExpressionVariant::ConstGenericExpression { .. } => {
1480                todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
1481            }
1482            TyExpressionVariant::Literal(lit) => format!("literal {lit}"),
1483            TyExpressionVariant::FunctionApplication {
1484                call_path: name, ..
1485            } => {
1486                format!("\"{}\" fn entry", name.suffix.as_str())
1487            }
1488            TyExpressionVariant::LazyOperator { op, .. } => match op {
1489                LazyOp::And => "&&".into(),
1490                LazyOp::Or => "||".into(),
1491            },
1492            TyExpressionVariant::Tuple { fields } => {
1493                let fields = fields
1494                    .iter()
1495                    .map(|field| format!("{:?}", engines.help_out(field)))
1496                    .collect::<Vec<_>>()
1497                    .join(", ");
1498                format!("tuple({fields})")
1499            }
1500            TyExpressionVariant::ArrayExplicit { .. } | TyExpressionVariant::ArrayRepeat { .. } => {
1501                "array".into()
1502            }
1503            TyExpressionVariant::ArrayIndex { .. } => "[..]".into(),
1504            TyExpressionVariant::StructExpression { struct_id, .. } => {
1505                let decl = engines.de().get(struct_id);
1506                format!("\"{}\" struct init", decl.name().as_str())
1507            }
1508            TyExpressionVariant::CodeBlock(_) => "code block entry".into(),
1509            TyExpressionVariant::FunctionParameter => "fn param access".into(),
1510            TyExpressionVariant::MatchExp { .. } | TyExpressionVariant::IfExp { .. } => {
1511                "if exp".into()
1512            }
1513            TyExpressionVariant::AsmExpression { .. } => "inline asm".into(),
1514            TyExpressionVariant::AbiCast { abi_name, .. } => {
1515                format!("abi cast {}", abi_name.suffix.as_str())
1516            }
1517            TyExpressionVariant::StructFieldAccess {
1518                resolved_type_of_parent,
1519                field_to_access,
1520                ..
1521            } => {
1522                format!(
1523                    "\"{:?}.{}\" struct field access",
1524                    engines.help_out(*resolved_type_of_parent),
1525                    field_to_access.name
1526                )
1527            }
1528            TyExpressionVariant::TupleElemAccess {
1529                resolved_type_of_parent,
1530                elem_to_access_num,
1531                ..
1532            } => {
1533                format!(
1534                    "\"{:?}.{}\" tuple index",
1535                    engines.help_out(*resolved_type_of_parent),
1536                    elem_to_access_num
1537                )
1538            }
1539            TyExpressionVariant::ConstantExpression { decl, .. } => {
1540                format!("\"{}\" constant exp", decl.name().as_str())
1541            }
1542            TyExpressionVariant::ConfigurableExpression { decl, .. } => {
1543                format!("\"{}\" configurable exp", decl.name().as_str())
1544            }
1545            TyExpressionVariant::VariableExpression { name, .. } => {
1546                format!("\"{}\" variable exp", name.as_str())
1547            }
1548            TyExpressionVariant::EnumInstantiation {
1549                tag,
1550                enum_ref,
1551                variant_name,
1552                ..
1553            } => {
1554                format!(
1555                    "{}::{} enum instantiation (tag: {})",
1556                    enum_ref.name().as_str(),
1557                    variant_name.as_str(),
1558                    tag
1559                )
1560            }
1561            TyExpressionVariant::StorageAccess(access) => {
1562                format!("storage field {} access", access.storage_field_name())
1563            }
1564            TyExpressionVariant::IntrinsicFunction(kind) => format!("{:?}", engines.help_out(kind)),
1565            TyExpressionVariant::AbiName(n) => format!("ABI name {n}"),
1566            TyExpressionVariant::EnumTag { exp } => {
1567                format!("({:?} as tag)", engines.help_out(exp.return_type))
1568            }
1569            TyExpressionVariant::UnsafeDowncast {
1570                exp,
1571                variant,
1572                call_path_decl,
1573            } => {
1574                format!(
1575                    "({:?} as {}::{})",
1576                    engines.help_out(exp.return_type),
1577                    engines.help_out(call_path_decl),
1578                    variant.name
1579                )
1580            }
1581            TyExpressionVariant::WhileLoop { condition, .. } => {
1582                format!("while loop on {:?}", engines.help_out(&**condition))
1583            }
1584            TyExpressionVariant::ForLoop { .. } => "for loop".to_string(),
1585            TyExpressionVariant::Break => "break".to_string(),
1586            TyExpressionVariant::Continue => "continue".to_string(),
1587            TyExpressionVariant::Reassignment(reassignment) => {
1588                let target = match &reassignment.lhs {
1589                    TyReassignmentTarget::Deref(exp) => format!("{:?}", engines.help_out(exp)),
1590                    TyReassignmentTarget::ElementAccess {
1591                        base_name,
1592                        base_type: _,
1593                        indices,
1594                    } => {
1595                        let mut target = base_name.to_string();
1596                        for index in indices {
1597                            match index {
1598                                ProjectionKind::StructField { name } => {
1599                                    target.push('.');
1600                                    target.push_str(name.as_str());
1601                                }
1602                                ProjectionKind::TupleField { index, .. } => {
1603                                    target.push('.');
1604                                    target.push_str(index.to_string().as_str());
1605                                }
1606                                ProjectionKind::ArrayIndex { index, .. } => {
1607                                    write!(&mut target, "[{:?}]", engines.help_out(index)).unwrap();
1608                                }
1609                            }
1610                        }
1611                        target
1612                    }
1613                };
1614
1615                format!(
1616                    "reassignment to {target} = {:?}",
1617                    engines.help_out(&reassignment.rhs)
1618                )
1619            }
1620            TyExpressionVariant::ImplicitReturn(exp) => {
1621                format!("implicit return {:?}", engines.help_out(&**exp))
1622            }
1623            TyExpressionVariant::Return(exp) => {
1624                format!("return {:?}", engines.help_out(&**exp))
1625            }
1626            TyExpressionVariant::Ref(exp) => {
1627                format!("&({:?})", engines.help_out(&**exp))
1628            }
1629            TyExpressionVariant::Deref(exp) => {
1630                format!("*({:?})", engines.help_out(&**exp))
1631            }
1632        };
1633        write!(f, "{s}")
1634    }
1635}
1636
1637impl TyExpressionVariant {
1638    /// Returns `self` as a literal, if possible.
1639    pub(crate) fn extract_literal_value(&self) -> Option<Literal> {
1640        match self {
1641            TyExpressionVariant::Literal(value) => Some(value.clone()),
1642            _ => None,
1643        }
1644    }
1645}