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                    handler,
384                    ctx.engines,
385                    logged_type_id,
386                    ctx.program_name.clone(),
387                )?);
388
389                // We still need to dive into the expression because it can have additional types to collect.
390                // E.g., `revert some_function_that_returns_error_enum_and_internally_logs_some_types()`;
391                res.append(&mut exp.collect_types_metadata(handler, ctx)?)
392            }
393            Ref(exp) | Deref(exp) => res.append(&mut exp.collect_types_metadata(handler, ctx)?),
394            // storage access can never be generic
395            // variable expressions don't ever have return types themselves, they're stored in
396            // `TyExpression::return_type`. Variable expressions are just names of variables.
397            VariableExpression { .. }
398            | ConstantExpression { .. }
399            | ConfigurableExpression { .. }
400            | ConstGenericExpression { .. }
401            | StorageAccess { .. }
402            | Literal(_)
403            | AbiName(_)
404            | Break
405            | Continue
406            | FunctionParameter => {}
407            Reassignment(reassignment) => {
408                res.append(&mut reassignment.rhs.collect_types_metadata(handler, ctx)?);
409            }
410        }
411        Ok(res)
412    }
413}
414
415impl MaterializeConstGenerics for TyExpression {
416    fn materialize_const_generics(
417        &mut self,
418        engines: &Engines,
419        handler: &Handler,
420        name: &str,
421        value: &TyExpression,
422    ) -> Result<(), ErrorEmitted> {
423        self.return_type
424            .materialize_const_generics(engines, handler, name, value)?;
425        match &mut self.expression {
426            TyExpressionVariant::CodeBlock(block) => {
427                for node in block.contents.iter_mut() {
428                    node.materialize_const_generics(engines, handler, name, value)?;
429                }
430                Ok(())
431            }
432            TyExpressionVariant::ConstGenericExpression { decl, .. } => {
433                decl.materialize_const_generics(engines, handler, name, value)
434            }
435            TyExpressionVariant::ImplicitReturn(expr) => {
436                expr.materialize_const_generics(engines, handler, name, value)
437            }
438            TyExpressionVariant::FunctionApplication {
439                arguments,
440                type_binding,
441                fn_ref,
442                ..
443            } => {
444                // Materialize non dummy fns
445                let new_decl = engines.de().get(fn_ref.id());
446                if !new_decl.is_trait_method_dummy {
447                    let mut type_subst_map = TypeSubstMap::new();
448                    type_subst_map
449                        .const_generics_materialization
450                        .insert(name.to_string(), value.clone());
451
452                    let mut new_decl = TyFunctionDecl::clone(&*new_decl);
453                    let r = new_decl.subst_inner(&SubstTypesContext {
454                        engines,
455                        type_subst_map: Some(&type_subst_map),
456                        subst_function_body: true,
457                    });
458
459                    if matches!(r, HasChanges::Yes) {
460                        *fn_ref = engines.de().insert(new_decl, None);
461                    }
462                }
463
464                if let Some(type_binding) = type_binding.as_mut() {
465                    type_binding
466                        .type_arguments
467                        .to_vec_mut()
468                        .materialize_const_generics(engines, handler, name, value)?;
469                }
470
471                for (_, expr) in arguments {
472                    expr.materialize_const_generics(engines, handler, name, value)?;
473                }
474                Ok(())
475            }
476            TyExpressionVariant::IntrinsicFunction(TyIntrinsicFunctionKind {
477                arguments,
478                type_arguments,
479                ..
480            }) => {
481                type_arguments.materialize_const_generics(engines, handler, name, value)?;
482                arguments.materialize_const_generics(engines, handler, name, value)
483            }
484            TyExpressionVariant::Return(expr) => {
485                expr.materialize_const_generics(engines, handler, name, value)
486            }
487            TyExpressionVariant::IfExp {
488                condition,
489                then,
490                r#else,
491            } => {
492                condition.materialize_const_generics(engines, handler, name, value)?;
493                then.materialize_const_generics(engines, handler, name, value)?;
494                if let Some(e) = r#else.as_mut() {
495                    e.materialize_const_generics(engines, handler, name, value)?;
496                }
497                Ok(())
498            }
499            TyExpressionVariant::WhileLoop { condition, body } => {
500                condition.materialize_const_generics(engines, handler, name, value)?;
501                body.materialize_const_generics(engines, handler, name, value)
502            }
503            TyExpressionVariant::Reassignment(expr) => expr
504                .rhs
505                .materialize_const_generics(engines, handler, name, value),
506            TyExpressionVariant::ArrayIndex { prefix, index } => {
507                prefix.materialize_const_generics(engines, handler, name, value)?;
508                index.materialize_const_generics(engines, handler, name, value)
509            }
510            TyExpressionVariant::Literal(_) | TyExpressionVariant::VariableExpression { .. } => {
511                Ok(())
512            }
513            TyExpressionVariant::ArrayExplicit {
514                elem_type,
515                contents,
516            } => {
517                elem_type.materialize_const_generics(engines, handler, name, value)?;
518                for item in contents.iter_mut() {
519                    item.materialize_const_generics(engines, handler, name, value)?;
520                }
521                Ok(())
522            }
523            TyExpressionVariant::ArrayRepeat {
524                elem_type,
525                value: elem_value,
526                length,
527            } => {
528                elem_type.materialize_const_generics(engines, handler, name, value)?;
529                elem_value.materialize_const_generics(engines, handler, name, value)?;
530                length.materialize_const_generics(engines, handler, name, value)
531            }
532            TyExpressionVariant::Ref(r) => {
533                r.materialize_const_generics(engines, handler, name, value)
534            }
535            TyExpressionVariant::Deref(r) => {
536                r.materialize_const_generics(engines, handler, name, value)
537            }
538            TyExpressionVariant::MatchExp { desugared, .. } => {
539                desugared.materialize_const_generics(engines, handler, name, value)
540            }
541            TyExpressionVariant::EnumInstantiation { contents, .. } => {
542                if let Some(contents) = contents.as_mut() {
543                    contents.materialize_const_generics(engines, handler, name, value)?;
544                }
545                Ok(())
546            }
547            TyExpressionVariant::EnumTag { exp } => {
548                exp.materialize_const_generics(engines, handler, name, value)
549            }
550            TyExpressionVariant::Tuple { fields } => {
551                for f in fields {
552                    f.materialize_const_generics(engines, handler, name, value)?;
553                }
554                Ok(())
555            }
556            TyExpressionVariant::TupleElemAccess {
557                prefix,
558                resolved_type_of_parent,
559                ..
560            } => {
561                prefix.materialize_const_generics(engines, handler, name, value)?;
562                resolved_type_of_parent
563                    .materialize_const_generics(engines, handler, name, value)?;
564                Ok(())
565            }
566            TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
567                lhs.materialize_const_generics(engines, handler, name, value)?;
568                rhs.materialize_const_generics(engines, handler, name, value)
569            }
570            TyExpressionVariant::AsmExpression { registers, .. } => {
571                for r in registers.iter_mut() {
572                    if let Some(init) = r.initializer.as_mut() {
573                        init.materialize_const_generics(engines, handler, name, value)?;
574                    }
575                }
576                Ok(())
577            }
578            TyExpressionVariant::ConstantExpression { decl, .. } => {
579                decl.materialize_const_generics(engines, handler, name, value)
580            }
581            TyExpressionVariant::StructExpression { fields, .. } => {
582                for f in fields {
583                    f.value
584                        .materialize_const_generics(engines, handler, name, value)?;
585                }
586                Ok(())
587            }
588            TyExpressionVariant::StructFieldAccess {
589                prefix,
590                resolved_type_of_parent,
591                ..
592            } => {
593                prefix.materialize_const_generics(engines, handler, name, value)?;
594                resolved_type_of_parent.materialize_const_generics(engines, handler, name, value)
595            }
596            TyExpressionVariant::UnsafeDowncast { exp, .. } => {
597                exp.materialize_const_generics(engines, handler, name, value)
598            }
599            TyExpressionVariant::Continue | TyExpressionVariant::Break => Ok(()),
600            TyExpressionVariant::AbiCast { address, .. } => {
601                address.materialize_const_generics(engines, handler, name, value)
602            }
603            _ => Err(handler.emit_err(
604                sway_error::error::CompileError::ConstGenericNotSupportedHere {
605                    span: self.span.clone(),
606                },
607            )),
608        }
609    }
610}
611
612impl TyExpression {
613    pub(crate) fn error(err: ErrorEmitted, span: Span, engines: &Engines) -> TyExpression {
614        let type_engine = engines.te();
615        TyExpression {
616            expression: TyExpressionVariant::Tuple { fields: vec![] },
617            return_type: type_engine.id_of_error_recovery(err),
618            span,
619        }
620    }
621
622    /// gathers the mutability of the expressions within
623    pub(crate) fn gather_mutability(&self) -> VariableMutability {
624        match &self.expression {
625            TyExpressionVariant::VariableExpression { mutability, .. } => *mutability,
626            _ => VariableMutability::Immutable,
627        }
628    }
629
630    /// Returns `self` as a literal, if possible.
631    pub(crate) fn extract_literal_value(&self) -> Option<Literal> {
632        self.expression.extract_literal_value()
633    }
634
635    // Checks if this expression references a deprecated item
636    // TODO: Extend checks in this function to fully implement deprecation.
637    //       See: https://github.com/FuelLabs/sway/issues/6942
638    pub(crate) fn check_deprecated(
639        &self,
640        engines: &Engines,
641        handler: &Handler,
642        allow_deprecated: &mut AllowDeprecatedState,
643    ) {
644        fn emit_warning_if_deprecated(
645            attributes: &Attributes,
646            span: &Span,
647            handler: &Handler,
648            deprecated_element: DeprecatedElement,
649            deprecated_element_name: &str,
650            allow_deprecated: &mut AllowDeprecatedState,
651        ) {
652            if allow_deprecated.is_allowed() {
653                return;
654            }
655
656            let Some(deprecated_attr) = attributes.deprecated() else {
657                return;
658            };
659
660            let help = deprecated_attr
661                .args
662                .iter()
663                // Last "note" argument wins ;-)
664                .rfind(|arg| arg.is_deprecated_note())
665                .and_then(|note_arg| match note_arg.get_string_opt(handler) {
666                    Ok(note) => note.cloned(),
667                    // We treat invalid values here as not having the "note" provided.
668                    // Attribute checking will emit errors.
669                    Err(_) => None,
670                });
671
672            handler.emit_warn(CompileWarning {
673                span: span.clone(),
674                warning_content: Warning::UsingDeprecated {
675                    deprecated_element,
676                    deprecated_element_name: deprecated_element_name.to_string(),
677                    help,
678                },
679            })
680        }
681
682        match &self.expression {
683            TyExpressionVariant::Literal(..) => {}
684            TyExpressionVariant::FunctionApplication {
685                call_path,
686                fn_ref,
687                arguments,
688                ..
689            } => {
690                for (_, expr) in arguments {
691                    expr.check_deprecated(engines, handler, allow_deprecated);
692                }
693
694                let fn_ty = engines.de().get(fn_ref);
695                if let Some(TyDecl::ImplSelfOrTrait(t)) = &fn_ty.implementing_type {
696                    let t = &engines.de().get(&t.decl_id).implementing_for;
697                    if let TypeInfo::Struct(struct_id) = &*engines.te().get(t.type_id()) {
698                        let s = engines.de().get(struct_id);
699                        emit_warning_if_deprecated(
700                            &s.attributes,
701                            &call_path.span(),
702                            handler,
703                            DeprecatedElement::Struct,
704                            s.call_path.suffix.as_str(),
705                            allow_deprecated,
706                        );
707                    }
708                }
709
710                emit_warning_if_deprecated(
711                    &fn_ty.attributes,
712                    &call_path.span(),
713                    handler,
714                    DeprecatedElement::Function,
715                    fn_ty.call_path.suffix.as_str(),
716                    allow_deprecated,
717                );
718            }
719            TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
720                lhs.check_deprecated(engines, handler, allow_deprecated);
721                rhs.check_deprecated(engines, handler, allow_deprecated);
722            }
723            TyExpressionVariant::ConstantExpression { span, decl, .. } => {
724                emit_warning_if_deprecated(
725                    &decl.attributes,
726                    span,
727                    handler,
728                    DeprecatedElement::Const,
729                    decl.call_path.suffix.as_str(),
730                    allow_deprecated,
731                );
732            }
733            TyExpressionVariant::ConfigurableExpression { span, decl, .. } => {
734                emit_warning_if_deprecated(
735                    &decl.attributes,
736                    span,
737                    handler,
738                    DeprecatedElement::Configurable,
739                    decl.call_path.suffix.as_str(),
740                    allow_deprecated,
741                );
742            }
743            // Const generics don“t have attributes, so deprecation warnings cannot be turned off.
744            TyExpressionVariant::ConstGenericExpression { .. } => {}
745            TyExpressionVariant::VariableExpression { .. } => {}
746            TyExpressionVariant::Tuple { fields } => {
747                for e in fields {
748                    e.check_deprecated(engines, handler, allow_deprecated);
749                }
750            }
751            TyExpressionVariant::ArrayExplicit { contents, .. } => {
752                for e in contents {
753                    e.check_deprecated(engines, handler, allow_deprecated);
754                }
755            }
756            TyExpressionVariant::ArrayRepeat { value, length, .. } => {
757                value.check_deprecated(engines, handler, allow_deprecated);
758                length.check_deprecated(engines, handler, allow_deprecated);
759            }
760            TyExpressionVariant::ArrayIndex { prefix, index } => {
761                prefix.check_deprecated(engines, handler, allow_deprecated);
762                index.check_deprecated(engines, handler, allow_deprecated);
763            }
764            TyExpressionVariant::StructExpression {
765                struct_id,
766                instantiation_span,
767                ..
768            } => {
769                let struct_decl = engines.de().get(struct_id);
770                emit_warning_if_deprecated(
771                    &struct_decl.attributes,
772                    instantiation_span,
773                    handler,
774                    DeprecatedElement::Struct,
775                    struct_decl.call_path.suffix.as_str(),
776                    allow_deprecated,
777                );
778            }
779            TyExpressionVariant::CodeBlock(block) => {
780                block.check_deprecated(engines, handler, allow_deprecated);
781            }
782            TyExpressionVariant::FunctionParameter => {}
783            TyExpressionVariant::MatchExp {
784                desugared,
785                // TODO: Check the scrutinees.
786                //       See: https://github.com/FuelLabs/sway/issues/6942
787                ..
788            } => {
789                desugared.check_deprecated(engines, handler, allow_deprecated);
790            }
791            TyExpressionVariant::IfExp {
792                condition,
793                then,
794                r#else,
795            } => {
796                condition.check_deprecated(engines, handler, allow_deprecated);
797                then.check_deprecated(engines, handler, allow_deprecated);
798                if let Some(e) = r#else {
799                    e.check_deprecated(engines, handler, allow_deprecated);
800                }
801            }
802            TyExpressionVariant::AsmExpression { .. } => {}
803            TyExpressionVariant::StructFieldAccess {
804                prefix,
805                field_to_access,
806                field_instantiation_span,
807                ..
808            } => {
809                prefix.check_deprecated(engines, handler, allow_deprecated);
810                emit_warning_if_deprecated(
811                    &field_to_access.attributes,
812                    field_instantiation_span,
813                    handler,
814                    DeprecatedElement::StructField,
815                    field_to_access.name.as_str(),
816                    allow_deprecated,
817                );
818            }
819            TyExpressionVariant::TupleElemAccess { prefix, .. } => {
820                prefix.check_deprecated(engines, handler, allow_deprecated);
821            }
822            TyExpressionVariant::EnumInstantiation {
823                enum_ref,
824                tag,
825                contents,
826                variant_instantiation_span,
827                call_path_binding,
828                ..
829            } => {
830                let enum_ty = engines.de().get(enum_ref);
831                emit_warning_if_deprecated(
832                    &enum_ty.attributes,
833                    // variant_instantiation_span,
834                    &call_path_binding.span,
835                    handler,
836                    DeprecatedElement::Enum,
837                    enum_ty.call_path.suffix.as_str(),
838                    allow_deprecated,
839                );
840                if let Some(variant_decl) = enum_ty.variants.get(*tag) {
841                    emit_warning_if_deprecated(
842                        &variant_decl.attributes,
843                        variant_instantiation_span,
844                        handler,
845                        DeprecatedElement::EnumVariant,
846                        variant_decl.name.as_str(),
847                        allow_deprecated,
848                    );
849                }
850                if let Some(expr) = contents {
851                    expr.check_deprecated(engines, handler, allow_deprecated);
852                }
853            }
854            TyExpressionVariant::AbiCast { address, .. } => {
855                // TODO: Check the abi name.
856                //       See: https://github.com/FuelLabs/sway/issues/6942
857                address.check_deprecated(engines, handler, allow_deprecated);
858            }
859            TyExpressionVariant::StorageAccess(access) => {
860                // TODO: Check the storage access.
861                //       See: https://github.com/FuelLabs/sway/issues/6942
862                if let Some(expr) = &access.key_expression {
863                    expr.check_deprecated(engines, handler, allow_deprecated);
864                }
865            }
866            TyExpressionVariant::IntrinsicFunction(kind) => {
867                for arg in kind.arguments.iter() {
868                    arg.check_deprecated(engines, handler, allow_deprecated);
869                }
870            }
871            TyExpressionVariant::AbiName(..) => {}
872            TyExpressionVariant::EnumTag { exp } => {
873                exp.check_deprecated(engines, handler, allow_deprecated);
874            }
875            TyExpressionVariant::UnsafeDowncast {
876                exp,
877                // TODO: Check the variant.
878                //       See: https://github.com/FuelLabs/sway/issues/6942
879                ..
880            } => {
881                exp.check_deprecated(engines, handler, allow_deprecated);
882            }
883            TyExpressionVariant::WhileLoop { condition, body } => {
884                condition.check_deprecated(engines, handler, allow_deprecated);
885                body.check_deprecated(engines, handler, allow_deprecated);
886            }
887            TyExpressionVariant::ForLoop { desugared } => {
888                desugared.check_deprecated(engines, handler, allow_deprecated);
889            }
890            TyExpressionVariant::Break => {}
891            TyExpressionVariant::Continue => {}
892            TyExpressionVariant::Reassignment(reass) => {
893                if let TyReassignmentTarget::DerefAccess { exp, indices } = &reass.lhs {
894                    exp.check_deprecated(engines, handler, allow_deprecated);
895                    for indice in indices {
896                        match indice {
897                            ProjectionKind::StructField {
898                                name: idx_name,
899                                field_to_access,
900                            } => {
901                                if let Some(field_to_access) = field_to_access {
902                                    emit_warning_if_deprecated(
903                                        &field_to_access.attributes,
904                                        &idx_name.span(),
905                                        handler,
906                                        DeprecatedElement::StructField,
907                                        idx_name.as_str(),
908                                        allow_deprecated,
909                                    );
910                                }
911                            }
912                            ProjectionKind::TupleField {
913                                index: _,
914                                index_span: _,
915                            } => {}
916                            ProjectionKind::ArrayIndex {
917                                index,
918                                index_span: _,
919                            } => index.check_deprecated(engines, handler, allow_deprecated),
920                        }
921                    }
922                }
923                // TODO: Check `TyReassignmentTarget::ElementAccess`.
924                //       See: https://github.com/FuelLabs/sway/issues/6942
925                reass
926                    .rhs
927                    .check_deprecated(engines, handler, allow_deprecated);
928            }
929            TyExpressionVariant::ImplicitReturn(expr) => {
930                expr.check_deprecated(engines, handler, allow_deprecated);
931            }
932            TyExpressionVariant::Return(expr) => {
933                expr.check_deprecated(engines, handler, allow_deprecated);
934            }
935            TyExpressionVariant::Panic(expr) => {
936                expr.check_deprecated(engines, handler, allow_deprecated);
937            }
938            TyExpressionVariant::Ref(expr) => {
939                expr.check_deprecated(engines, handler, allow_deprecated);
940            }
941            TyExpressionVariant::Deref(expr) => {
942                expr.check_deprecated(engines, handler, allow_deprecated);
943            }
944        }
945    }
946
947    pub fn as_array(&self) -> Option<(&TypeId, &[TyExpression])> {
948        match &self.expression {
949            TyExpressionVariant::ArrayExplicit {
950                elem_type,
951                contents,
952            } => Some((elem_type, contents)),
953            _ => None,
954        }
955    }
956
957    pub fn as_intrinsic(&self) -> Option<&TyIntrinsicFunctionKind> {
958        match &self.expression {
959            TyExpressionVariant::IntrinsicFunction(v) => Some(v),
960            _ => None,
961        }
962    }
963
964    /// Unify elem_type with each element return type.
965    /// Must be called on arrays.
966    pub fn as_array_unify_elements(&self, handler: &Handler, engines: &Engines) {
967        let TyExpressionVariant::ArrayExplicit {
968            elem_type,
969            contents,
970        } = &self.expression
971        else {
972            unreachable!("Should only be called on Arrays")
973        };
974
975        let array_elem_type = engines.te().get(*elem_type);
976        if !matches!(&*array_elem_type, TypeInfo::Never) {
977            let unify = crate::type_system::unify::unifier::Unifier::new(
978                engines,
979                "",
980                unify::unifier::UnifyKind::Default,
981            );
982            for element in contents {
983                let element_type = engines.te().get(element.return_type);
984
985                // If the element is never, we do not need to check
986                if matches!(&*element_type, TypeInfo::Never) {
987                    continue;
988                }
989
990                let h = Handler::default();
991                unify.unify(&h, element.return_type, *elem_type, &element.span, true);
992
993                // unification error points to type that failed
994                // we want to report the element type instead
995                if h.has_errors() {
996                    handler.emit_err(CompileError::TypeError(TypeError::MismatchedType {
997                        expected: engines.help_out(&*array_elem_type).to_string(),
998                        received: engines.help_out(&*element_type).to_string(),
999                        help_text: String::new(),
1000                        span: element.span.clone(),
1001                    }));
1002                }
1003            }
1004        }
1005    }
1006}