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