sway_core/language/ty/declaration/
function.rs

1use crate::{
2    decl_engine::*,
3    engine_threading::*,
4    has_changes,
5    language::{
6        parsed::{self, FunctionDeclaration, FunctionDeclarationKind},
7        ty::*,
8        CallPath, Inline, Purity, Visibility,
9    },
10    semantic_analysis::TypeCheckContext,
11    transform::{self, AttributeKind},
12    type_system::*,
13    types::*,
14};
15use ast_elements::type_parameter::ConstGenericExpr;
16use monomorphization::MonomorphizeHelper;
17use serde::{Deserialize, Serialize};
18use sha2::{Digest, Sha256};
19use std::{
20    collections::BTreeMap,
21    fmt,
22    hash::{Hash, Hasher},
23};
24use sway_error::handler::{ErrorEmitted, Handler};
25use sway_types::{Ident, Named, Span, Spanned};
26
27#[derive(Clone, Debug, Serialize, Deserialize)]
28pub enum TyFunctionDeclKind {
29    Default,
30    Entry,
31    Main,
32    Test,
33}
34
35#[derive(Clone, Debug, Serialize, Deserialize)]
36pub struct TyFunctionDecl {
37    pub name: Ident,
38    pub body: TyCodeBlock,
39    pub parameters: Vec<TyFunctionParameter>,
40    pub implementing_type: Option<TyDecl>,
41    pub implementing_for_typeid: Option<TypeId>,
42    pub span: Span,
43    pub call_path: CallPath,
44    pub attributes: transform::Attributes,
45    pub type_parameters: Vec<TypeParameter>,
46    pub return_type: GenericArgument,
47    pub visibility: Visibility,
48    /// whether this function exists in another contract and requires a call to it or not
49    pub is_contract_call: bool,
50    pub purity: Purity,
51    pub where_clause: Vec<(Ident, Vec<TraitConstraint>)>,
52    pub is_trait_method_dummy: bool,
53    pub is_type_check_finalized: bool,
54    pub kind: TyFunctionDeclKind,
55}
56
57impl TyDeclParsedType for TyFunctionDecl {
58    type ParsedType = FunctionDeclaration;
59}
60
61impl DebugWithEngines for TyFunctionDecl {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
63        write!(
64            f,
65            "{}{:?}{}({}):{}->{}",
66            if self.is_trait_method_dummy {
67                "dummy ".to_string()
68            } else {
69                "".to_string()
70            },
71            self.name,
72            if !self.type_parameters.is_empty() {
73                format!(
74                    "<{}>",
75                    self.type_parameters
76                        .iter()
77                        .map(|p| {
78                            match p {
79                                TypeParameter::Type(p) => {
80                                    format!(
81                                        "{:?} -> {:?}",
82                                        engines.help_out(p.initial_type_id),
83                                        engines.help_out(p.type_id)
84                                    )
85                                }
86                                TypeParameter::Const(p) => {
87                                    format!("{} -> {:?}", p.name, p.expr)
88                                }
89                            }
90                        })
91                        .collect::<Vec<_>>()
92                        .join(", ")
93                )
94            } else {
95                "".to_string()
96            },
97            self.parameters
98                .iter()
99                .map(|p| format!(
100                    "{}:{} -> {}",
101                    p.name.as_str(),
102                    engines.help_out(p.type_argument.initial_type_id()),
103                    engines.help_out(p.type_argument.type_id())
104                ))
105                .collect::<Vec<_>>()
106                .join(", "),
107            engines.help_out(self.return_type.initial_type_id()),
108            engines.help_out(self.return_type.type_id()),
109        )
110    }
111}
112
113impl DisplayWithEngines for TyFunctionDecl {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
115        write!(
116            f,
117            "{}{}({}) -> {}",
118            self.name,
119            if !self.type_parameters.is_empty() {
120                format!(
121                    "<{}>",
122                    self.type_parameters
123                        .iter()
124                        .map(|p| {
125                            let p = p
126                                .as_type_parameter()
127                                .expect("only works for type parameters");
128                            format!("{}", engines.help_out(p.initial_type_id))
129                        })
130                        .collect::<Vec<_>>()
131                        .join(", ")
132                )
133            } else {
134                "".to_string()
135            },
136            self.parameters
137                .iter()
138                .map(|p| format!(
139                    "{}: {}",
140                    p.name.as_str(),
141                    engines.help_out(p.type_argument.initial_type_id())
142                ))
143                .collect::<Vec<_>>()
144                .join(", "),
145            engines.help_out(self.return_type.initial_type_id()),
146        )
147    }
148}
149
150impl MaterializeConstGenerics for TyFunctionDecl {
151    fn materialize_const_generics(
152        &mut self,
153        engines: &Engines,
154        handler: &Handler,
155        name: &str,
156        value: &TyExpression,
157    ) -> Result<(), ErrorEmitted> {
158        for tp in self.type_parameters.iter_mut() {
159            match tp {
160                TypeParameter::Type(p) => p
161                    .type_id
162                    .materialize_const_generics(engines, handler, name, value)?,
163                TypeParameter::Const(p) if p.name.as_str() == name => {
164                    assert!(p.expr.is_none());
165                    p.expr = Some(ConstGenericExpr::from_ty_expression(handler, value)?);
166                }
167                _ => {}
168            }
169        }
170
171        for param in self.parameters.iter_mut() {
172            param
173                .type_argument
174                .type_id_mut()
175                .materialize_const_generics(engines, handler, name, value)?;
176        }
177        self.return_type
178            .type_id_mut()
179            .materialize_const_generics(engines, handler, name, value)?;
180        self.body
181            .materialize_const_generics(engines, handler, name, value)
182    }
183}
184
185impl DeclRefFunction {
186    /// Makes method with a copy of type_id.
187    /// This avoids altering the type_id already in the type map.
188    /// Without this it is possible to retrieve a method from the type map unify its types and
189    /// the second time it won't be possible to retrieve the same method.
190    pub fn get_method_safe_to_unify(&self, engines: &Engines, type_id: TypeId) -> Self {
191        let decl_engine = engines.de();
192
193        let mut method = (*decl_engine.get_function(self)).clone();
194
195        if let Some(method_implementing_for_typeid) = method.implementing_for_typeid {
196            let mut type_id_type_subst_map = TypeSubstMap::new();
197
198            if let Some(TyDecl::ImplSelfOrTrait(t)) = &method.implementing_type {
199                let impl_self_or_trait = &*engines.de().get(&t.decl_id);
200
201                let mut type_id_type_parameters = vec![];
202                let mut const_generic_parameters = BTreeMap::default();
203                type_id.extract_type_parameters(
204                    engines,
205                    0,
206                    &mut type_id_type_parameters,
207                    &mut const_generic_parameters,
208                    impl_self_or_trait.implementing_for.type_id(),
209                );
210
211                type_id_type_subst_map
212                    .const_generics_materialization
213                    .append(&mut const_generic_parameters);
214
215                for p in impl_self_or_trait
216                    .impl_type_parameters
217                    .iter()
218                    .filter_map(|x| x.as_type_parameter())
219                {
220                    let matches = type_id_type_parameters
221                        .iter()
222                        .filter(|(_, orig_tp)| {
223                            engines.te().get(*orig_tp).eq(
224                                &*engines.te().get(p.type_id),
225                                &PartialEqWithEnginesContext::new(engines),
226                            )
227                        })
228                        .collect::<Vec<_>>();
229
230                    if !matches.is_empty() {
231                        // Adds type substitution for first match only as we can apply only one.
232                        type_id_type_subst_map.insert(p.type_id, matches[0].0);
233                    } else if engines
234                        .te()
235                        .get(impl_self_or_trait.implementing_for.initial_type_id())
236                        .eq(
237                            &*engines.te().get(p.initial_type_id),
238                            &PartialEqWithEnginesContext::new(engines),
239                        )
240                    {
241                        type_id_type_subst_map.insert(p.type_id, type_id);
242                    }
243                }
244            }
245
246            let mut method_type_subst_map = TypeSubstMap::new();
247            method_type_subst_map.extend(&type_id_type_subst_map);
248            method_type_subst_map.insert(method_implementing_for_typeid, type_id);
249
250            method.subst(&SubstTypesContext::new(
251                engines,
252                &method_type_subst_map,
253                true,
254            ));
255
256            return engines
257                .de()
258                .insert(
259                    method.clone(),
260                    engines.de().get_parsed_decl_id(self.id()).as_ref(),
261                )
262                .with_parent(decl_engine, self.id().into());
263        }
264
265        self.clone()
266    }
267}
268
269impl Named for TyFunctionDecl {
270    fn name(&self) -> &Ident {
271        &self.name
272    }
273}
274
275impl IsConcrete for TyFunctionDecl {
276    fn is_concrete(&self, engines: &Engines) -> bool {
277        self.type_parameters
278            .iter()
279            .all(|tp| tp.is_concrete(engines))
280            && self
281                .return_type
282                .type_id()
283                .is_concrete(engines, TreatNumericAs::Concrete)
284            && self.parameters().iter().all(|t| {
285                t.type_argument
286                    .type_id()
287                    .is_concrete(engines, TreatNumericAs::Concrete)
288            })
289    }
290}
291impl declaration::FunctionSignature for TyFunctionDecl {
292    fn parameters(&self) -> &Vec<TyFunctionParameter> {
293        &self.parameters
294    }
295
296    fn return_type(&self) -> &GenericArgument {
297        &self.return_type
298    }
299}
300
301impl EqWithEngines for TyFunctionDecl {}
302impl PartialEqWithEngines for TyFunctionDecl {
303    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
304        self.name == other.name
305            && self.body.eq(&other.body, ctx)
306            && self.parameters.eq(&other.parameters, ctx)
307            && self.return_type.eq(&other.return_type, ctx)
308            && self.type_parameters.eq(&other.type_parameters, ctx)
309            && self.visibility == other.visibility
310            && self.is_contract_call == other.is_contract_call
311            && self.purity == other.purity
312    }
313}
314
315impl HashWithEngines for TyFunctionDecl {
316    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
317        let TyFunctionDecl {
318            name,
319            body,
320            parameters,
321            return_type,
322            type_parameters,
323            visibility,
324            is_contract_call,
325            purity,
326            // these fields are not hashed because they aren't relevant/a
327            // reliable source of obj v. obj distinction
328            call_path: _,
329            span: _,
330            attributes: _,
331            implementing_type: _,
332            implementing_for_typeid: _,
333            where_clause: _,
334            is_trait_method_dummy: _,
335            is_type_check_finalized: _,
336            kind: _,
337        } = self;
338        name.hash(state);
339        body.hash(state, engines);
340        parameters.hash(state, engines);
341        return_type.hash(state, engines);
342        type_parameters.hash(state, engines);
343        visibility.hash(state);
344        is_contract_call.hash(state);
345        purity.hash(state);
346    }
347}
348
349impl SubstTypes for TyFunctionDecl {
350    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
351        let changes = if ctx.subst_function_body {
352            has_changes! {
353                self.type_parameters.subst(ctx);
354                self.parameters.subst(ctx);
355                self.return_type.subst(ctx);
356                self.body.subst(ctx);
357                self.implementing_for_typeid.subst(ctx);
358            }
359        } else {
360            has_changes! {
361                self.type_parameters.subst(ctx);
362                self.parameters.subst(ctx);
363                self.return_type.subst(ctx);
364                self.implementing_for_typeid.subst(ctx);
365            }
366        };
367
368        if let Some(map) = ctx.type_subst_map.as_ref() {
369            let handler = Handler::default();
370            for (name, value) in &map.const_generics_materialization {
371                let _ = self.materialize_const_generics(ctx.engines, &handler, name, value);
372            }
373            HasChanges::Yes
374        } else {
375            changes
376        }
377    }
378}
379
380impl ReplaceDecls for TyFunctionDecl {
381    fn replace_decls_inner(
382        &mut self,
383        decl_mapping: &DeclMapping,
384        handler: &Handler,
385        ctx: &mut TypeCheckContext,
386    ) -> Result<bool, ErrorEmitted> {
387        let mut func_ctx = ctx.by_ref().with_self_type(self.implementing_for_typeid);
388        self.body
389            .replace_decls(decl_mapping, handler, &mut func_ctx)
390    }
391}
392
393impl Spanned for TyFunctionDecl {
394    fn span(&self) -> Span {
395        self.span.clone()
396    }
397}
398
399impl MonomorphizeHelper for TyFunctionDecl {
400    fn type_parameters(&self) -> &[TypeParameter] {
401        &self.type_parameters
402    }
403
404    fn name(&self) -> &Ident {
405        &self.name
406    }
407
408    fn has_self_type_param(&self) -> bool {
409        false
410    }
411}
412
413impl CollectTypesMetadata for TyFunctionDecl {
414    fn collect_types_metadata(
415        &self,
416        handler: &Handler,
417        ctx: &mut CollectTypesMetadataContext,
418    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
419        let mut body = vec![];
420        for content in self.body.contents.iter() {
421            body.append(&mut content.collect_types_metadata(handler, ctx)?);
422        }
423        body.append(
424            &mut self
425                .return_type
426                .type_id()
427                .collect_types_metadata(handler, ctx)?,
428        );
429        for p in self.type_parameters.iter() {
430            let p = p
431                .as_type_parameter()
432                .expect("only works for type parameters");
433            body.append(&mut p.type_id.collect_types_metadata(handler, ctx)?);
434        }
435        for param in self.parameters.iter() {
436            body.append(
437                &mut param
438                    .type_argument
439                    .type_id()
440                    .collect_types_metadata(handler, ctx)?,
441            );
442        }
443        Ok(body)
444    }
445}
446
447impl TyFunctionDecl {
448    pub(crate) fn set_implementing_type(&mut self, decl: TyDecl) {
449        self.implementing_type = Some(decl);
450    }
451
452    /// Used to create a stubbed out function when the function fails to
453    /// compile, preventing cascading namespace errors.
454    pub(crate) fn error(decl: &parsed::FunctionDeclaration) -> TyFunctionDecl {
455        let parsed::FunctionDeclaration {
456            name,
457            return_type,
458            span,
459            visibility,
460            purity,
461            where_clause,
462            kind,
463            ..
464        } = decl;
465        TyFunctionDecl {
466            purity: *purity,
467            name: name.clone(),
468            body: <_>::default(),
469            implementing_type: None,
470            implementing_for_typeid: None,
471            span: span.clone(),
472            call_path: CallPath::from(Ident::dummy()),
473            attributes: Default::default(),
474            is_contract_call: false,
475            parameters: Default::default(),
476            visibility: *visibility,
477            return_type: return_type.clone(),
478            type_parameters: Default::default(),
479            where_clause: where_clause.clone(),
480            is_trait_method_dummy: false,
481            is_type_check_finalized: true,
482            kind: match kind {
483                FunctionDeclarationKind::Default => TyFunctionDeclKind::Default,
484                FunctionDeclarationKind::Entry => TyFunctionDeclKind::Entry,
485                FunctionDeclarationKind::Test => TyFunctionDeclKind::Test,
486                FunctionDeclarationKind::Main => TyFunctionDeclKind::Main,
487            },
488        }
489    }
490
491    /// If there are parameters, join their spans. Otherwise, use the fn name span.
492    pub(crate) fn parameters_span(&self) -> Span {
493        if !self.parameters.is_empty() {
494            self.parameters.iter().fold(
495                // TODO: Use Span::join_all().
496                self.parameters[0].name.span(),
497                |acc, TyFunctionParameter { type_argument, .. }| {
498                    Span::join(acc, &type_argument.span())
499                },
500            )
501        } else {
502            self.name.span()
503        }
504    }
505
506    pub fn to_fn_selector_value_untruncated(
507        &self,
508        handler: &Handler,
509        engines: &Engines,
510    ) -> Result<Vec<u8>, ErrorEmitted> {
511        let mut hasher = Sha256::new();
512        let data = self.to_selector_name(handler, engines)?;
513        hasher.update(data);
514        let hash = hasher.finalize();
515        Ok(hash.to_vec())
516    }
517
518    /// Converts a [TyFunctionDecl] into a value that is to be used in contract function
519    /// selectors.
520    /// Hashes the name and parameters using SHA256, and then truncates to four bytes.
521    pub fn to_fn_selector_value(
522        &self,
523        handler: &Handler,
524        engines: &Engines,
525    ) -> Result<[u8; 4], ErrorEmitted> {
526        let hash = self.to_fn_selector_value_untruncated(handler, engines)?;
527        // 4 bytes truncation via copying into a 4 byte buffer
528        let mut buf = [0u8; 4];
529        buf.copy_from_slice(&hash[..4]);
530        Ok(buf)
531    }
532
533    pub fn to_selector_name(
534        &self,
535        handler: &Handler,
536        engines: &Engines,
537    ) -> Result<String, ErrorEmitted> {
538        let named_params = self
539            .parameters
540            .iter()
541            .map(|TyFunctionParameter { type_argument, .. }| {
542                engines
543                    .te()
544                    .to_typeinfo(type_argument.type_id(), &type_argument.span())
545                    .expect("unreachable I think?")
546                    .to_selector_name(handler, engines, &type_argument.span())
547            })
548            .filter_map(|name| name.ok())
549            .collect::<Vec<String>>();
550
551        Ok(format!(
552            "{}({})",
553            self.name.as_str(),
554            named_params.join(","),
555        ))
556    }
557
558    /// Whether or not this function is the default entry point.
559    pub fn is_entry(&self) -> bool {
560        matches!(self.kind, TyFunctionDeclKind::Entry)
561    }
562
563    pub fn is_main(&self) -> bool {
564        matches!(self.kind, TyFunctionDeclKind::Main)
565    }
566
567    /// Whether or not this function is a unit test, i.e. decorated with `#[test]`.
568    pub fn is_test(&self) -> bool {
569        //TODO match kind to Test
570        self.attributes.has_any_of_kind(AttributeKind::Test)
571    }
572
573    pub fn inline(&self) -> Option<Inline> {
574        self.attributes.inline()
575    }
576
577    pub fn is_fallback(&self) -> bool {
578        self.attributes.has_any_of_kind(AttributeKind::Fallback)
579    }
580
581    /// Whether or not this function is a constructor for the type given by `type_id`.
582    ///
583    /// Returns `Some(true)` if the function is surely the constructor and `Some(false)` if
584    /// it is surely not a constructor, and `None` if it cannot decide.
585    pub fn is_constructor(&self, engines: &Engines, type_id: TypeId) -> Option<bool> {
586        if self
587            .parameters
588            .first()
589            .map(|param| param.is_self())
590            .unwrap_or_default()
591        {
592            return Some(false);
593        };
594
595        match &self.implementing_type {
596            Some(TyDecl::ImplSelfOrTrait(t)) => {
597                let unify_check = UnifyCheck::non_dynamic_equality(engines);
598
599                let implementing_for = engines.de().get(&t.decl_id).implementing_for.type_id();
600
601                // TODO: Implement the check in detail for all possible cases (e.g. trait impls for generics etc.)
602                //       and return just the definite `bool` and not `Option<bool>`.
603                //       That would be too much effort at the moment for the immediate practical need of
604                //       error reporting where we suggest obvious most common constructors
605                //       that will be found using this simple check.
606                if unify_check.check(type_id, implementing_for)
607                    && unify_check.check(type_id, self.return_type.type_id())
608                {
609                    Some(true)
610                } else {
611                    None
612                }
613            }
614            _ => Some(false),
615        }
616    }
617
618    pub fn is_from_blanket_impl(&self, engines: &Engines) -> bool {
619        if let Some(TyDecl::ImplSelfOrTrait(existing_impl_trait)) = self.implementing_type.clone() {
620            let existing_trait_decl = engines
621                .de()
622                .get_impl_self_or_trait(&existing_impl_trait.decl_id);
623            if !existing_trait_decl.impl_type_parameters.is_empty()
624                && matches!(
625                    *engines
626                        .te()
627                        .get(existing_trait_decl.implementing_for.type_id()),
628                    TypeInfo::UnknownGeneric { .. }
629                )
630            {
631                return true;
632            }
633        }
634        false
635    }
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
639pub struct TyFunctionParameter {
640    pub name: Ident,
641    pub is_reference: bool,
642    pub is_mutable: bool,
643    pub mutability_span: Span,
644    pub type_argument: GenericArgument,
645}
646
647impl EqWithEngines for TyFunctionParameter {}
648impl PartialEqWithEngines for TyFunctionParameter {
649    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
650        self.name == other.name
651            && self.type_argument.eq(&other.type_argument, ctx)
652            && self.is_reference == other.is_reference
653            && self.is_mutable == other.is_mutable
654    }
655}
656
657impl HashWithEngines for TyFunctionParameter {
658    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
659        let TyFunctionParameter {
660            name,
661            is_reference,
662            is_mutable,
663            type_argument,
664            // these fields are not hashed because they aren't relevant/a
665            // reliable source of obj v. obj distinction
666            mutability_span: _,
667        } = self;
668        name.hash(state);
669        type_argument.hash(state, engines);
670        is_reference.hash(state);
671        is_mutable.hash(state);
672    }
673}
674
675impl SubstTypes for TyFunctionParameter {
676    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
677        self.type_argument.type_id_mut().subst(ctx)
678    }
679}
680
681impl TyFunctionParameter {
682    pub fn is_self(&self) -> bool {
683        self.name.as_str() == "self"
684    }
685}
686
687#[derive(Clone, Debug, PartialEq, Eq, Hash)]
688pub enum TyFunctionSigTypeParameter {
689    Type(TypeId),
690    Const(ConstGenericExpr),
691}
692
693#[derive(Clone, Debug, PartialEq, Eq, Hash)]
694pub struct TyFunctionSig {
695    pub return_type: TypeId,
696    pub parameters: Vec<TypeId>,
697    pub type_parameters: Vec<TyFunctionSigTypeParameter>,
698}
699
700impl DisplayWithEngines for TyFunctionSig {
701    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
702        write!(f, "{:?}", engines.help_out(self))
703    }
704}
705
706impl DebugWithEngines for TyFunctionSig {
707    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
708        let tp_str = if self.type_parameters.is_empty() {
709            "".to_string()
710        } else {
711            format!(
712                "<{}>",
713                self.type_parameters
714                    .iter()
715                    .map(|p| match p {
716                        TyFunctionSigTypeParameter::Type(t) => format!("{:?}", engines.help_out(t)),
717                        TyFunctionSigTypeParameter::Const(expr) =>
718                            format!("{:?}", engines.help_out(expr)),
719                    })
720                    .collect::<Vec<_>>()
721                    .join(", "),
722            )
723        };
724        write!(
725            f,
726            "fn{}({}) -> {}",
727            tp_str,
728            self.parameters
729                .iter()
730                .map(|p| format!("{}", engines.help_out(p)))
731                .collect::<Vec<_>>()
732                .join(", "),
733            engines.help_out(self.return_type),
734        )
735    }
736}
737
738impl TyFunctionSig {
739    pub fn from_fn_decl(fn_decl: &TyFunctionDecl) -> Self {
740        Self {
741            return_type: fn_decl.return_type.type_id(),
742            parameters: fn_decl
743                .parameters
744                .iter()
745                .map(|p| p.type_argument.type_id())
746                .collect::<Vec<_>>(),
747            type_parameters: fn_decl
748                .type_parameters
749                .iter()
750                .map(|x| match x {
751                    TypeParameter::Type(p) => TyFunctionSigTypeParameter::Type(p.type_id),
752                    TypeParameter::Const(p) => {
753                        let expr = ConstGenericExpr::AmbiguousVariableExpression {
754                            ident: p.name.clone(),
755                        };
756                        TyFunctionSigTypeParameter::Const(p.expr.clone().unwrap_or(expr))
757                    }
758                })
759                .collect(),
760        }
761    }
762
763    pub fn is_concrete(&self, engines: &Engines) -> bool {
764        self.return_type
765            .is_concrete(engines, TreatNumericAs::Concrete)
766            && self
767                .parameters
768                .iter()
769                .all(|p| p.is_concrete(engines, TreatNumericAs::Concrete))
770            && self
771                .type_parameters
772                .iter()
773                .filter_map(|x| match x {
774                    TyFunctionSigTypeParameter::Type(type_id) => Some(type_id),
775                    TyFunctionSigTypeParameter::Const(_) => None,
776                })
777                .all(|type_id| type_id.is_concrete(engines, TreatNumericAs::Concrete))
778    }
779
780    /// Returns a String representing the function.
781    /// When the function is monomorphized the returned String is unique.
782    /// Two monomorphized functions that generate the same String can be assumed to be the same.
783    pub fn get_type_str(&self, engines: &Engines) -> String {
784        let tp_str = if self.type_parameters.is_empty() {
785            "".to_string()
786        } else {
787            format!(
788                "<{}>",
789                self.type_parameters
790                    .iter()
791                    .map(|x| match x {
792                        TyFunctionSigTypeParameter::Type(type_id) => type_id.get_type_str(engines),
793                        TyFunctionSigTypeParameter::Const(p) => {
794                            match p {
795                                ConstGenericExpr::Literal { val, .. } => val.to_string(),
796                                ConstGenericExpr::AmbiguousVariableExpression { .. } => todo!(),
797                            }
798                        }
799                    })
800                    .collect::<Vec<_>>()
801                    .join(", "),
802            )
803        };
804        format!(
805            "fn{}({}) -> {}",
806            tp_str,
807            self.parameters
808                .iter()
809                .map(|p| p.get_type_str(engines))
810                .collect::<Vec<_>>()
811                .join(", "),
812            self.return_type.get_type_str(engines),
813        )
814    }
815}