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