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