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