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