sway_core/language/ty/declaration/
function.rs

1use crate::{
2    ast_elements::type_argument::GenericTypeArgument,
3    decl_engine::*,
4    engine_threading::*,
5    has_changes,
6    language::{
7        parsed::{self, FunctionDeclaration, FunctionDeclarationKind},
8        ty::*,
9        CallPath, Inline, Purity, Trace, Visibility,
10    },
11    semantic_analysis::TypeCheckContext,
12    transform::{self, AttributeKind},
13    type_system::*,
14    types::*,
15};
16use ast_elements::type_parameter::ConstGenericExpr;
17use either::Either;
18use monomorphization::MonomorphizeHelper;
19use serde::{Deserialize, Serialize};
20use sha2::{Digest, Sha256};
21use std::{
22    collections::BTreeMap,
23    fmt,
24    hash::{Hash, Hasher},
25};
26use sway_error::handler::{ErrorEmitted, Handler};
27use sway_types::{Ident, Named, Span, Spanned};
28
29#[derive(Clone, Debug, Serialize, Deserialize)]
30pub enum TyFunctionDeclKind {
31    Default,
32    Entry,
33    Main,
34    Test,
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct TyFunctionDecl {
39    pub name: Ident,
40    pub body: TyCodeBlock,
41    pub parameters: Vec<TyFunctionParameter>,
42    /// The [TyDecl] in which this function is implemented.
43    ///
44    /// For [TyFunctionDecl]s representing _declarations_ of
45    /// trait or ABI provided functions and methods, this will be
46    /// the [TyDecl::TraitDecl] and [TyDecl::AbiDecl], respectively.
47    ///
48    /// For [TyFunctionDecl]s representing _implementations_ of
49    /// functions and methods in trait or self impls, this will be
50    /// the [TyDecl::ImplSelfOrTrait].
51    ///
52    /// **For [TyFunctionDecl]s representing _function applications_,
53    /// this will always be the [TyDecl::ImplSelfOrTrait], even if
54    /// the called function is a trait or ABI provided function.**
55    ///
56    /// `None` for module functions.
57    pub implementing_type: Option<TyDecl>,
58    /// The [TypeId] of the type that this function is implemented for.
59    ///
60    /// For [TyFunctionDecl]s representing _declarations_ of
61    /// trait or ABI provided functions and methods, this will be
62    /// the [TypeInfo::UnknownGeneric] representing the `Self` generic parameter.
63    ///
64    /// For [TyFunctionDecl]s representing _implementations_ of
65    /// functions and methods in trait or self impls, this will be
66    /// the [TypeInfo] of the corresponding `Self` type, e.g., [TypeInfo::Struct].
67    ///
68    /// **For [TyFunctionDecl]s representing _function applications_,
69    /// this will always be the [TypeInfo] of the corresponding `Self` type,
70    /// even if the called function is a trait or ABI provided function.**
71    ///
72    /// `None` for module functions.
73    pub implementing_for: Option<TypeId>,
74    pub span: Span,
75    /// For module functions, this is the full call path of the function.
76    ///
77    /// Otherwise, the [CallPath::prefixes] are the prefixes of the module
78    /// in which the defining [TyFunctionDecl] is located, and the
79    /// [CallPath::suffix] is the function name.
80    pub call_path: CallPath,
81    pub attributes: transform::Attributes,
82    pub type_parameters: Vec<TypeParameter>,
83    pub return_type: GenericTypeArgument,
84    pub visibility: Visibility,
85    /// Whether this function exists in another contract and requires a call to it or not.
86    pub is_contract_call: bool,
87    pub purity: Purity,
88    pub where_clause: Vec<(Ident, Vec<TraitConstraint>)>,
89    pub is_trait_method_dummy: bool,
90    pub is_type_check_finalized: bool,
91    /// !!! WARNING !!!
92    /// This field is currently not reliable.
93    /// Do not use it to check the function kind.
94    /// Instead, use the [Self::is_default], [Self::is_entry], [Self::is_main], and [Self::is_test] methods.
95    /// TODO: See: https://github.com/FuelLabs/sway/issues/7371
96    /// !!! WARNING !!!
97    pub kind: TyFunctionDeclKind,
98}
99
100impl TyDeclParsedType for TyFunctionDecl {
101    type ParsedType = FunctionDeclaration;
102}
103
104impl DebugWithEngines for TyFunctionDecl {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
106        write!(
107            f,
108            "{}{:?}{}({}): {:?} -> {:?}",
109            if self.is_trait_method_dummy {
110                "dummy ".to_string()
111            } else {
112                "".to_string()
113            },
114            self.name,
115            if !self.type_parameters.is_empty() {
116                format!(
117                    "<{}>",
118                    self.type_parameters
119                        .iter()
120                        .map(|p| format!("{:?}", engines.help_out(p)))
121                        .collect::<Vec<_>>()
122                        .join(", ")
123                )
124            } else {
125                "".to_string()
126            },
127            self.parameters
128                .iter()
129                .map(|p| format!(
130                    "{}: {:?} -> {:?}",
131                    p.name.as_str(),
132                    engines.help_out(p.type_argument.initial_type_id),
133                    engines.help_out(p.type_argument.type_id)
134                ))
135                .collect::<Vec<_>>()
136                .join(", "),
137            engines.help_out(self.return_type.initial_type_id),
138            engines.help_out(self.return_type.type_id),
139        )
140    }
141}
142
143impl DisplayWithEngines for TyFunctionDecl {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
145        write!(
146            f,
147            "{}{}({}) -> {}",
148            self.name,
149            if !self.type_parameters.is_empty() {
150                format!(
151                    "<{}>",
152                    self.type_parameters
153                        .iter()
154                        .map(|p| {
155                            let p = p
156                                .as_type_parameter()
157                                .expect("only works for type parameters");
158                            format!("{}", engines.help_out(p.initial_type_id))
159                        })
160                        .collect::<Vec<_>>()
161                        .join(", ")
162                )
163            } else {
164                "".to_string()
165            },
166            self.parameters
167                .iter()
168                .map(|p| format!(
169                    "{}: {}",
170                    p.name.as_str(),
171                    engines.help_out(p.type_argument.initial_type_id)
172                ))
173                .collect::<Vec<_>>()
174                .join(", "),
175            engines.help_out(self.return_type.initial_type_id),
176        )
177    }
178}
179
180impl MaterializeConstGenerics for TyFunctionDecl {
181    fn materialize_const_generics(
182        &mut self,
183        engines: &Engines,
184        handler: &Handler,
185        name: &str,
186        value: &TyExpression,
187    ) -> Result<(), ErrorEmitted> {
188        for tp in self.type_parameters.iter_mut() {
189            match tp {
190                TypeParameter::Type(p) => p
191                    .type_id
192                    .materialize_const_generics(engines, handler, name, value)?,
193                TypeParameter::Const(p) if p.name.as_str() == name => match p.expr.as_ref() {
194                    Some(v) => {
195                        assert!(
196                            v.as_literal_val().unwrap() as u64
197                                == value
198                                    .extract_literal_value()
199                                    .unwrap()
200                                    .cast_value_to_u64()
201                                    .unwrap()
202                        );
203                    }
204                    None => {
205                        p.expr = Some(ConstGenericExpr::from_ty_expression(handler, value)?);
206                    }
207                },
208                _ => {}
209            }
210        }
211
212        for param in self.parameters.iter_mut() {
213            param
214                .type_argument
215                .type_id
216                .materialize_const_generics(engines, handler, name, value)?;
217        }
218        self.return_type
219            .type_id
220            .materialize_const_generics(engines, handler, name, value)?;
221        self.body
222            .materialize_const_generics(engines, handler, name, value)
223    }
224}
225
226/// Rename const generics when the name inside the struct/enum declaration  does not match
227/// the name in the impl.
228fn rename_const_generics_on_function(
229    engines: &Engines,
230    impl_self_or_trait: &TyImplSelfOrTrait,
231    function: &mut TyFunctionDecl,
232) {
233    let from = impl_self_or_trait.implementing_for.initial_type_id;
234    let to = impl_self_or_trait.implementing_for.type_id;
235
236    let from = engines.te().get(from);
237    let to = engines.te().get(to);
238
239    match (&*from, &*to) {
240        (
241            TypeInfo::Custom {
242                type_arguments: Some(type_arguments),
243                ..
244            },
245            TypeInfo::Struct(s),
246        ) => {
247            let decl = engines.de().get(s);
248            rename_const_generics_on_function_inner(
249                engines,
250                function,
251                type_arguments,
252                decl.type_parameters(),
253            );
254        }
255        (
256            TypeInfo::Custom {
257                type_arguments: Some(type_arguments),
258                ..
259            },
260            TypeInfo::Enum(s),
261        ) => {
262            let decl = engines.de().get(s);
263            rename_const_generics_on_function_inner(
264                engines,
265                function,
266                type_arguments,
267                decl.type_parameters(),
268            );
269        }
270        _ => (),
271    }
272}
273
274fn rename_const_generics_on_function_inner(
275    engines: &Engines,
276    function: &mut TyFunctionDecl,
277    type_arguments: &[GenericArgument],
278    generic_parameters: &[TypeParameter],
279) {
280    for a in type_arguments.iter().zip(generic_parameters.iter()) {
281        match (a.0, a.1) {
282            (GenericArgument::Type(a), TypeParameter::Const(b)) => {
283                // replace all references from "a.name.as_str()" to "b.name.as_str()"
284                let mut type_subst_map = TypeSubstMap::default();
285                type_subst_map.const_generics_renaming.insert(
286                    a.call_path_tree
287                        .as_ref()
288                        .unwrap()
289                        .qualified_call_path
290                        .call_path
291                        .suffix
292                        .clone(),
293                    b.name.clone(),
294                );
295                function.subst_inner(&SubstTypesContext {
296                    engines,
297                    type_subst_map: Some(&type_subst_map),
298                    subst_function_body: true,
299                });
300            }
301            (GenericArgument::Const(a), TypeParameter::Const(b)) => {
302                engines
303                    .obs()
304                    .trace(|| format!("{:?} -> {:?}", a.expr, b.expr));
305            }
306            _ => {}
307        }
308    }
309}
310
311impl DeclRefFunction {
312    /// Makes method with a copy of type_id.
313    /// This avoids altering the type_id already in the type map.
314    /// Without this it is possible to retrieve a method from the type map unify its types and
315    /// the second time it won't be possible to retrieve the same method.
316    pub fn get_method_safe_to_unify(&self, engines: &Engines, type_id: TypeId) -> Self {
317        engines.obs().trace(|| {
318            format!(
319                "    before get_method_safe_to_unify: {:?} {:?}",
320                engines.help_out(type_id),
321                engines.help_out(self.id())
322            )
323        });
324
325        let decl_engine = engines.de();
326
327        let original = &*decl_engine.get_function(self);
328        let mut method = original.clone();
329
330        if let Some(method_implementing_for) = method.implementing_for {
331            let mut type_id_type_subst_map = TypeSubstMap::new();
332
333            if let Some(TyDecl::ImplSelfOrTrait(t)) = method.implementing_type.clone() {
334                let impl_self_or_trait = &*engines.de().get(&t.decl_id);
335                rename_const_generics_on_function(engines, impl_self_or_trait, &mut method);
336
337                let mut type_id_type_parameters = vec![];
338                let mut const_generic_parameters = BTreeMap::default();
339                type_id.extract_type_parameters(
340                    engines,
341                    0,
342                    &mut type_id_type_parameters,
343                    &mut const_generic_parameters,
344                    impl_self_or_trait.implementing_for.type_id,
345                );
346
347                type_id_type_subst_map
348                    .const_generics_materialization
349                    .append(&mut const_generic_parameters);
350
351                for p in impl_self_or_trait
352                    .impl_type_parameters
353                    .iter()
354                    .filter_map(|x| x.as_type_parameter())
355                {
356                    let matches = type_id_type_parameters
357                        .iter()
358                        .filter(|(_, orig_tp)| {
359                            engines.te().get(*orig_tp).eq(
360                                &*engines.te().get(p.type_id),
361                                &PartialEqWithEnginesContext::new(engines),
362                            )
363                        })
364                        .collect::<Vec<_>>();
365
366                    if !matches.is_empty() {
367                        // Adds type substitution for first match only as we can apply only one.
368                        type_id_type_subst_map.insert(p.type_id, matches[0].0);
369                    } else if engines
370                        .te()
371                        .get(impl_self_or_trait.implementing_for.initial_type_id)
372                        .eq(
373                            &*engines.te().get(p.initial_type_id),
374                            &PartialEqWithEnginesContext::new(engines),
375                        )
376                    {
377                        type_id_type_subst_map.insert(p.type_id, type_id);
378                    }
379                }
380            }
381
382            // Duplicate arguments to avoid changing TypeId inside TraitMap
383            for parameter in method.parameters.iter_mut() {
384                parameter.type_argument.type_id = engines
385                    .te()
386                    .duplicate(engines, parameter.type_argument.type_id)
387            }
388
389            let mut method_type_subst_map = TypeSubstMap::new();
390            method_type_subst_map.extend(&type_id_type_subst_map);
391            method_type_subst_map.insert(method_implementing_for, type_id);
392
393            method.subst(&SubstTypesContext::new(
394                engines,
395                &method_type_subst_map,
396                true,
397            ));
398
399            let r = engines
400                .de()
401                .insert(
402                    method.clone(),
403                    engines.de().get_parsed_decl_id(self.id()).as_ref(),
404                )
405                .with_parent(decl_engine, self.id().into());
406
407            engines.obs().trace(|| {
408                format!(
409                    "    after get_method_safe_to_unify: {:?}; {:?}",
410                    engines.help_out(type_id),
411                    engines.help_out(r.id())
412                )
413            });
414
415            return r;
416        }
417
418        engines.obs().trace(|| {
419            format!(
420                "    after get_method_safe_to_unify: {:?}; {:?}",
421                engines.help_out(type_id),
422                engines.help_out(self.id())
423            )
424        });
425
426        self.clone()
427    }
428}
429
430impl Named for TyFunctionDecl {
431    fn name(&self) -> &Ident {
432        &self.name
433    }
434}
435
436impl IsConcrete for TyFunctionDecl {
437    fn is_concrete(&self, engines: &Engines) -> bool {
438        self.type_parameters
439            .iter()
440            .all(|tp| tp.is_concrete(engines))
441            && self
442                .return_type
443                .type_id
444                .is_concrete(engines, TreatNumericAs::Concrete)
445            && self.parameters().iter().all(|t| {
446                t.type_argument
447                    .type_id
448                    .is_concrete(engines, TreatNumericAs::Concrete)
449            })
450    }
451}
452impl declaration::FunctionSignature for TyFunctionDecl {
453    fn parameters(&self) -> &Vec<TyFunctionParameter> {
454        &self.parameters
455    }
456
457    fn return_type(&self) -> &GenericTypeArgument {
458        &self.return_type
459    }
460}
461
462impl EqWithEngines for TyFunctionDecl {}
463impl PartialEqWithEngines for TyFunctionDecl {
464    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
465        self.name == other.name
466            && self.body.eq(&other.body, ctx)
467            && self.parameters.eq(&other.parameters, ctx)
468            && self.return_type.eq(&other.return_type, ctx)
469            && self.type_parameters.eq(&other.type_parameters, ctx)
470            && self.visibility == other.visibility
471            && self.is_contract_call == other.is_contract_call
472            && self.purity == other.purity
473            && self.call_path == other.call_path
474            && self.span == other.span
475    }
476}
477
478impl HashWithEngines for TyFunctionDecl {
479    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
480        let TyFunctionDecl {
481            name,
482            body,
483            parameters,
484            return_type,
485            type_parameters,
486            visibility,
487            is_contract_call,
488            purity,
489            call_path,
490            span,
491            // these fields are not hashed because they aren't relevant/a
492            // reliable source of obj v. obj distinction
493            attributes: _,
494            implementing_type: _,
495            implementing_for: _,
496            where_clause: _,
497            is_trait_method_dummy: _,
498            is_type_check_finalized: _,
499            kind: _,
500        } = self;
501        name.hash(state);
502        body.hash(state, engines);
503        parameters.hash(state, engines);
504        return_type.hash(state, engines);
505        type_parameters.hash(state, engines);
506        visibility.hash(state);
507        is_contract_call.hash(state);
508        purity.hash(state);
509        call_path.hash(state);
510        span.hash(state);
511    }
512}
513
514impl SubstTypes for TyFunctionDecl {
515    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
516        let changes = if ctx.subst_function_body {
517            has_changes! {
518                self.type_parameters.subst(ctx);
519                self.parameters.subst(ctx);
520                self.return_type.subst(ctx);
521                self.body.subst(ctx);
522                self.implementing_for.subst(ctx);
523            }
524        } else {
525            has_changes! {
526                self.type_parameters.subst(ctx);
527                self.parameters.subst(ctx);
528                self.return_type.subst(ctx);
529                self.implementing_for.subst(ctx);
530            }
531        };
532
533        if let Some(map) = ctx.type_subst_map.as_ref() {
534            let handler = Handler::default();
535            for (name, value) in &map.const_generics_materialization {
536                let _ = self.materialize_const_generics(ctx.engines, &handler, name, value);
537            }
538            HasChanges::Yes
539        } else {
540            changes
541        }
542    }
543}
544
545impl ReplaceDecls for TyFunctionDecl {
546    fn replace_decls_inner(
547        &mut self,
548        decl_mapping: &DeclMapping,
549        handler: &Handler,
550        ctx: &mut TypeCheckContext,
551    ) -> Result<bool, ErrorEmitted> {
552        let mut func_ctx = ctx.by_ref().with_self_type(self.implementing_for);
553        self.body
554            .replace_decls(decl_mapping, handler, &mut func_ctx)
555    }
556}
557
558impl Spanned for TyFunctionDecl {
559    fn span(&self) -> Span {
560        self.span.clone()
561    }
562}
563
564impl MonomorphizeHelper for TyFunctionDecl {
565    fn type_parameters(&self) -> &[TypeParameter] {
566        &self.type_parameters
567    }
568
569    fn name(&self) -> &Ident {
570        &self.name
571    }
572
573    fn has_self_type_param(&self) -> bool {
574        false
575    }
576}
577
578impl CollectTypesMetadata for TyFunctionDecl {
579    fn collect_types_metadata(
580        &self,
581        handler: &Handler,
582        ctx: &mut CollectTypesMetadataContext,
583    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
584        let mut body = vec![];
585        for content in self.body.contents.iter() {
586            body.append(&mut content.collect_types_metadata(handler, ctx)?);
587        }
588        body.append(
589            &mut self
590                .return_type
591                .type_id
592                .collect_types_metadata(handler, ctx)?,
593        );
594        for p in self.type_parameters.iter() {
595            let p = p
596                .as_type_parameter()
597                .expect("only works for type parameters");
598            body.append(&mut p.type_id.collect_types_metadata(handler, ctx)?);
599        }
600        for param in self.parameters.iter() {
601            body.append(
602                &mut param
603                    .type_argument
604                    .type_id
605                    .collect_types_metadata(handler, ctx)?,
606            );
607        }
608        Ok(body)
609    }
610}
611
612impl TyFunctionDecl {
613    pub(crate) fn set_implementing_type(&mut self, decl: TyDecl) {
614        self.implementing_type = Some(decl);
615    }
616
617    /// Used to create a stubbed out function when the function fails to
618    /// compile, preventing cascading namespace errors.
619    pub(crate) fn error(decl: &parsed::FunctionDeclaration) -> TyFunctionDecl {
620        let parsed::FunctionDeclaration {
621            name,
622            return_type,
623            span,
624            visibility,
625            purity,
626            where_clause,
627            kind,
628            ..
629        } = decl;
630        TyFunctionDecl {
631            purity: *purity,
632            name: name.clone(),
633            body: <_>::default(),
634            implementing_type: None,
635            implementing_for: None,
636            span: span.clone(),
637            call_path: CallPath::from(Ident::dummy()),
638            attributes: Default::default(),
639            is_contract_call: false,
640            parameters: Default::default(),
641            visibility: *visibility,
642            return_type: return_type.clone(),
643            type_parameters: Default::default(),
644            where_clause: where_clause.clone(),
645            is_trait_method_dummy: false,
646            is_type_check_finalized: true,
647            kind: match kind {
648                FunctionDeclarationKind::Default => TyFunctionDeclKind::Default,
649                FunctionDeclarationKind::Entry => TyFunctionDeclKind::Entry,
650                FunctionDeclarationKind::Test => TyFunctionDeclKind::Test,
651                FunctionDeclarationKind::Main => TyFunctionDeclKind::Main,
652            },
653        }
654    }
655
656    /// If there are parameters, join their spans. Otherwise, use the fn name span.
657    pub(crate) fn parameters_span(&self) -> Span {
658        if !self.parameters.is_empty() {
659            self.parameters.iter().fold(
660                // TODO: Use Span::join_all().
661                self.parameters[0].name.span(),
662                |acc, TyFunctionParameter { type_argument, .. }| {
663                    Span::join(acc, &type_argument.span)
664                },
665            )
666        } else {
667            self.name.span()
668        }
669    }
670
671    pub fn to_fn_selector_value_untruncated(
672        &self,
673        handler: &Handler,
674        engines: &Engines,
675    ) -> Result<Vec<u8>, ErrorEmitted> {
676        let mut hasher = Sha256::new();
677        let data = self.to_selector_name(handler, engines)?;
678        hasher.update(data);
679        let hash = hasher.finalize();
680        Ok(hash.to_vec())
681    }
682
683    /// Converts a [TyFunctionDecl] into a value that is to be used in contract function
684    /// selectors.
685    /// Hashes the name and parameters using SHA256, and then truncates to four bytes.
686    pub fn to_fn_selector_value(
687        &self,
688        handler: &Handler,
689        engines: &Engines,
690    ) -> Result<[u8; 4], ErrorEmitted> {
691        let hash = self.to_fn_selector_value_untruncated(handler, engines)?;
692        // 4 bytes truncation via copying into a 4 byte buffer
693        let mut buf = [0u8; 4];
694        buf.copy_from_slice(&hash[..4]);
695        Ok(buf)
696    }
697
698    pub fn to_selector_name(
699        &self,
700        handler: &Handler,
701        engines: &Engines,
702    ) -> Result<String, ErrorEmitted> {
703        let named_params = self
704            .parameters
705            .iter()
706            .map(|TyFunctionParameter { type_argument, .. }| {
707                engines
708                    .te()
709                    .to_typeinfo(type_argument.type_id, &type_argument.span)
710                    .expect("unreachable I think?")
711                    .to_selector_name(handler, engines, &type_argument.span)
712            })
713            .filter_map(|name| name.ok())
714            .collect::<Vec<String>>();
715
716        Ok(format!(
717            "{}({})",
718            self.name.as_str(),
719            named_params.join(","),
720        ))
721    }
722
723    pub fn is_default(&self) -> bool {
724        // TODO: Properly implement `TyFunctionDecl::kind` and match kind to `Default`.
725        //       See: https://github.com/FuelLabs/sway/issues/7371
726        !(self.is_entry() || self.is_main() || self.is_test())
727    }
728
729    /// Whether or not this function is the default entry point.
730    pub fn is_entry(&self) -> bool {
731        matches!(self.kind, TyFunctionDeclKind::Entry)
732    }
733
734    pub fn is_main(&self) -> bool {
735        matches!(self.kind, TyFunctionDeclKind::Main)
736    }
737
738    /// Whether or not this function is a unit test, i.e. decorated with `#[test]`.
739    pub fn is_test(&self) -> bool {
740        // TODO: Properly implement `TyFunctionDecl::kind` and match kind to `Test`.
741        //       See: https://github.com/FuelLabs/sway/issues/7371
742        self.attributes.has_any_of_kind(AttributeKind::Test)
743    }
744
745    pub fn inline(&self) -> Option<Inline> {
746        self.attributes.inline()
747    }
748
749    pub fn trace(&self) -> Option<Trace> {
750        self.attributes.trace()
751    }
752
753    pub fn is_fallback(&self) -> bool {
754        self.attributes.has_any_of_kind(AttributeKind::Fallback)
755    }
756
757    /// Whether or not this function is a constructor for the type given by `type_id`.
758    ///
759    /// Returns `Some(true)` if the function is surely the constructor and `Some(false)` if
760    /// it is surely not a constructor, and `None` if it cannot decide.
761    pub fn is_constructor(&self, engines: &Engines, type_id: TypeId) -> Option<bool> {
762        if self
763            .parameters
764            .first()
765            .map(|param| param.is_self())
766            .unwrap_or_default()
767        {
768            return Some(false);
769        };
770
771        match &self.implementing_type {
772            Some(TyDecl::ImplSelfOrTrait(t)) => {
773                let unify_check = UnifyCheck::non_dynamic_equality(engines);
774
775                let implementing_for = engines.de().get(&t.decl_id).implementing_for.type_id;
776
777                // TODO: Implement the check in detail for all possible cases (e.g. trait impls for generics etc.)
778                //       and return just the definite `bool` and not `Option<bool>`.
779                //       That would be too much effort at the moment for the immediate practical need of
780                //       error reporting where we suggest obvious most common constructors
781                //       that will be found using this simple check.
782                if unify_check.check(type_id, implementing_for)
783                    && unify_check.check(type_id, self.return_type.type_id)
784                {
785                    Some(true)
786                } else {
787                    None
788                }
789            }
790            _ => Some(false),
791        }
792    }
793
794    pub fn is_from_blanket_impl(&self, engines: &Engines) -> bool {
795        if let Some(TyDecl::ImplSelfOrTrait(existing_impl_trait)) = &self.implementing_type {
796            let existing_trait_decl = engines
797                .de()
798                .get_impl_self_or_trait(&existing_impl_trait.decl_id);
799            if !existing_trait_decl.impl_type_parameters.is_empty()
800                && matches!(
801                    *engines
802                        .te()
803                        .get(existing_trait_decl.implementing_for.type_id),
804                    TypeInfo::UnknownGeneric { .. }
805                )
806            {
807                return true;
808            }
809        }
810        false
811    }
812}
813
814#[derive(Debug, Clone, Serialize, Deserialize)]
815pub struct TyFunctionParameter {
816    pub name: Ident,
817    pub is_reference: bool,
818    pub is_mutable: bool,
819    pub mutability_span: Span,
820    pub type_argument: GenericTypeArgument,
821}
822
823impl EqWithEngines for TyFunctionParameter {}
824impl PartialEqWithEngines for TyFunctionParameter {
825    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
826        self.name == other.name
827            && self.type_argument.eq(&other.type_argument, ctx)
828            && self.is_reference == other.is_reference
829            && self.is_mutable == other.is_mutable
830    }
831}
832
833impl HashWithEngines for TyFunctionParameter {
834    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
835        let TyFunctionParameter {
836            name,
837            is_reference,
838            is_mutable,
839            type_argument,
840            // these fields are not hashed because they aren't relevant/a
841            // reliable source of obj v. obj distinction
842            mutability_span: _,
843        } = self;
844        name.hash(state);
845        type_argument.hash(state, engines);
846        is_reference.hash(state);
847        is_mutable.hash(state);
848    }
849}
850
851impl SubstTypes for TyFunctionParameter {
852    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
853        self.type_argument.type_id.subst(ctx)
854    }
855}
856
857impl TyFunctionParameter {
858    pub fn is_self(&self) -> bool {
859        self.name.as_str() == "self"
860    }
861}
862
863#[derive(Clone, Debug, PartialEq, Eq, Hash)]
864pub enum TyFunctionSigTypeParameter {
865    Type(TypeId),
866    Const(ConstGenericExpr),
867}
868
869#[derive(Clone, Debug, PartialEq, Eq, Hash)]
870pub struct TyFunctionSig {
871    pub return_type: TypeId,
872    pub parameters: Vec<TypeId>,
873    pub type_parameters: Vec<TyFunctionSigTypeParameter>,
874}
875
876impl DisplayWithEngines for TyFunctionSig {
877    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
878        write!(f, "{:?}", engines.help_out(self))
879    }
880}
881
882impl DebugWithEngines for TyFunctionSig {
883    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
884        let tp_str = if self.type_parameters.is_empty() {
885            "".to_string()
886        } else {
887            format!(
888                "<{}>",
889                self.type_parameters
890                    .iter()
891                    .map(|p| match p {
892                        TyFunctionSigTypeParameter::Type(t) => format!("{:?}", engines.help_out(t)),
893                        TyFunctionSigTypeParameter::Const(expr) =>
894                            format!("{:?}", engines.help_out(expr)),
895                    })
896                    .collect::<Vec<_>>()
897                    .join(", "),
898            )
899        };
900        write!(
901            f,
902            "fn{}({}) -> {}",
903            tp_str,
904            self.parameters
905                .iter()
906                .map(|p| format!("{}", engines.help_out(p)))
907                .collect::<Vec<_>>()
908                .join(", "),
909            engines.help_out(self.return_type),
910        )
911    }
912}
913
914impl TyFunctionSig {
915    pub fn from_fn_decl(fn_decl: &TyFunctionDecl) -> Self {
916        Self {
917            return_type: fn_decl.return_type.type_id,
918            parameters: fn_decl
919                .parameters
920                .iter()
921                .map(|p| p.type_argument.type_id)
922                .collect::<Vec<_>>(),
923            type_parameters: fn_decl
924                .type_parameters
925                .iter()
926                .map(|x| match x {
927                    TypeParameter::Type(p) => TyFunctionSigTypeParameter::Type(p.type_id),
928                    TypeParameter::Const(p) => {
929                        let expr = ConstGenericExpr::AmbiguousVariableExpression {
930                            ident: p.name.clone(),
931                            decl: None,
932                        };
933                        TyFunctionSigTypeParameter::Const(p.expr.clone().unwrap_or(expr))
934                    }
935                })
936                .collect(),
937        }
938    }
939
940    pub fn is_concrete(&self, engines: &Engines) -> bool {
941        self.return_type
942            .is_concrete(engines, TreatNumericAs::Concrete)
943            && self
944                .parameters
945                .iter()
946                .all(|p| p.is_concrete(engines, TreatNumericAs::Concrete))
947            && self.type_parameters.iter().all(|x| match x {
948                TyFunctionSigTypeParameter::Type(type_id) => {
949                    type_id.is_concrete(engines, TreatNumericAs::Concrete)
950                }
951                TyFunctionSigTypeParameter::Const(expr) => match expr {
952                    ConstGenericExpr::Literal { .. } => true,
953                    ConstGenericExpr::AmbiguousVariableExpression { .. } => false,
954                },
955            })
956    }
957
958    /// Returns a [String] representing the function.
959    /// When the function is monomorphized the returned string is unique.
960    /// Two monomorphized functions that generate the same string can be assumed to be the same.
961    pub fn get_type_str(&self, engines: &Engines) -> String {
962        let tp_str = if self.type_parameters.is_empty() {
963            "".to_string()
964        } else {
965            format!(
966                "<{}>",
967                self.type_parameters
968                    .iter()
969                    .map(|x| match x {
970                        TyFunctionSigTypeParameter::Type(type_id) => type_id.get_type_str(engines),
971                        TyFunctionSigTypeParameter::Const(p) => {
972                            match p {
973                                ConstGenericExpr::Literal { val, .. } => val.to_string(),
974                                ConstGenericExpr::AmbiguousVariableExpression { ident, .. } => {
975                                    ident.as_str().to_string()
976                                }
977                            }
978                        }
979                    })
980                    .collect::<Vec<_>>()
981                    .join(", "),
982            )
983        };
984        format!(
985            "fn{}({}) -> {}",
986            tp_str,
987            self.parameters
988                .iter()
989                .map(|p| p.get_type_str(engines))
990                .collect::<Vec<_>>()
991                .join(", "),
992            self.return_type.get_type_str(engines),
993        )
994    }
995}
996
997// TODO: Investigate and fix the following invalid display:
998//       - `<(Struct) as AbiDecode>::abi_decode(ref mut buffer: BufferReader)`
999//         Note that sometimes it is properly displayed as
1000//         `<Struct as AbiDecode>::abi_decode(ref mut buffer: BufferReader)`
1001
1002// TODO: Investigate why traits are sometimes not displayed with full path, e.g.:
1003//          `<path::Struct as Trait>::trait_method`
1004//       instead of
1005//          `<path::Struct as path::Trait>::trait_method`
1006//        Examples can be found in test:
1007//          should_fail/associated_type_multiple_traits_same_name/test.toml
1008
1009// TODO: Investigate how to better display `Self` type in some edge cases,
1010//       like, e.g., in test:
1011//          should_fail/method_missing_constraint
1012//       It can be that this is not an issue of the type displaying but rather
1013//       the formed error itself.
1014
1015/// Provides a configurable way to display a [TyFunctionDecl].
1016///
1017/// E.g., for a module function `some_function`:
1018/// - `some_function`
1019/// - `some_function(u64, T)`
1020/// - `some_function(u64, T) -> T`
1021/// - `some_pkg::some_module::some_function<T>(arg1: u64, arg2: T) -> T`
1022///
1023/// E.g., for a trait method `some_trait_method`:
1024/// - `some_lib::traits::MyTrait::some_trait_method(self: Self) -> u64`
1025/// - `<some_pkg::some_module::MyStruct<u64, bool> as some_lib::traits::MyTrait>::some_trait_method`
1026#[derive(Debug, Clone, Copy)]
1027pub struct TyFunctionDisplay {
1028    /// E.g., when true:
1029    /// - `SelfType::some_function`, if the function is declared in a trait or self impl.
1030    /// - `Trait::some_function`, or `Abi::some_function`, if it is a provided function.
1031    ///
1032    /// E.g., when false:
1033    /// - `some_function`.
1034    display_self_type: bool,
1035    /// E.g, when true: `<SelfType as Trait>::some_function`.
1036    /// E.g, when false: `SelfType::some_function`.
1037    display_trait: bool,
1038    /// E.g, when true: `some_pkg::some_module::some_module_function`.
1039    /// E.g, when false: `some_module_function`.
1040    display_module_fn_call_path: bool,
1041    /// E.g, when true: `some_function<A, B>`.
1042    /// E.g, when false: `some_function`.
1043    display_fn_type_params: bool,
1044    /// Display the type of the `self` parameter. E.g., `self: MyStruct<u64, bool>`.
1045    /// If false, it will just display `self`, if `display_param_names` is true.
1046    /// If `display_param_names` is false, it will still display the type name,
1047    /// if `display_param_types` is true.
1048    display_self_param_type: bool,
1049    /// E.g, when true: `some_function(ref mut a: u8)`, `some_function(ref mut a)`, or `some_function(ref mut u8)`.
1050    /// E.g, when false: `some_function(a: u8)`, `some_function(a)`, or `some_function(u8)`.
1051    display_ref_mut: bool,
1052    /// E.g, when true: `some_function(a: u8, b: u256)`.
1053    /// E.g, when false: `some_function(u8, u256)`.
1054    display_param_names: bool,
1055    /// E.g, when true: `some_function(a: u8, b: u256)`.
1056    /// E.g, when false: `some_function(a, b)`.
1057    display_param_types: bool,
1058    /// E.g, when true: `some_function -> ReturnType`.
1059    /// E.g, when false: `some_function`.
1060    display_return_type: bool,
1061    /// Defines how to display all of the types:
1062    /// - trait and self type,
1063    /// - type parameters,
1064    /// - self parameter type,
1065    /// - parameter types,
1066    /// - return type.
1067    types_display: TypeInfoDisplay,
1068}
1069
1070impl TyFunctionDisplay {
1071    pub const fn only_name() -> Self {
1072        Self {
1073            display_trait: false,
1074            display_self_type: false,
1075            display_module_fn_call_path: false,
1076            display_fn_type_params: false,
1077            display_self_param_type: false,
1078            display_ref_mut: false,
1079            display_param_names: false,
1080            display_param_types: false,
1081            display_return_type: false,
1082            types_display: TypeInfoDisplay::only_name(),
1083        }
1084    }
1085
1086    pub const fn full() -> Self {
1087        Self {
1088            display_trait: true,
1089            display_self_type: true,
1090            display_module_fn_call_path: true,
1091            display_fn_type_params: true,
1092            display_self_param_type: true,
1093            display_ref_mut: true,
1094            display_param_names: true,
1095            display_param_types: true,
1096            display_return_type: true,
1097            types_display: TypeInfoDisplay::full(),
1098        }
1099    }
1100
1101    pub const fn with_trait(self) -> Self {
1102        Self {
1103            display_trait: true,
1104            ..self
1105        }
1106    }
1107
1108    pub const fn without_trait(self) -> Self {
1109        Self {
1110            display_trait: false,
1111            ..self
1112        }
1113    }
1114
1115    pub const fn with_self_type(self) -> Self {
1116        Self {
1117            display_self_type: true,
1118            ..self
1119        }
1120    }
1121
1122    pub const fn without_self_type(self) -> Self {
1123        Self {
1124            display_self_type: false,
1125            ..self
1126        }
1127    }
1128
1129    pub const fn with_module_fn_call_path(self) -> Self {
1130        Self {
1131            display_module_fn_call_path: true,
1132            ..self
1133        }
1134    }
1135
1136    pub const fn without_module_fn_call_path(self) -> Self {
1137        Self {
1138            display_module_fn_call_path: false,
1139            ..self
1140        }
1141    }
1142
1143    pub const fn with_fn_type_params(self) -> Self {
1144        Self {
1145            display_fn_type_params: true,
1146            ..self
1147        }
1148    }
1149
1150    pub const fn without_fn_type_params(self) -> Self {
1151        Self {
1152            display_fn_type_params: false,
1153            ..self
1154        }
1155    }
1156
1157    pub const fn with_self_param_type(self) -> Self {
1158        Self {
1159            display_self_param_type: true,
1160            ..self
1161        }
1162    }
1163
1164    pub const fn without_self_param_type(self) -> Self {
1165        Self {
1166            display_self_param_type: false,
1167            ..self
1168        }
1169    }
1170
1171    pub const fn with_ref_mut(self) -> Self {
1172        Self {
1173            display_ref_mut: true,
1174            ..self
1175        }
1176    }
1177
1178    pub const fn without_ref_mut(self) -> Self {
1179        Self {
1180            display_ref_mut: false,
1181            ..self
1182        }
1183    }
1184
1185    pub const fn with_param_names(self) -> Self {
1186        Self {
1187            display_param_names: true,
1188            ..self
1189        }
1190    }
1191
1192    pub const fn without_param_names(self) -> Self {
1193        Self {
1194            display_param_names: false,
1195            ..self
1196        }
1197    }
1198
1199    pub const fn with_param_types(self) -> Self {
1200        Self {
1201            display_param_types: true,
1202            ..self
1203        }
1204    }
1205
1206    pub const fn without_param_types(self) -> Self {
1207        Self {
1208            display_param_types: false,
1209            ..self
1210        }
1211    }
1212
1213    pub const fn with_return_type(self) -> Self {
1214        Self {
1215            display_return_type: true,
1216            ..self
1217        }
1218    }
1219
1220    pub const fn without_return_type(self) -> Self {
1221        Self {
1222            display_return_type: false,
1223            ..self
1224        }
1225    }
1226
1227    pub const fn with_types_display(self, types_display: TypeInfoDisplay) -> Self {
1228        Self {
1229            types_display,
1230            ..self
1231        }
1232    }
1233
1234    pub const fn with_signature(self) -> Self {
1235        Self {
1236            display_param_names: true,
1237            display_param_types: true,
1238            display_return_type: true,
1239            ..self
1240        }
1241    }
1242
1243    pub const fn without_signature(self) -> Self {
1244        Self {
1245            display_param_names: false,
1246            display_param_types: false,
1247            display_return_type: false,
1248            ..self
1249        }
1250    }
1251
1252    pub const fn with_parameters(self) -> Self {
1253        Self {
1254            display_param_names: true,
1255            display_param_types: true,
1256            ..self
1257        }
1258    }
1259
1260    pub const fn without_parameters(self) -> Self {
1261        Self {
1262            display_param_names: false,
1263            display_param_types: false,
1264            ..self
1265        }
1266    }
1267
1268    fn should_display_parameters(&self) -> bool {
1269        self.display_param_names || self.display_param_types
1270    }
1271
1272    fn should_display_param_type(&self, param: &TyFunctionParameter) -> bool {
1273        self.display_param_types
1274            && (param.is_self() && self.display_self_param_type || !param.is_self())
1275    }
1276
1277    fn is_module_function(&self, fn_decl: &TyFunctionDecl) -> bool {
1278        fn_decl.implementing_type.is_none() && fn_decl.implementing_for.is_none()
1279    }
1280
1281    /// Quick heuristic to calculate the initial capacity of the [String]
1282    /// used to store the display of the function represented by `fn_decl`.
1283    fn calculate_initial_string_capacity(&self, fn_decl: &TyFunctionDecl) -> usize {
1284        const DEFAULT_TYPE_NAME_LENGTH: usize = 10;
1285        const DEFAULT_CONST_GENERIC_TYPE_PARAM_LENGTH: usize = 2; // E.g., `T`, or `42`.
1286        const DOUBLE_COLON_LENGTH: usize = 2;
1287
1288        let mut capacity = 0;
1289
1290        if (self.display_trait || self.display_self_type) && fn_decl.implementing_type.is_some() {
1291            capacity += DEFAULT_TYPE_NAME_LENGTH + DOUBLE_COLON_LENGTH;
1292        }
1293
1294        capacity += fn_decl.name.as_str().len();
1295        // If it's a module function and we need to display the call path.
1296        if self.display_module_fn_call_path && self.is_module_function(fn_decl) {
1297            capacity += fn_decl.call_path.prefixes.iter().fold(0, |acc, prefix| {
1298                acc + prefix.as_str().len() + DOUBLE_COLON_LENGTH
1299            });
1300        }
1301
1302        if self.display_fn_type_params && !fn_decl.type_parameters.is_empty() {
1303            capacity += 2; // For angle brackets.
1304            capacity += fn_decl.type_parameters.iter().fold(0, |acc, tp| {
1305                acc + match tp {
1306                    TypeParameter::Type(_) => DEFAULT_TYPE_NAME_LENGTH,
1307                    TypeParameter::Const(_) => DEFAULT_CONST_GENERIC_TYPE_PARAM_LENGTH,
1308                } + 2 // For the type parameter name and the comma.
1309            });
1310        }
1311
1312        if self.should_display_parameters() {
1313            capacity += 2; // For parentheses.
1314
1315            fn_decl.parameters.iter().for_each(|param| {
1316                if self.display_param_names {
1317                    capacity += param.name.as_str().len();
1318                    if self.should_display_param_type(param) {
1319                        capacity += 2; // For the colon and space `: `.
1320                    }
1321                }
1322                if self.should_display_param_type(param) {
1323                    capacity += DEFAULT_TYPE_NAME_LENGTH;
1324                }
1325
1326                capacity += 2; // For the comma and space `, `.
1327            });
1328
1329            if !fn_decl.parameters.is_empty() {
1330                capacity -= 2; // Remove the last comma and space `, `.
1331            }
1332        }
1333
1334        if self.display_return_type {
1335            capacity += 4; // For the ` -> `.
1336            capacity += DEFAULT_TYPE_NAME_LENGTH;
1337        }
1338
1339        capacity
1340    }
1341
1342    pub fn display(&self, fn_decl: &TyFunctionDecl, engines: &Engines) -> String {
1343        let mut result = String::with_capacity(self.calculate_initial_string_capacity(fn_decl));
1344
1345        // Append call path to module function, or self type and trait type to members,
1346        // if configured so.
1347        if self.display_module_fn_call_path && self.is_module_function(fn_decl) {
1348            // TODO: Remove this workaround once https://github.com/FuelLabs/sway/issues/7304 is fixed
1349            //       and uncomment the original code below.
1350            if let Some((first_prefix, rest_prefixes)) = fn_decl.call_path.prefixes.split_first() {
1351                let first_prefix = if !first_prefix.as_str().contains('-') {
1352                    first_prefix.as_str()
1353                } else {
1354                    &first_prefix.as_str().replace('-', "_")
1355                };
1356                result.push_str(first_prefix);
1357                result.push_str("::");
1358                for prefix in rest_prefixes {
1359                    result.push_str(prefix.as_str());
1360                    result.push_str("::");
1361                }
1362            }
1363
1364            // fn_decl.call_path.prefixes.iter().for_each(|prefix| {
1365            //     result.push_str(prefix.as_str());
1366            //     result.push_str("::");
1367            // });
1368        } else if self.display_self_type || self.display_trait {
1369            match fn_decl.implementing_type.as_ref() {
1370                Some(TyDecl::TraitDecl(trait_decl)) if self.display_self_type => {
1371                    // The function is a provided trait function, so in the context of displaying,
1372                    // we treat the trait as the self type.
1373                    let trait_decl = engines.de().get_trait(&trait_decl.decl_id);
1374                    self.display_udt_decl_into(
1375                        &trait_decl.call_path,
1376                        Either::Left(&trait_decl.type_parameters),
1377                        engines,
1378                        &mut result,
1379                    );
1380                    result.push_str("::");
1381                }
1382                Some(TyDecl::AbiDecl(abi_decl)) if self.display_self_type => {
1383                    // The function is a provided ABI function, so in the context of displaying,
1384                    // we treat the ABI as the self type.
1385                    let abi_decl = engines.de().get_abi(&abi_decl.decl_id);
1386                    // TODO: Add call path support for `TyAbiDecl`. Currently, it contains only the name.
1387                    //       When done, call `self.display_udt_decl_into` here, with empty type parameters.
1388                    result.push_str(abi_decl.name.as_str());
1389                    result.push_str("::");
1390                }
1391                Some(TyDecl::ImplSelfOrTrait(impl_self_or_trait_decl)) => {
1392                    let impl_self_or_trait_decl = engines
1393                        .de()
1394                        .get_impl_self_or_trait(&impl_self_or_trait_decl.decl_id);
1395                    let self_type = if self.display_self_type {
1396                        let implementing_for = match fn_decl.implementing_for {
1397                            Some(implementing_for) => engines.te().get(implementing_for),
1398                            None => {
1399                                // No implementing for provided, as a fallback we use the one
1400                                // from the `impl_self_or_trait_decl`.
1401                                engines
1402                                    .te()
1403                                    .get(impl_self_or_trait_decl.implementing_for.type_id)
1404                            }
1405                        };
1406                        Some(
1407                            self.types_display
1408                                .display(&implementing_for, engines)
1409                                .to_string(),
1410                        )
1411                    } else {
1412                        None
1413                    };
1414                    let trait_type = if self.display_trait {
1415                        impl_self_or_trait_decl
1416                            .as_ref()
1417                            .trait_decl_ref
1418                            .as_ref()
1419                            .map(|trait_or_abi_decl| {
1420                                match trait_or_abi_decl.id() {
1421                                    InterfaceDeclId::Abi(decl_id) => {
1422                                        let abi_decl = engines.de().get_abi(decl_id);
1423                                        abi_decl.name.to_string()
1424                                    }
1425                                    InterfaceDeclId::Trait(decl_id) => {
1426                                        let trait_decl = engines.de().get_trait(decl_id);
1427                                        // Take the trait call path from the declaration,
1428                                        // and the actual parameters from the impl.
1429                                        self.display_udt_decl(
1430                                            &trait_decl.call_path,
1431                                            Either::Right(
1432                                                &impl_self_or_trait_decl.trait_type_arguments,
1433                                            ),
1434                                            engines,
1435                                        )
1436                                    }
1437                                }
1438                            })
1439                    } else {
1440                        None
1441                    };
1442
1443                    match (self_type, trait_type) {
1444                        (None, None) => {}
1445                        (None, Some(type_name)) | (Some(type_name), None) => {
1446                            result.push_str(&type_name);
1447                            result.push_str("::");
1448                        }
1449                        (Some(self_type), Some(trait_type)) => {
1450                            result.push('<');
1451                            result.push_str(&self_type);
1452                            result.push_str(" as ");
1453                            result.push_str(&trait_type);
1454                            result.push('>');
1455                            result.push_str("::");
1456                        }
1457                    }
1458                }
1459                _ => {
1460                    if let Some(implementing_for) = fn_decl.implementing_for {
1461                        let implementing_for = engines.te().get(implementing_for);
1462                        result.push_str(&self.types_display.display(&implementing_for, engines));
1463                        result.push_str("::");
1464                    }
1465                }
1466            }
1467        }
1468
1469        // Always append function name.
1470        result.push_str(fn_decl.name.as_str());
1471
1472        // Append function parameters, if configured so.
1473        if self.should_display_parameters() {
1474            result.push('(');
1475
1476            fn_decl.parameters.iter().for_each(|param| {
1477                if self.display_ref_mut && param.is_mutable && param.is_reference {
1478                    result.push_str("ref mut ");
1479                }
1480                if self.display_param_names {
1481                    result.push_str(param.name.as_str());
1482                    if self.should_display_param_type(param) {
1483                        result.push_str(": ");
1484                    }
1485                }
1486                if self.should_display_param_type(param) {
1487                    let param_type = engines.te().get(param.type_argument.type_id);
1488                    result.push_str(&self.types_display.display(&param_type, engines));
1489                }
1490
1491                result.push_str(", ");
1492            });
1493
1494            // Remove trailing comma and space if present.
1495            result.truncate(result.rfind(',').unwrap_or(result.len()));
1496
1497            result.push(')');
1498        }
1499
1500        // Append return type, if configured so.
1501        if self.display_return_type {
1502            result.push_str(" -> ");
1503            let return_type = engines.te().get(fn_decl.return_type.type_id);
1504            result.push_str(&self.types_display.display(&return_type, engines));
1505        }
1506
1507        result
1508    }
1509
1510    fn display_udt_decl(
1511        &self,
1512        udt_name: &CallPath,
1513        type_params: Either<&[TypeParameter], &[GenericArgument]>,
1514        engines: &Engines,
1515    ) -> String {
1516        let capacity = udt_name.suffix.as_str().len()
1517            + if self.types_display.display_call_paths {
1518                udt_name
1519                    .prefixes
1520                    .iter()
1521                    .map(|p| p.as_str().len())
1522                    .sum::<usize>()
1523            } else {
1524                0
1525            };
1526
1527        let mut dest = String::with_capacity(capacity);
1528        self.display_udt_decl_into(udt_name, type_params, engines, &mut dest);
1529        dest
1530    }
1531
1532    /// Displays a user-defined type (UDT) declaration into the `dest`.
1533    /// UDTs are: traits, ABIs, structs, enums, and type aliases.
1534    fn display_udt_decl_into(
1535        &self,
1536        udt_name: &CallPath,
1537        type_params: Either<&[TypeParameter], &[GenericArgument]>,
1538        engines: &Engines,
1539        dest: &mut String,
1540    ) {
1541        if self.types_display.display_call_paths {
1542            dest.push_str(&udt_name.to_string());
1543        } else {
1544            dest.push_str(udt_name.suffix.as_str());
1545        }
1546
1547        match type_params {
1548            Either::Left(type_params) => {
1549                if !type_params.is_empty() {
1550                    dest.push_str(
1551                        &self
1552                            .types_display
1553                            .display_non_empty_type_params(type_params, engines),
1554                    );
1555                }
1556            }
1557            Either::Right(generic_args) => {
1558                if !generic_args.is_empty() {
1559                    dest.push_str(
1560                        &self
1561                            .types_display
1562                            .display_non_empty_generic_args(generic_args, engines),
1563                    );
1564                }
1565            }
1566        }
1567    }
1568}