sway_core/language/ty/declaration/
function.rs

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