sway_core/language/ty/declaration/
function.rs

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