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 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 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 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 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 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 pub(crate) fn parameters_span(&self) -> Span {
454 if !self.parameters.is_empty() {
455 self.parameters.iter().fold(
456 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 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 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 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 pub fn is_test(&self) -> bool {
530 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 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 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 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 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}