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