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.generic_parameters {
227                    match p {
228                        TypeParameter::Type(p) => {
229                            ctx.call_site_insert(p.type_id, instantiation_span.clone());
230                        }
231                        TypeParameter::Const(_) => {}
232                    }
233                }
234                if let TypeInfo::Struct(decl_ref) = &*ctx.engines.te().get(self.return_type) {
235                    let decl = decl_engine.get_struct(decl_ref);
236                    for p in &decl.generic_parameters {
237                        match p {
238                            TypeParameter::Type(p) => {
239                                ctx.call_site_insert(p.type_id, instantiation_span.clone());
240                            }
241                            TypeParameter::Const(_) => {}
242                        }
243                    }
244                }
245                for field in fields.iter() {
246                    res.append(&mut field.value.collect_types_metadata(handler, ctx)?);
247                }
248            }
249            LazyOperator { lhs, rhs, .. } => {
250                res.append(&mut lhs.collect_types_metadata(handler, ctx)?);
251                res.append(&mut rhs.collect_types_metadata(handler, ctx)?);
252            }
253            ArrayExplicit {
254                elem_type: _,
255                contents,
256            } => {
257                for content in contents.iter() {
258                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
259                }
260            }
261            ArrayRepeat {
262                elem_type: _,
263                value,
264                length,
265            } => {
266                res.append(&mut value.collect_types_metadata(handler, ctx)?);
267                res.append(&mut length.collect_types_metadata(handler, ctx)?);
268            }
269            ArrayIndex { prefix, index } => {
270                res.append(&mut (**prefix).collect_types_metadata(handler, ctx)?);
271                res.append(&mut (**index).collect_types_metadata(handler, ctx)?);
272            }
273            CodeBlock(block) => {
274                for content in block.contents.iter() {
275                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
276                }
277            }
278            MatchExp { desugared, .. } => {
279                res.append(&mut desugared.collect_types_metadata(handler, ctx)?)
280            }
281            IfExp {
282                condition,
283                then,
284                r#else,
285            } => {
286                res.append(&mut condition.collect_types_metadata(handler, ctx)?);
287                res.append(&mut then.collect_types_metadata(handler, ctx)?);
288                if let Some(r#else) = r#else {
289                    res.append(&mut r#else.collect_types_metadata(handler, ctx)?);
290                }
291            }
292            StructFieldAccess {
293                prefix,
294                resolved_type_of_parent,
295                ..
296            } => {
297                res.append(&mut prefix.collect_types_metadata(handler, ctx)?);
298                res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?);
299            }
300            TupleElemAccess {
301                prefix,
302                resolved_type_of_parent,
303                ..
304            } => {
305                res.append(&mut prefix.collect_types_metadata(handler, ctx)?);
306                res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?);
307            }
308            EnumInstantiation {
309                enum_ref,
310                contents,
311                call_path_binding,
312                ..
313            } => {
314                let enum_decl = decl_engine.get_enum(enum_ref);
315                for p in enum_decl.generic_parameters.iter() {
316                    match p {
317                        TypeParameter::Type(p) => {
318                            ctx.call_site_insert(p.type_id, call_path_binding.inner.suffix.span())
319                        }
320                        TypeParameter::Const(_) => {}
321                    }
322                }
323                if let Some(contents) = contents {
324                    res.append(&mut contents.collect_types_metadata(handler, ctx)?);
325                }
326                for variant in enum_decl.variants.iter() {
327                    res.append(
328                        &mut variant
329                            .type_argument
330                            .type_id()
331                            .collect_types_metadata(handler, ctx)?,
332                    );
333                }
334                for p in enum_decl.generic_parameters.iter() {
335                    match p {
336                        TypeParameter::Type(p) => {
337                            res.append(&mut p.type_id.collect_types_metadata(handler, ctx)?);
338                        }
339                        TypeParameter::Const(_) => {}
340                    }
341                }
342            }
343            AbiCast { address, .. } => {
344                res.append(&mut address.collect_types_metadata(handler, ctx)?);
345            }
346            IntrinsicFunction(kind) => {
347                res.append(&mut kind.collect_types_metadata(handler, ctx)?);
348            }
349            EnumTag { exp } => {
350                res.append(&mut exp.collect_types_metadata(handler, ctx)?);
351            }
352            UnsafeDowncast {
353                exp,
354                variant,
355                call_path_decl: _,
356            } => {
357                res.append(&mut exp.collect_types_metadata(handler, ctx)?);
358                res.append(
359                    &mut variant
360                        .type_argument
361                        .type_id()
362                        .collect_types_metadata(handler, ctx)?,
363                );
364            }
365            WhileLoop { condition, body } => {
366                res.append(&mut condition.collect_types_metadata(handler, ctx)?);
367                for content in body.contents.iter() {
368                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
369                }
370            }
371            ForLoop { desugared } => {
372                res.append(&mut desugared.collect_types_metadata(handler, ctx)?);
373            }
374            ImplicitReturn(exp) | Return(exp) => {
375                res.append(&mut exp.collect_types_metadata(handler, ctx)?)
376            }
377            Panic(exp) => {
378                // Register the type of the `panic` argument as a logged type.
379                let logged_type_id =
380                    TypeMetadata::get_logged_type_id(exp, ctx.experimental.new_encoding)
381                        .map_err(|err| handler.emit_err(err))?;
382                res.push(TypeMetadata::new_logged_type(
383                    ctx.engines,
384                    logged_type_id,
385                    ctx.program_name.clone(),
386                ));
387
388                // We still need to dive into the expression because it can have additional types to collect.
389                // E.g., `revert some_function_that_returns_error_enum_and_internally_logs_some_types()`;
390                res.append(&mut exp.collect_types_metadata(handler, ctx)?)
391            }
392            Ref(exp) | Deref(exp) => res.append(&mut exp.collect_types_metadata(handler, ctx)?),
393            // storage access can never be generic
394            // variable expressions don't ever have return types themselves, they're stored in
395            // `TyExpression::return_type`. Variable expressions are just names of variables.
396            VariableExpression { .. }
397            | ConstantExpression { .. }
398            | ConfigurableExpression { .. }
399            | ConstGenericExpression { .. }
400            | StorageAccess { .. }
401            | Literal(_)
402            | AbiName(_)
403            | Break
404            | Continue
405            | FunctionParameter => {}
406            Reassignment(reassignment) => {
407                res.append(&mut reassignment.rhs.collect_types_metadata(handler, ctx)?);
408            }
409        }
410        Ok(res)
411    }
412}
413
414impl MaterializeConstGenerics for TyExpression {
415    fn materialize_const_generics(
416        &mut self,
417        engines: &Engines,
418        handler: &Handler,
419        name: &str,
420        value: &TyExpression,
421    ) -> Result<(), ErrorEmitted> {
422        self.return_type
423            .materialize_const_generics(engines, handler, name, value)?;
424        match &mut self.expression {
425            TyExpressionVariant::CodeBlock(block) => {
426                for node in block.contents.iter_mut() {
427                    node.materialize_const_generics(engines, handler, name, value)?;
428                }
429                Ok(())
430            }
431            TyExpressionVariant::ConstGenericExpression { decl, .. } => {
432                decl.materialize_const_generics(engines, handler, name, value)
433            }
434            TyExpressionVariant::ImplicitReturn(expr) => {
435                expr.materialize_const_generics(engines, handler, name, value)
436            }
437            TyExpressionVariant::FunctionApplication { arguments, .. } => {
438                for (_, expr) in arguments {
439                    expr.materialize_const_generics(engines, handler, name, value)?;
440                }
441                Ok(())
442            }
443            TyExpressionVariant::IntrinsicFunction(TyIntrinsicFunctionKind {
444                arguments, ..
445            }) => {
446                for expr in arguments {
447                    expr.materialize_const_generics(engines, handler, name, value)?;
448                }
449                Ok(())
450            }
451            TyExpressionVariant::Return(expr) => {
452                expr.materialize_const_generics(engines, handler, name, value)
453            }
454            TyExpressionVariant::IfExp {
455                condition,
456                then,
457                r#else,
458            } => {
459                condition.materialize_const_generics(engines, handler, name, value)?;
460                then.materialize_const_generics(engines, handler, name, value)?;
461                if let Some(e) = r#else.as_mut() {
462                    e.materialize_const_generics(engines, handler, name, value)?;
463                }
464                Ok(())
465            }
466            TyExpressionVariant::WhileLoop { condition, body } => {
467                condition.materialize_const_generics(engines, handler, name, value)?;
468                body.materialize_const_generics(engines, handler, name, value)
469            }
470            TyExpressionVariant::Reassignment(expr) => expr
471                .rhs
472                .materialize_const_generics(engines, handler, name, value),
473            TyExpressionVariant::ArrayIndex { prefix, index } => {
474                prefix.materialize_const_generics(engines, handler, name, value)?;
475                index.materialize_const_generics(engines, handler, name, value)
476            }
477            TyExpressionVariant::Literal(_) | TyExpressionVariant::VariableExpression { .. } => {
478                Ok(())
479            }
480            TyExpressionVariant::ArrayRepeat {
481                elem_type,
482                value: elem_value,
483                length,
484            } => {
485                elem_type.materialize_const_generics(engines, handler, name, value)?;
486                elem_value.materialize_const_generics(engines, handler, name, value)?;
487                length.materialize_const_generics(engines, handler, name, value)
488            }
489            TyExpressionVariant::Ref(r) => {
490                r.materialize_const_generics(engines, handler, name, value)
491            }
492            TyExpressionVariant::Deref(r) => {
493                r.materialize_const_generics(engines, handler, name, value)
494            }
495            TyExpressionVariant::MatchExp { desugared, .. } => {
496                desugared.materialize_const_generics(engines, handler, name, value)
497            }
498            TyExpressionVariant::EnumInstantiation { contents, .. } => {
499                if let Some(contents) = contents.as_mut() {
500                    contents.materialize_const_generics(engines, handler, name, value)?;
501                }
502                Ok(())
503            }
504            TyExpressionVariant::EnumTag { exp } => {
505                exp.materialize_const_generics(engines, handler, name, value)
506            }
507            TyExpressionVariant::Tuple { fields } => {
508                for f in fields {
509                    f.materialize_const_generics(engines, handler, name, value)?;
510                }
511                Ok(())
512            }
513            TyExpressionVariant::TupleElemAccess {
514                prefix,
515                resolved_type_of_parent,
516                ..
517            } => {
518                prefix.materialize_const_generics(engines, handler, name, value)?;
519                resolved_type_of_parent
520                    .materialize_const_generics(engines, handler, name, value)?;
521                Ok(())
522            }
523            TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
524                lhs.materialize_const_generics(engines, handler, name, value)?;
525                rhs.materialize_const_generics(engines, handler, name, value)
526            }
527            TyExpressionVariant::AsmExpression { registers, .. } => {
528                for r in registers.iter_mut() {
529                    if let Some(init) = r.initializer.as_mut() {
530                        init.materialize_const_generics(engines, handler, name, value)?;
531                    }
532                }
533                Ok(())
534            }
535            TyExpressionVariant::ConstantExpression { .. } => Ok(()),
536            TyExpressionVariant::StructExpression { fields, .. } => {
537                for f in fields {
538                    f.value
539                        .materialize_const_generics(engines, handler, name, value)?;
540                }
541                Ok(())
542            }
543            TyExpressionVariant::StructFieldAccess {
544                prefix,
545                resolved_type_of_parent,
546                ..
547            } => {
548                prefix.materialize_const_generics(engines, handler, name, value)?;
549                resolved_type_of_parent.materialize_const_generics(engines, handler, name, value)
550            }
551            TyExpressionVariant::UnsafeDowncast { exp, .. } => {
552                exp.materialize_const_generics(engines, handler, name, value)
553            }
554            _ => Err(handler.emit_err(
555                sway_error::error::CompileError::ConstGenericNotSupportedHere {
556                    span: self.span.clone(),
557                },
558            )),
559        }
560    }
561}
562
563impl TyExpression {
564    pub(crate) fn error(err: ErrorEmitted, span: Span, engines: &Engines) -> TyExpression {
565        let type_engine = engines.te();
566        TyExpression {
567            expression: TyExpressionVariant::Tuple { fields: vec![] },
568            return_type: type_engine.id_of_error_recovery(err),
569            span,
570        }
571    }
572
573    /// gathers the mutability of the expressions within
574    pub(crate) fn gather_mutability(&self) -> VariableMutability {
575        match &self.expression {
576            TyExpressionVariant::VariableExpression { mutability, .. } => *mutability,
577            _ => VariableMutability::Immutable,
578        }
579    }
580
581    /// Returns `self` as a literal, if possible.
582    pub(crate) fn extract_literal_value(&self) -> Option<Literal> {
583        self.expression.extract_literal_value()
584    }
585
586    // Checks if this expression references a deprecated item
587    // TODO: Extend checks in this function to fully implement deprecation.
588    //       See: https://github.com/FuelLabs/sway/issues/6942
589    pub(crate) fn check_deprecated(
590        &self,
591        engines: &Engines,
592        handler: &Handler,
593        allow_deprecated: &mut AllowDeprecatedState,
594    ) {
595        fn emit_warning_if_deprecated(
596            attributes: &Attributes,
597            span: &Span,
598            handler: &Handler,
599            deprecated_element: DeprecatedElement,
600            deprecated_element_name: &str,
601            allow_deprecated: &mut AllowDeprecatedState,
602        ) {
603            if allow_deprecated.is_allowed() {
604                return;
605            }
606
607            let Some(deprecated_attr) = attributes.deprecated() else {
608                return;
609            };
610
611            let help = deprecated_attr
612                .args
613                .iter()
614                // Last "note" argument wins ;-)
615                .rfind(|arg| arg.is_deprecated_note())
616                .and_then(|note_arg| match note_arg.get_string_opt(handler) {
617                    Ok(note) => note.cloned(),
618                    // We treat invalid values here as not having the "note" provided.
619                    // Attribute checking will emit errors.
620                    Err(_) => None,
621                });
622
623            handler.emit_warn(CompileWarning {
624                span: span.clone(),
625                warning_content: Warning::UsingDeprecated {
626                    deprecated_element,
627                    deprecated_element_name: deprecated_element_name.to_string(),
628                    help,
629                },
630            })
631        }
632
633        match &self.expression {
634            TyExpressionVariant::Literal(..) => {}
635            TyExpressionVariant::FunctionApplication {
636                call_path,
637                fn_ref,
638                arguments,
639                ..
640            } => {
641                for (_, expr) in arguments {
642                    expr.check_deprecated(engines, handler, allow_deprecated);
643                }
644
645                let fn_ty = engines.de().get(fn_ref);
646                if let Some(TyDecl::ImplSelfOrTrait(t)) = &fn_ty.implementing_type {
647                    let t = &engines.de().get(&t.decl_id).implementing_for;
648                    if let TypeInfo::Struct(struct_id) = &*engines.te().get(t.type_id()) {
649                        let s = engines.de().get(struct_id);
650                        emit_warning_if_deprecated(
651                            &s.attributes,
652                            &call_path.span(),
653                            handler,
654                            DeprecatedElement::Struct,
655                            s.call_path.suffix.as_str(),
656                            allow_deprecated,
657                        );
658                    }
659                }
660
661                emit_warning_if_deprecated(
662                    &fn_ty.attributes,
663                    &call_path.span(),
664                    handler,
665                    DeprecatedElement::Function,
666                    fn_ty.call_path.suffix.as_str(),
667                    allow_deprecated,
668                );
669            }
670            TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
671                lhs.check_deprecated(engines, handler, allow_deprecated);
672                rhs.check_deprecated(engines, handler, allow_deprecated);
673            }
674            TyExpressionVariant::ConstantExpression { span, decl, .. } => {
675                emit_warning_if_deprecated(
676                    &decl.attributes,
677                    span,
678                    handler,
679                    DeprecatedElement::Const,
680                    decl.call_path.suffix.as_str(),
681                    allow_deprecated,
682                );
683            }
684            TyExpressionVariant::ConfigurableExpression { span, decl, .. } => {
685                emit_warning_if_deprecated(
686                    &decl.attributes,
687                    span,
688                    handler,
689                    DeprecatedElement::Configurable,
690                    decl.call_path.suffix.as_str(),
691                    allow_deprecated,
692                );
693            }
694            // Const generics don“t have attributes, so deprecation warnings cannot be turned off.
695            TyExpressionVariant::ConstGenericExpression { .. } => {}
696            TyExpressionVariant::VariableExpression { .. } => {}
697            TyExpressionVariant::Tuple { fields } => {
698                for e in fields {
699                    e.check_deprecated(engines, handler, allow_deprecated);
700                }
701            }
702            TyExpressionVariant::ArrayExplicit { contents, .. } => {
703                for e in contents {
704                    e.check_deprecated(engines, handler, allow_deprecated);
705                }
706            }
707            TyExpressionVariant::ArrayRepeat { value, length, .. } => {
708                value.check_deprecated(engines, handler, allow_deprecated);
709                length.check_deprecated(engines, handler, allow_deprecated);
710            }
711            TyExpressionVariant::ArrayIndex { prefix, index } => {
712                prefix.check_deprecated(engines, handler, allow_deprecated);
713                index.check_deprecated(engines, handler, allow_deprecated);
714            }
715            TyExpressionVariant::StructExpression {
716                struct_id,
717                instantiation_span,
718                ..
719            } => {
720                let struct_decl = engines.de().get(struct_id);
721                emit_warning_if_deprecated(
722                    &struct_decl.attributes,
723                    instantiation_span,
724                    handler,
725                    DeprecatedElement::Struct,
726                    struct_decl.call_path.suffix.as_str(),
727                    allow_deprecated,
728                );
729            }
730            TyExpressionVariant::CodeBlock(block) => {
731                block.check_deprecated(engines, handler, allow_deprecated);
732            }
733            TyExpressionVariant::FunctionParameter => {}
734            TyExpressionVariant::MatchExp {
735                desugared,
736                // TODO: Check the scrutinees.
737                //       See: https://github.com/FuelLabs/sway/issues/6942
738                ..
739            } => {
740                desugared.check_deprecated(engines, handler, allow_deprecated);
741            }
742            TyExpressionVariant::IfExp {
743                condition,
744                then,
745                r#else,
746            } => {
747                condition.check_deprecated(engines, handler, allow_deprecated);
748                then.check_deprecated(engines, handler, allow_deprecated);
749                if let Some(e) = r#else {
750                    e.check_deprecated(engines, handler, allow_deprecated);
751                }
752            }
753            TyExpressionVariant::AsmExpression { .. } => {}
754            TyExpressionVariant::StructFieldAccess {
755                prefix,
756                field_to_access,
757                field_instantiation_span,
758                ..
759            } => {
760                prefix.check_deprecated(engines, handler, allow_deprecated);
761                emit_warning_if_deprecated(
762                    &field_to_access.attributes,
763                    field_instantiation_span,
764                    handler,
765                    DeprecatedElement::StructField,
766                    field_to_access.name.as_str(),
767                    allow_deprecated,
768                );
769            }
770            TyExpressionVariant::TupleElemAccess { prefix, .. } => {
771                prefix.check_deprecated(engines, handler, allow_deprecated);
772            }
773            TyExpressionVariant::EnumInstantiation {
774                enum_ref,
775                tag,
776                contents,
777                variant_instantiation_span,
778                call_path_binding,
779                ..
780            } => {
781                let enum_ty = engines.de().get(enum_ref);
782                emit_warning_if_deprecated(
783                    &enum_ty.attributes,
784                    // variant_instantiation_span,
785                    &call_path_binding.span,
786                    handler,
787                    DeprecatedElement::Enum,
788                    enum_ty.call_path.suffix.as_str(),
789                    allow_deprecated,
790                );
791                if let Some(variant_decl) = enum_ty.variants.get(*tag) {
792                    emit_warning_if_deprecated(
793                        &variant_decl.attributes,
794                        variant_instantiation_span,
795                        handler,
796                        DeprecatedElement::EnumVariant,
797                        variant_decl.name.as_str(),
798                        allow_deprecated,
799                    );
800                }
801                if let Some(expr) = contents {
802                    expr.check_deprecated(engines, handler, allow_deprecated);
803                }
804            }
805            TyExpressionVariant::AbiCast { address, .. } => {
806                // TODO: Check the abi name.
807                //       See: https://github.com/FuelLabs/sway/issues/6942
808                address.check_deprecated(engines, handler, allow_deprecated);
809            }
810            TyExpressionVariant::StorageAccess(access) => {
811                // TODO: Check the storage access.
812                //       See: https://github.com/FuelLabs/sway/issues/6942
813                if let Some(expr) = &access.key_expression {
814                    expr.check_deprecated(engines, handler, allow_deprecated);
815                }
816            }
817            TyExpressionVariant::IntrinsicFunction(kind) => {
818                for arg in kind.arguments.iter() {
819                    arg.check_deprecated(engines, handler, allow_deprecated);
820                }
821            }
822            TyExpressionVariant::AbiName(..) => {}
823            TyExpressionVariant::EnumTag { exp } => {
824                exp.check_deprecated(engines, handler, allow_deprecated);
825            }
826            TyExpressionVariant::UnsafeDowncast {
827                exp,
828                // TODO: Check the variant.
829                //       See: https://github.com/FuelLabs/sway/issues/6942
830                ..
831            } => {
832                exp.check_deprecated(engines, handler, allow_deprecated);
833            }
834            TyExpressionVariant::WhileLoop { condition, body } => {
835                condition.check_deprecated(engines, handler, allow_deprecated);
836                body.check_deprecated(engines, handler, allow_deprecated);
837            }
838            TyExpressionVariant::ForLoop { desugared } => {
839                desugared.check_deprecated(engines, handler, allow_deprecated);
840            }
841            TyExpressionVariant::Break => {}
842            TyExpressionVariant::Continue => {}
843            TyExpressionVariant::Reassignment(reass) => {
844                if let TyReassignmentTarget::DerefAccess { exp, indices } = &reass.lhs {
845                    exp.check_deprecated(engines, handler, allow_deprecated);
846                    for indice in indices {
847                        match indice {
848                            ProjectionKind::StructField {
849                                name: idx_name,
850                                field_to_access,
851                            } => {
852                                if let Some(field_to_access) = field_to_access {
853                                    emit_warning_if_deprecated(
854                                        &field_to_access.attributes,
855                                        &idx_name.span(),
856                                        handler,
857                                        DeprecatedElement::StructField,
858                                        idx_name.as_str(),
859                                        allow_deprecated,
860                                    );
861                                }
862                            }
863                            ProjectionKind::TupleField {
864                                index: _,
865                                index_span: _,
866                            } => {}
867                            ProjectionKind::ArrayIndex {
868                                index,
869                                index_span: _,
870                            } => index.check_deprecated(engines, handler, allow_deprecated),
871                        }
872                    }
873                }
874                // TODO: Check `TyReassignmentTarget::ElementAccess`.
875                //       See: https://github.com/FuelLabs/sway/issues/6942
876                reass
877                    .rhs
878                    .check_deprecated(engines, handler, allow_deprecated);
879            }
880            TyExpressionVariant::ImplicitReturn(expr) => {
881                expr.check_deprecated(engines, handler, allow_deprecated);
882            }
883            TyExpressionVariant::Return(expr) => {
884                expr.check_deprecated(engines, handler, allow_deprecated);
885            }
886            TyExpressionVariant::Panic(expr) => {
887                expr.check_deprecated(engines, handler, allow_deprecated);
888            }
889            TyExpressionVariant::Ref(expr) => {
890                expr.check_deprecated(engines, handler, allow_deprecated);
891            }
892            TyExpressionVariant::Deref(expr) => {
893                expr.check_deprecated(engines, handler, allow_deprecated);
894            }
895        }
896    }
897
898    pub fn as_array(&self) -> Option<(&TypeId, &[TyExpression])> {
899        match &self.expression {
900            TyExpressionVariant::ArrayExplicit {
901                elem_type,
902                contents,
903            } => Some((elem_type, contents)),
904            _ => None,
905        }
906    }
907
908    pub fn as_intrinsic(&self) -> Option<&TyIntrinsicFunctionKind> {
909        match &self.expression {
910            TyExpressionVariant::IntrinsicFunction(v) => Some(v),
911            _ => None,
912        }
913    }
914
915    /// Unify elem_type with each element return type.
916    /// Must be called on arrays.
917    pub fn as_array_unify_elements(&self, handler: &Handler, engines: &Engines) {
918        let TyExpressionVariant::ArrayExplicit {
919            elem_type,
920            contents,
921        } = &self.expression
922        else {
923            unreachable!("Should only be called on Arrays")
924        };
925
926        let array_elem_type = engines.te().get(*elem_type);
927        if !matches!(&*array_elem_type, TypeInfo::Never) {
928            let unify = crate::type_system::unify::unifier::Unifier::new(
929                engines,
930                "",
931                unify::unifier::UnifyKind::Default,
932            );
933            for element in contents {
934                let element_type = engines.te().get(element.return_type);
935
936                // If the element is never, we do not need to check
937                if matches!(&*element_type, TypeInfo::Never) {
938                    continue;
939                }
940
941                let h = Handler::default();
942                unify.unify(&h, element.return_type, *elem_type, &element.span, true);
943
944                // unification error points to type that failed
945                // we want to report the element type instead
946                if h.has_errors() {
947                    handler.emit_err(CompileError::TypeError(TypeError::MismatchedType {
948                        expected: format!("{:?}", engines.help_out(&array_elem_type)),
949                        received: format!("{:?}", engines.help_out(element_type)),
950                        help_text: String::new(),
951                        span: element.span.clone(),
952                    }));
953                }
954            }
955        }
956    }
957}