Skip to main content

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