sway_core/language/ty/declaration/
function.rs

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