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 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 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 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 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 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 pub(crate) fn parameters_span(&self) -> Span {
465 if !self.parameters.is_empty() {
466 self.parameters.iter().fold(
467 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 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 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 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 pub fn is_test(&self) -> bool {
541 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 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 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 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 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}