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