sway_core/language/ty/expression/
expression.rs

1use crate::{
2    decl_engine::*,
3    engine_threading::*,
4    has_changes,
5    language::{ty::*, Literal},
6    semantic_analysis::{
7        TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization,
8        TypeCheckFinalizationContext,
9    },
10    transform::{AllowDeprecatedState, Attributes},
11    type_system::*,
12    types::*,
13};
14use serde::{Deserialize, Serialize};
15use std::{fmt, hash::Hasher};
16use sway_error::{
17    error::CompileError,
18    handler::{ErrorEmitted, Handler},
19    type_error::TypeError,
20    warning::{CompileWarning, DeprecatedElement, Warning},
21};
22use sway_types::{Span, Spanned};
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct TyExpression {
26    pub expression: TyExpressionVariant,
27    pub return_type: TypeId,
28    pub span: Span,
29}
30
31impl EqWithEngines for TyExpression {}
32impl PartialEqWithEngines for TyExpression {
33    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
34        let type_engine = ctx.engines().te();
35        self.expression.eq(&other.expression, ctx)
36            && type_engine
37                .get(self.return_type)
38                .eq(&type_engine.get(other.return_type), ctx)
39    }
40}
41
42impl HashWithEngines for TyExpression {
43    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
44        let TyExpression {
45            expression,
46            return_type,
47            // these fields are not hashed because they aren't relevant/a
48            // reliable source of obj v. obj distinction
49            span: _,
50        } = self;
51        let type_engine = engines.te();
52        expression.hash(state, engines);
53        type_engine.get(*return_type).hash(state, engines);
54    }
55}
56
57impl SubstTypes for TyExpression {
58    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
59        has_changes! {
60            self.return_type.subst(ctx);
61            self.expression.subst(ctx);
62        }
63    }
64}
65
66impl ReplaceDecls for TyExpression {
67    fn replace_decls_inner(
68        &mut self,
69        decl_mapping: &DeclMapping,
70        handler: &Handler,
71        ctx: &mut TypeCheckContext,
72    ) -> Result<bool, ErrorEmitted> {
73        self.expression.replace_decls(decl_mapping, handler, ctx)
74    }
75}
76
77impl UpdateConstantExpression for TyExpression {
78    fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
79        self.expression
80            .update_constant_expression(engines, implementing_type)
81    }
82}
83
84impl DisplayWithEngines for TyExpression {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
86        write!(
87            f,
88            "{} ({})",
89            engines.help_out(&self.expression),
90            engines.help_out(self.return_type)
91        )
92    }
93}
94
95impl DebugWithEngines for TyExpression {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
97        write!(
98            f,
99            "{:?} ({:?})",
100            engines.help_out(&self.expression),
101            engines.help_out(self.return_type)
102        )
103    }
104}
105
106impl TypeCheckAnalysis for TyExpression {
107    fn type_check_analyze(
108        &self,
109        handler: &Handler,
110        ctx: &mut TypeCheckAnalysisContext,
111    ) -> Result<(), ErrorEmitted> {
112        match &self.expression {
113            // Check literal "fits" into assigned typed.
114            TyExpressionVariant::Literal(Literal::Numeric(literal_value)) => {
115                let t = ctx.engines.te().get(self.return_type);
116                if let TypeInfo::UnsignedInteger(bits) = &*t {
117                    if bits.would_overflow(*literal_value) {
118                        handler.emit_err(CompileError::TypeError(TypeError::LiteralOverflow {
119                            expected: format!("{:?}", ctx.engines.help_out(t)),
120                            span: self.span.clone(),
121                        }));
122                    }
123                }
124            }
125            TyExpressionVariant::ArrayExplicit { .. } => {
126                self.as_array_unify_elements(handler, ctx.engines);
127            }
128            _ => {}
129        }
130        self.expression.type_check_analyze(handler, ctx)
131    }
132}
133
134impl TypeCheckFinalization for TyExpression {
135    fn type_check_finalize(
136        &mut self,
137        handler: &Handler,
138        ctx: &mut TypeCheckFinalizationContext,
139    ) -> Result<(), ErrorEmitted> {
140        let res = self.expression.type_check_finalize(handler, ctx);
141        if let TyExpressionVariant::FunctionApplication { fn_ref, .. } = &self.expression {
142            let method = ctx.engines.de().get_function(fn_ref);
143            self.return_type = method.return_type.type_id();
144        }
145        res
146    }
147}
148
149impl CollectTypesMetadata for TyExpression {
150    fn collect_types_metadata(
151        &self,
152        handler: &Handler,
153        ctx: &mut CollectTypesMetadataContext,
154    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
155        use TyExpressionVariant::*;
156        let decl_engine = ctx.engines.de();
157        let mut res = self.return_type.collect_types_metadata(handler, ctx)?;
158        match &self.expression {
159            FunctionApplication {
160                arguments,
161                fn_ref,
162                call_path,
163                type_binding,
164                ..
165            } => {
166                for arg in arguments.iter() {
167                    res.append(&mut arg.1.collect_types_metadata(handler, ctx)?);
168                }
169                let function_decl = decl_engine.get_function(fn_ref);
170
171                ctx.call_site_push();
172                for (idx, p) in function_decl
173                    .type_parameters
174                    .iter()
175                    .filter_map(|x| x.as_type_parameter())
176                    .enumerate()
177                {
178                    ctx.call_site_insert(p.type_id, call_path.span());
179
180                    // Verify type arguments are concrete
181                    res.extend(
182                        p.type_id
183                            .collect_types_metadata(handler, ctx)?
184                            .into_iter()
185                            // try to use the caller span for better error messages
186                            .map(|x| match x {
187                                TypeMetadata::UnresolvedType(ident, original_span) => {
188                                    let span = type_binding
189                                        .as_ref()
190                                        .and_then(|type_binding| {
191                                            type_binding.type_arguments.as_slice().get(idx)
192                                        })
193                                        .map(|type_argument| Some(type_argument.span()))
194                                        .unwrap_or(original_span);
195                                    TypeMetadata::UnresolvedType(ident, span)
196                                }
197                                x => x,
198                            }),
199                    );
200                }
201
202                for content in function_decl.body.contents.iter() {
203                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
204                }
205                ctx.call_site_pop();
206            }
207            Tuple { fields } => {
208                for field in fields.iter() {
209                    res.append(&mut field.collect_types_metadata(handler, ctx)?);
210                }
211            }
212            AsmExpression { registers, .. } => {
213                for register in registers.iter() {
214                    if let Some(init) = register.initializer.as_ref() {
215                        res.append(&mut init.collect_types_metadata(handler, ctx)?);
216                    }
217                }
218            }
219            StructExpression {
220                fields,
221                instantiation_span,
222                struct_id,
223                ..
224            } => {
225                let struct_decl = decl_engine.get_struct(struct_id);
226                for p in &struct_decl.type_parameters {
227                    let p = p
228                        .as_type_parameter()
229                        .expect("only works for type parameters");
230                    ctx.call_site_insert(p.type_id, instantiation_span.clone());
231                }
232                if let TypeInfo::Struct(decl_ref) = &*ctx.engines.te().get(self.return_type) {
233                    let decl = decl_engine.get_struct(decl_ref);
234                    for p in &decl.type_parameters {
235                        let p = p
236                            .as_type_parameter()
237                            .expect("only works for type parameters");
238                        ctx.call_site_insert(p.type_id, instantiation_span.clone());
239                    }
240                }
241                for field in fields.iter() {
242                    res.append(&mut field.value.collect_types_metadata(handler, ctx)?);
243                }
244            }
245            LazyOperator { lhs, rhs, .. } => {
246                res.append(&mut lhs.collect_types_metadata(handler, ctx)?);
247                res.append(&mut rhs.collect_types_metadata(handler, ctx)?);
248            }
249            ArrayExplicit {
250                elem_type: _,
251                contents,
252            } => {
253                for content in contents.iter() {
254                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
255                }
256            }
257            ArrayRepeat {
258                elem_type: _,
259                value,
260                length,
261            } => {
262                res.append(&mut value.collect_types_metadata(handler, ctx)?);
263                res.append(&mut length.collect_types_metadata(handler, ctx)?);
264            }
265            ArrayIndex { prefix, index } => {
266                res.append(&mut (**prefix).collect_types_metadata(handler, ctx)?);
267                res.append(&mut (**index).collect_types_metadata(handler, ctx)?);
268            }
269            CodeBlock(block) => {
270                for content in block.contents.iter() {
271                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
272                }
273            }
274            MatchExp { desugared, .. } => {
275                res.append(&mut desugared.collect_types_metadata(handler, ctx)?)
276            }
277            IfExp {
278                condition,
279                then,
280                r#else,
281            } => {
282                res.append(&mut condition.collect_types_metadata(handler, ctx)?);
283                res.append(&mut then.collect_types_metadata(handler, ctx)?);
284                if let Some(r#else) = r#else {
285                    res.append(&mut r#else.collect_types_metadata(handler, ctx)?);
286                }
287            }
288            StructFieldAccess {
289                prefix,
290                resolved_type_of_parent,
291                ..
292            } => {
293                res.append(&mut prefix.collect_types_metadata(handler, ctx)?);
294                res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?);
295            }
296            TupleElemAccess {
297                prefix,
298                resolved_type_of_parent,
299                ..
300            } => {
301                res.append(&mut prefix.collect_types_metadata(handler, ctx)?);
302                res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?);
303            }
304            EnumInstantiation {
305                enum_ref,
306                contents,
307                call_path_binding,
308                ..
309            } => {
310                let enum_decl = decl_engine.get_enum(enum_ref);
311                for p in enum_decl.type_parameters.iter() {
312                    let p = p
313                        .as_type_parameter()
314                        .expect("only works for type parameters");
315                    ctx.call_site_insert(p.type_id, call_path_binding.inner.suffix.span())
316                }
317                if let Some(contents) = contents {
318                    res.append(&mut contents.collect_types_metadata(handler, ctx)?);
319                }
320                for variant in enum_decl.variants.iter() {
321                    res.append(
322                        &mut variant
323                            .type_argument
324                            .type_id()
325                            .collect_types_metadata(handler, ctx)?,
326                    );
327                }
328                for p in enum_decl.type_parameters.iter() {
329                    let p = p
330                        .as_type_parameter()
331                        .expect("only works for type parameters");
332                    res.append(&mut p.type_id.collect_types_metadata(handler, ctx)?);
333                }
334            }
335            AbiCast { address, .. } => {
336                res.append(&mut address.collect_types_metadata(handler, ctx)?);
337            }
338            IntrinsicFunction(kind) => {
339                res.append(&mut kind.collect_types_metadata(handler, ctx)?);
340            }
341            EnumTag { exp } => {
342                res.append(&mut exp.collect_types_metadata(handler, ctx)?);
343            }
344            UnsafeDowncast {
345                exp,
346                variant,
347                call_path_decl: _,
348            } => {
349                res.append(&mut exp.collect_types_metadata(handler, ctx)?);
350                res.append(
351                    &mut variant
352                        .type_argument
353                        .type_id()
354                        .collect_types_metadata(handler, ctx)?,
355                );
356            }
357            WhileLoop { condition, body } => {
358                res.append(&mut condition.collect_types_metadata(handler, ctx)?);
359                for content in body.contents.iter() {
360                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
361                }
362            }
363            ForLoop { desugared } => {
364                res.append(&mut desugared.collect_types_metadata(handler, ctx)?);
365            }
366            ImplicitReturn(exp) | Return(exp) => {
367                res.append(&mut exp.collect_types_metadata(handler, ctx)?)
368            }
369            Ref(exp) | Deref(exp) => res.append(&mut exp.collect_types_metadata(handler, ctx)?),
370            // storage access can never be generic
371            // variable expressions don't ever have return types themselves, they're stored in
372            // `TyExpression::return_type`. Variable expressions are just names of variables.
373            VariableExpression { .. }
374            | ConstantExpression { .. }
375            | ConfigurableExpression { .. }
376            | ConstGenericExpression { .. }
377            | StorageAccess { .. }
378            | Literal(_)
379            | AbiName(_)
380            | Break
381            | Continue
382            | FunctionParameter => {}
383            Reassignment(reassignment) => {
384                res.append(&mut reassignment.rhs.collect_types_metadata(handler, ctx)?);
385            }
386        }
387        Ok(res)
388    }
389}
390
391impl MaterializeConstGenerics for TyExpression {
392    fn materialize_const_generics(
393        &mut self,
394        engines: &Engines,
395        handler: &Handler,
396        name: &str,
397        value: &TyExpression,
398    ) -> Result<(), ErrorEmitted> {
399        self.return_type
400            .materialize_const_generics(engines, handler, name, value)?;
401        match &mut self.expression {
402            TyExpressionVariant::CodeBlock(block) => {
403                for node in block.contents.iter_mut() {
404                    node.materialize_const_generics(engines, handler, name, value)?;
405                }
406                Ok(())
407            }
408            TyExpressionVariant::ConstGenericExpression { decl, .. } => {
409                decl.materialize_const_generics(engines, handler, name, value)
410            }
411            TyExpressionVariant::ImplicitReturn(expr) => {
412                expr.materialize_const_generics(engines, handler, name, value)
413            }
414            TyExpressionVariant::FunctionApplication { arguments, .. } => {
415                for (_, expr) in arguments {
416                    expr.materialize_const_generics(engines, handler, name, value)?;
417                }
418                Ok(())
419            }
420            TyExpressionVariant::IntrinsicFunction(TyIntrinsicFunctionKind {
421                arguments, ..
422            }) => {
423                for expr in arguments {
424                    expr.materialize_const_generics(engines, handler, name, value)?;
425                }
426                Ok(())
427            }
428            TyExpressionVariant::Return(expr) => {
429                expr.materialize_const_generics(engines, handler, name, value)
430            }
431            TyExpressionVariant::IfExp {
432                condition,
433                then,
434                r#else,
435            } => {
436                condition.materialize_const_generics(engines, handler, name, value)?;
437                then.materialize_const_generics(engines, handler, name, value)?;
438                if let Some(e) = r#else.as_mut() {
439                    e.materialize_const_generics(engines, handler, name, value)?;
440                }
441                Ok(())
442            }
443            TyExpressionVariant::WhileLoop { condition, body } => {
444                condition.materialize_const_generics(engines, handler, name, value)?;
445                body.materialize_const_generics(engines, handler, name, value)
446            }
447            TyExpressionVariant::Reassignment(expr) => expr
448                .rhs
449                .materialize_const_generics(engines, handler, name, value),
450            TyExpressionVariant::ArrayIndex { prefix, index } => {
451                prefix.materialize_const_generics(engines, handler, name, value)?;
452                index.materialize_const_generics(engines, handler, name, value)
453            }
454            TyExpressionVariant::Literal(_) | TyExpressionVariant::VariableExpression { .. } => {
455                Ok(())
456            }
457            TyExpressionVariant::ArrayRepeat {
458                elem_type,
459                value: elem_value,
460                length,
461            } => {
462                elem_type.materialize_const_generics(engines, handler, name, value)?;
463                elem_value.materialize_const_generics(engines, handler, name, value)?;
464                length.materialize_const_generics(engines, handler, name, value)
465            }
466            TyExpressionVariant::Ref(r) => {
467                r.materialize_const_generics(engines, handler, name, value)
468            }
469            TyExpressionVariant::Deref(r) => {
470                r.materialize_const_generics(engines, handler, name, value)
471            }
472            _ => Err(handler.emit_err(
473                sway_error::error::CompileError::ConstGenericNotSupportedHere {
474                    span: self.span.clone(),
475                },
476            )),
477        }
478    }
479}
480
481impl TyExpression {
482    pub(crate) fn error(err: ErrorEmitted, span: Span, engines: &Engines) -> TyExpression {
483        let type_engine = engines.te();
484        TyExpression {
485            expression: TyExpressionVariant::Tuple { fields: vec![] },
486            return_type: type_engine.id_of_error_recovery(err),
487            span,
488        }
489    }
490
491    /// gathers the mutability of the expressions within
492    pub(crate) fn gather_mutability(&self) -> VariableMutability {
493        match &self.expression {
494            TyExpressionVariant::VariableExpression { mutability, .. } => *mutability,
495            _ => VariableMutability::Immutable,
496        }
497    }
498
499    /// Returns `self` as a literal, if possible.
500    pub(crate) fn extract_literal_value(&self) -> Option<Literal> {
501        self.expression.extract_literal_value()
502    }
503
504    // Checks if this expression references a deprecated item
505    // TODO: Extend checks in this function to fully implement deprecation.
506    //       See: https://github.com/FuelLabs/sway/issues/6942
507    pub(crate) fn check_deprecated(
508        &self,
509        engines: &Engines,
510        handler: &Handler,
511        allow_deprecated: &mut AllowDeprecatedState,
512    ) {
513        fn emit_warning_if_deprecated(
514            attributes: &Attributes,
515            span: &Span,
516            handler: &Handler,
517            deprecated_element: DeprecatedElement,
518            deprecated_element_name: &str,
519            allow_deprecated: &mut AllowDeprecatedState,
520        ) {
521            if allow_deprecated.is_allowed() {
522                return;
523            }
524
525            let Some(deprecated_attr) = attributes.deprecated() else {
526                return;
527            };
528
529            let help = deprecated_attr
530                .args
531                .iter()
532                // Last "note" argument wins ;-)
533                .rfind(|arg| arg.is_deprecated_note())
534                .and_then(|note_arg| match note_arg.get_string_opt(handler) {
535                    Ok(note) => note.cloned(),
536                    // We treat invalid values here as not having the "note" provided.
537                    // Attribute checking will emit errors.
538                    Err(_) => None,
539                });
540
541            handler.emit_warn(CompileWarning {
542                span: span.clone(),
543                warning_content: Warning::UsingDeprecated {
544                    deprecated_element,
545                    deprecated_element_name: deprecated_element_name.to_string(),
546                    help,
547                },
548            })
549        }
550
551        match &self.expression {
552            TyExpressionVariant::Literal(..) => {}
553            TyExpressionVariant::FunctionApplication {
554                call_path,
555                fn_ref,
556                arguments,
557                ..
558            } => {
559                for (_, expr) in arguments {
560                    expr.check_deprecated(engines, handler, allow_deprecated);
561                }
562
563                let fn_ty = engines.de().get(fn_ref);
564                if let Some(TyDecl::ImplSelfOrTrait(t)) = &fn_ty.implementing_type {
565                    let t = &engines.de().get(&t.decl_id).implementing_for;
566                    if let TypeInfo::Struct(struct_id) = &*engines.te().get(t.type_id()) {
567                        let s = engines.de().get(struct_id);
568                        emit_warning_if_deprecated(
569                            &s.attributes,
570                            &call_path.span(),
571                            handler,
572                            DeprecatedElement::Struct,
573                            s.call_path.suffix.as_str(),
574                            allow_deprecated,
575                        );
576                    }
577                }
578
579                emit_warning_if_deprecated(
580                    &fn_ty.attributes,
581                    &call_path.span(),
582                    handler,
583                    DeprecatedElement::Function,
584                    fn_ty.call_path.suffix.as_str(),
585                    allow_deprecated,
586                );
587            }
588            TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
589                lhs.check_deprecated(engines, handler, allow_deprecated);
590                rhs.check_deprecated(engines, handler, allow_deprecated);
591            }
592            TyExpressionVariant::ConstantExpression { span, decl, .. } => {
593                emit_warning_if_deprecated(
594                    &decl.attributes,
595                    span,
596                    handler,
597                    DeprecatedElement::Const,
598                    decl.call_path.suffix.as_str(),
599                    allow_deprecated,
600                );
601            }
602            TyExpressionVariant::ConfigurableExpression { span, decl, .. } => {
603                emit_warning_if_deprecated(
604                    &decl.attributes,
605                    span,
606                    handler,
607                    DeprecatedElement::Configurable,
608                    decl.call_path.suffix.as_str(),
609                    allow_deprecated,
610                );
611            }
612            // Const generics don“t have attributes, so deprecation warnings cannot be turned off.
613            TyExpressionVariant::ConstGenericExpression { .. } => {}
614            TyExpressionVariant::VariableExpression { .. } => {}
615            TyExpressionVariant::Tuple { fields } => {
616                for e in fields {
617                    e.check_deprecated(engines, handler, allow_deprecated);
618                }
619            }
620            TyExpressionVariant::ArrayExplicit { contents, .. } => {
621                for e in contents {
622                    e.check_deprecated(engines, handler, allow_deprecated);
623                }
624            }
625            TyExpressionVariant::ArrayRepeat { value, length, .. } => {
626                value.check_deprecated(engines, handler, allow_deprecated);
627                length.check_deprecated(engines, handler, allow_deprecated);
628            }
629            TyExpressionVariant::ArrayIndex { prefix, index } => {
630                prefix.check_deprecated(engines, handler, allow_deprecated);
631                index.check_deprecated(engines, handler, allow_deprecated);
632            }
633            TyExpressionVariant::StructExpression {
634                struct_id,
635                instantiation_span,
636                ..
637            } => {
638                let struct_decl = engines.de().get(struct_id);
639                emit_warning_if_deprecated(
640                    &struct_decl.attributes,
641                    instantiation_span,
642                    handler,
643                    DeprecatedElement::Struct,
644                    struct_decl.call_path.suffix.as_str(),
645                    allow_deprecated,
646                );
647            }
648            TyExpressionVariant::CodeBlock(block) => {
649                block.check_deprecated(engines, handler, allow_deprecated);
650            }
651            TyExpressionVariant::FunctionParameter => {}
652            TyExpressionVariant::MatchExp {
653                desugared,
654                // TODO: Check the scrutinees.
655                //       See: https://github.com/FuelLabs/sway/issues/6942
656                ..
657            } => {
658                desugared.check_deprecated(engines, handler, allow_deprecated);
659            }
660            TyExpressionVariant::IfExp {
661                condition,
662                then,
663                r#else,
664            } => {
665                condition.check_deprecated(engines, handler, allow_deprecated);
666                then.check_deprecated(engines, handler, allow_deprecated);
667                if let Some(e) = r#else {
668                    e.check_deprecated(engines, handler, allow_deprecated);
669                }
670            }
671            TyExpressionVariant::AsmExpression { .. } => {}
672            TyExpressionVariant::StructFieldAccess {
673                prefix,
674                field_to_access,
675                field_instantiation_span,
676                ..
677            } => {
678                prefix.check_deprecated(engines, handler, allow_deprecated);
679                emit_warning_if_deprecated(
680                    &field_to_access.attributes,
681                    field_instantiation_span,
682                    handler,
683                    DeprecatedElement::StructField,
684                    field_to_access.name.as_str(),
685                    allow_deprecated,
686                );
687            }
688            TyExpressionVariant::TupleElemAccess { prefix, .. } => {
689                prefix.check_deprecated(engines, handler, allow_deprecated);
690            }
691            TyExpressionVariant::EnumInstantiation {
692                enum_ref,
693                tag,
694                contents,
695                variant_instantiation_span,
696                call_path_binding,
697                ..
698            } => {
699                let enum_ty = engines.de().get(enum_ref);
700                emit_warning_if_deprecated(
701                    &enum_ty.attributes,
702                    // variant_instantiation_span,
703                    &call_path_binding.span,
704                    handler,
705                    DeprecatedElement::Enum,
706                    enum_ty.call_path.suffix.as_str(),
707                    allow_deprecated,
708                );
709                if let Some(variant_decl) = enum_ty.variants.get(*tag) {
710                    emit_warning_if_deprecated(
711                        &variant_decl.attributes,
712                        variant_instantiation_span,
713                        handler,
714                        DeprecatedElement::EnumVariant,
715                        variant_decl.name.as_str(),
716                        allow_deprecated,
717                    );
718                }
719                if let Some(expr) = contents {
720                    expr.check_deprecated(engines, handler, allow_deprecated);
721                }
722            }
723            TyExpressionVariant::AbiCast { address, .. } => {
724                // TODO: Check the abi name.
725                //       See: https://github.com/FuelLabs/sway/issues/6942
726                address.check_deprecated(engines, handler, allow_deprecated);
727            }
728            TyExpressionVariant::StorageAccess(access) => {
729                // TODO: Check the storage access.
730                //       See: https://github.com/FuelLabs/sway/issues/6942
731                if let Some(expr) = &access.key_expression {
732                    expr.check_deprecated(engines, handler, allow_deprecated);
733                }
734            }
735            TyExpressionVariant::IntrinsicFunction(kind) => {
736                for arg in kind.arguments.iter() {
737                    arg.check_deprecated(engines, handler, allow_deprecated);
738                }
739            }
740            TyExpressionVariant::AbiName(..) => {}
741            TyExpressionVariant::EnumTag { exp } => {
742                exp.check_deprecated(engines, handler, allow_deprecated);
743            }
744            TyExpressionVariant::UnsafeDowncast {
745                exp,
746                // TODO: Check the variant.
747                //       See: https://github.com/FuelLabs/sway/issues/6942
748                ..
749            } => {
750                exp.check_deprecated(engines, handler, allow_deprecated);
751            }
752            TyExpressionVariant::WhileLoop { condition, body } => {
753                condition.check_deprecated(engines, handler, allow_deprecated);
754                body.check_deprecated(engines, handler, allow_deprecated);
755            }
756            TyExpressionVariant::ForLoop { desugared } => {
757                desugared.check_deprecated(engines, handler, allow_deprecated);
758            }
759            TyExpressionVariant::Break => {}
760            TyExpressionVariant::Continue => {}
761            TyExpressionVariant::Reassignment(reass) => {
762                if let TyReassignmentTarget::DerefAccess { exp, indices } = &reass.lhs {
763                    exp.check_deprecated(engines, handler, allow_deprecated);
764                    for indice in indices {
765                        match indice {
766                            ProjectionKind::StructField {
767                                name: idx_name,
768                                field_to_access,
769                            } => {
770                                if let Some(field_to_access) = field_to_access {
771                                    emit_warning_if_deprecated(
772                                        &field_to_access.attributes,
773                                        &idx_name.span(),
774                                        handler,
775                                        DeprecatedElement::StructField,
776                                        idx_name.as_str(),
777                                        allow_deprecated,
778                                    );
779                                }
780                            }
781                            ProjectionKind::TupleField {
782                                index: _,
783                                index_span: _,
784                            } => {}
785                            ProjectionKind::ArrayIndex {
786                                index,
787                                index_span: _,
788                            } => index.check_deprecated(engines, handler, allow_deprecated),
789                        }
790                    }
791                }
792                // TODO: Check `TyReassignmentTarget::ElementAccess`.
793                //       See: https://github.com/FuelLabs/sway/issues/6942
794                reass
795                    .rhs
796                    .check_deprecated(engines, handler, allow_deprecated);
797            }
798            TyExpressionVariant::ImplicitReturn(expr) => {
799                expr.check_deprecated(engines, handler, allow_deprecated);
800            }
801            TyExpressionVariant::Return(expr) => {
802                expr.check_deprecated(engines, handler, allow_deprecated);
803            }
804            TyExpressionVariant::Ref(expr) => {
805                expr.check_deprecated(engines, handler, allow_deprecated);
806            }
807            TyExpressionVariant::Deref(expr) => {
808                expr.check_deprecated(engines, handler, allow_deprecated);
809            }
810        }
811    }
812
813    pub fn as_array(&self) -> Option<(&TypeId, &[TyExpression])> {
814        match &self.expression {
815            TyExpressionVariant::ArrayExplicit {
816                elem_type,
817                contents,
818            } => Some((elem_type, contents)),
819            _ => None,
820        }
821    }
822
823    pub fn as_intrinsic(&self) -> Option<&TyIntrinsicFunctionKind> {
824        match &self.expression {
825            TyExpressionVariant::IntrinsicFunction(v) => Some(v),
826            _ => None,
827        }
828    }
829
830    /// Unify elem_type with each element return type.
831    /// Must be called on arrays.
832    pub fn as_array_unify_elements(&self, handler: &Handler, engines: &Engines) {
833        let TyExpressionVariant::ArrayExplicit {
834            elem_type,
835            contents,
836        } = &self.expression
837        else {
838            unreachable!("Should only be called on Arrays")
839        };
840
841        let array_elem_type = engines.te().get(*elem_type);
842        if !matches!(&*array_elem_type, TypeInfo::Never) {
843            let unify = crate::type_system::unify::unifier::Unifier::new(
844                engines,
845                "",
846                unify::unifier::UnifyKind::Default,
847            );
848            for element in contents {
849                let element_type = engines.te().get(element.return_type);
850
851                // If the element is never, we do not need to check
852                if matches!(&*element_type, TypeInfo::Never) {
853                    continue;
854                }
855
856                let h = Handler::default();
857                unify.unify(&h, element.return_type, *elem_type, &element.span, true);
858
859                // unification error points to type that failed
860                // we want to report the element type instead
861                if h.has_errors() {
862                    handler.emit_err(CompileError::TypeError(TypeError::MismatchedType {
863                        expected: format!("{:?}", engines.help_out(&array_elem_type)),
864                        received: format!("{:?}", engines.help_out(element_type)),
865                        help_text: String::new(),
866                        span: element.span.clone(),
867                    }));
868                }
869            }
870        }
871    }
872}