Skip to main content

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