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