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