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 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 mut method = (*decl_engine.get_function(self)).clone();
194
195 if let Some(method_implementing_for_typeid) = method.implementing_for_typeid {
196 let mut type_id_type_subst_map = TypeSubstMap::new();
197
198 if let Some(TyDecl::ImplSelfOrTrait(t)) = &method.implementing_type {
199 let impl_self_or_trait = &*engines.de().get(&t.decl_id);
200
201 let mut type_id_type_parameters = vec![];
202 let mut const_generic_parameters = BTreeMap::default();
203 type_id.extract_type_parameters(
204 engines,
205 0,
206 &mut type_id_type_parameters,
207 &mut const_generic_parameters,
208 impl_self_or_trait.implementing_for.type_id(),
209 );
210
211 type_id_type_subst_map
212 .const_generics_materialization
213 .append(&mut const_generic_parameters);
214
215 for p in impl_self_or_trait
216 .impl_type_parameters
217 .iter()
218 .filter_map(|x| x.as_type_parameter())
219 {
220 let matches = type_id_type_parameters
221 .iter()
222 .filter(|(_, orig_tp)| {
223 engines.te().get(*orig_tp).eq(
224 &*engines.te().get(p.type_id),
225 &PartialEqWithEnginesContext::new(engines),
226 )
227 })
228 .collect::<Vec<_>>();
229
230 if !matches.is_empty() {
231 type_id_type_subst_map.insert(p.type_id, matches[0].0);
233 } else if engines
234 .te()
235 .get(impl_self_or_trait.implementing_for.initial_type_id())
236 .eq(
237 &*engines.te().get(p.initial_type_id),
238 &PartialEqWithEnginesContext::new(engines),
239 )
240 {
241 type_id_type_subst_map.insert(p.type_id, type_id);
242 }
243 }
244 }
245
246 let mut method_type_subst_map = TypeSubstMap::new();
247 method_type_subst_map.extend(&type_id_type_subst_map);
248 method_type_subst_map.insert(method_implementing_for_typeid, type_id);
249
250 method.subst(&SubstTypesContext::new(
251 engines,
252 &method_type_subst_map,
253 true,
254 ));
255
256 return engines
257 .de()
258 .insert(
259 method.clone(),
260 engines.de().get_parsed_decl_id(self.id()).as_ref(),
261 )
262 .with_parent(decl_engine, self.id().into());
263 }
264
265 self.clone()
266 }
267}
268
269impl Named for TyFunctionDecl {
270 fn name(&self) -> &Ident {
271 &self.name
272 }
273}
274
275impl IsConcrete for TyFunctionDecl {
276 fn is_concrete(&self, engines: &Engines) -> bool {
277 self.type_parameters
278 .iter()
279 .all(|tp| tp.is_concrete(engines))
280 && self
281 .return_type
282 .type_id()
283 .is_concrete(engines, TreatNumericAs::Concrete)
284 && self.parameters().iter().all(|t| {
285 t.type_argument
286 .type_id()
287 .is_concrete(engines, TreatNumericAs::Concrete)
288 })
289 }
290}
291impl declaration::FunctionSignature for TyFunctionDecl {
292 fn parameters(&self) -> &Vec<TyFunctionParameter> {
293 &self.parameters
294 }
295
296 fn return_type(&self) -> &GenericArgument {
297 &self.return_type
298 }
299}
300
301impl EqWithEngines for TyFunctionDecl {}
302impl PartialEqWithEngines for TyFunctionDecl {
303 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
304 self.name == other.name
305 && self.body.eq(&other.body, ctx)
306 && self.parameters.eq(&other.parameters, ctx)
307 && self.return_type.eq(&other.return_type, ctx)
308 && self.type_parameters.eq(&other.type_parameters, ctx)
309 && self.visibility == other.visibility
310 && self.is_contract_call == other.is_contract_call
311 && self.purity == other.purity
312 }
313}
314
315impl HashWithEngines for TyFunctionDecl {
316 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
317 let TyFunctionDecl {
318 name,
319 body,
320 parameters,
321 return_type,
322 type_parameters,
323 visibility,
324 is_contract_call,
325 purity,
326 call_path: _,
329 span: _,
330 attributes: _,
331 implementing_type: _,
332 implementing_for_typeid: _,
333 where_clause: _,
334 is_trait_method_dummy: _,
335 is_type_check_finalized: _,
336 kind: _,
337 } = self;
338 name.hash(state);
339 body.hash(state, engines);
340 parameters.hash(state, engines);
341 return_type.hash(state, engines);
342 type_parameters.hash(state, engines);
343 visibility.hash(state);
344 is_contract_call.hash(state);
345 purity.hash(state);
346 }
347}
348
349impl SubstTypes for TyFunctionDecl {
350 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
351 let changes = if ctx.subst_function_body {
352 has_changes! {
353 self.type_parameters.subst(ctx);
354 self.parameters.subst(ctx);
355 self.return_type.subst(ctx);
356 self.body.subst(ctx);
357 self.implementing_for_typeid.subst(ctx);
358 }
359 } else {
360 has_changes! {
361 self.type_parameters.subst(ctx);
362 self.parameters.subst(ctx);
363 self.return_type.subst(ctx);
364 self.implementing_for_typeid.subst(ctx);
365 }
366 };
367
368 if let Some(map) = ctx.type_subst_map.as_ref() {
369 let handler = Handler::default();
370 for (name, value) in &map.const_generics_materialization {
371 let _ = self.materialize_const_generics(ctx.engines, &handler, name, value);
372 }
373 HasChanges::Yes
374 } else {
375 changes
376 }
377 }
378}
379
380impl ReplaceDecls for TyFunctionDecl {
381 fn replace_decls_inner(
382 &mut self,
383 decl_mapping: &DeclMapping,
384 handler: &Handler,
385 ctx: &mut TypeCheckContext,
386 ) -> Result<bool, ErrorEmitted> {
387 let mut func_ctx = ctx.by_ref().with_self_type(self.implementing_for_typeid);
388 self.body
389 .replace_decls(decl_mapping, handler, &mut func_ctx)
390 }
391}
392
393impl Spanned for TyFunctionDecl {
394 fn span(&self) -> Span {
395 self.span.clone()
396 }
397}
398
399impl MonomorphizeHelper for TyFunctionDecl {
400 fn type_parameters(&self) -> &[TypeParameter] {
401 &self.type_parameters
402 }
403
404 fn name(&self) -> &Ident {
405 &self.name
406 }
407
408 fn has_self_type_param(&self) -> bool {
409 false
410 }
411}
412
413impl CollectTypesMetadata for TyFunctionDecl {
414 fn collect_types_metadata(
415 &self,
416 handler: &Handler,
417 ctx: &mut CollectTypesMetadataContext,
418 ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
419 let mut body = vec![];
420 for content in self.body.contents.iter() {
421 body.append(&mut content.collect_types_metadata(handler, ctx)?);
422 }
423 body.append(
424 &mut self
425 .return_type
426 .type_id()
427 .collect_types_metadata(handler, ctx)?,
428 );
429 for p in self.type_parameters.iter() {
430 let p = p
431 .as_type_parameter()
432 .expect("only works for type parameters");
433 body.append(&mut p.type_id.collect_types_metadata(handler, ctx)?);
434 }
435 for param in self.parameters.iter() {
436 body.append(
437 &mut param
438 .type_argument
439 .type_id()
440 .collect_types_metadata(handler, ctx)?,
441 );
442 }
443 Ok(body)
444 }
445}
446
447impl TyFunctionDecl {
448 pub(crate) fn set_implementing_type(&mut self, decl: TyDecl) {
449 self.implementing_type = Some(decl);
450 }
451
452 pub(crate) fn error(decl: &parsed::FunctionDeclaration) -> TyFunctionDecl {
455 let parsed::FunctionDeclaration {
456 name,
457 return_type,
458 span,
459 visibility,
460 purity,
461 where_clause,
462 kind,
463 ..
464 } = decl;
465 TyFunctionDecl {
466 purity: *purity,
467 name: name.clone(),
468 body: <_>::default(),
469 implementing_type: None,
470 implementing_for_typeid: None,
471 span: span.clone(),
472 call_path: CallPath::from(Ident::dummy()),
473 attributes: Default::default(),
474 is_contract_call: false,
475 parameters: Default::default(),
476 visibility: *visibility,
477 return_type: return_type.clone(),
478 type_parameters: Default::default(),
479 where_clause: where_clause.clone(),
480 is_trait_method_dummy: false,
481 is_type_check_finalized: true,
482 kind: match kind {
483 FunctionDeclarationKind::Default => TyFunctionDeclKind::Default,
484 FunctionDeclarationKind::Entry => TyFunctionDeclKind::Entry,
485 FunctionDeclarationKind::Test => TyFunctionDeclKind::Test,
486 FunctionDeclarationKind::Main => TyFunctionDeclKind::Main,
487 },
488 }
489 }
490
491 pub(crate) fn parameters_span(&self) -> Span {
493 if !self.parameters.is_empty() {
494 self.parameters.iter().fold(
495 self.parameters[0].name.span(),
497 |acc, TyFunctionParameter { type_argument, .. }| {
498 Span::join(acc, &type_argument.span())
499 },
500 )
501 } else {
502 self.name.span()
503 }
504 }
505
506 pub fn to_fn_selector_value_untruncated(
507 &self,
508 handler: &Handler,
509 engines: &Engines,
510 ) -> Result<Vec<u8>, ErrorEmitted> {
511 let mut hasher = Sha256::new();
512 let data = self.to_selector_name(handler, engines)?;
513 hasher.update(data);
514 let hash = hasher.finalize();
515 Ok(hash.to_vec())
516 }
517
518 pub fn to_fn_selector_value(
522 &self,
523 handler: &Handler,
524 engines: &Engines,
525 ) -> Result<[u8; 4], ErrorEmitted> {
526 let hash = self.to_fn_selector_value_untruncated(handler, engines)?;
527 let mut buf = [0u8; 4];
529 buf.copy_from_slice(&hash[..4]);
530 Ok(buf)
531 }
532
533 pub fn to_selector_name(
534 &self,
535 handler: &Handler,
536 engines: &Engines,
537 ) -> Result<String, ErrorEmitted> {
538 let named_params = self
539 .parameters
540 .iter()
541 .map(|TyFunctionParameter { type_argument, .. }| {
542 engines
543 .te()
544 .to_typeinfo(type_argument.type_id(), &type_argument.span())
545 .expect("unreachable I think?")
546 .to_selector_name(handler, engines, &type_argument.span())
547 })
548 .filter_map(|name| name.ok())
549 .collect::<Vec<String>>();
550
551 Ok(format!(
552 "{}({})",
553 self.name.as_str(),
554 named_params.join(","),
555 ))
556 }
557
558 pub fn is_entry(&self) -> bool {
560 matches!(self.kind, TyFunctionDeclKind::Entry)
561 }
562
563 pub fn is_main(&self) -> bool {
564 matches!(self.kind, TyFunctionDeclKind::Main)
565 }
566
567 pub fn is_test(&self) -> bool {
569 self.attributes.has_any_of_kind(AttributeKind::Test)
571 }
572
573 pub fn inline(&self) -> Option<Inline> {
574 self.attributes.inline()
575 }
576
577 pub fn is_fallback(&self) -> bool {
578 self.attributes.has_any_of_kind(AttributeKind::Fallback)
579 }
580
581 pub fn is_constructor(&self, engines: &Engines, type_id: TypeId) -> Option<bool> {
586 if self
587 .parameters
588 .first()
589 .map(|param| param.is_self())
590 .unwrap_or_default()
591 {
592 return Some(false);
593 };
594
595 match &self.implementing_type {
596 Some(TyDecl::ImplSelfOrTrait(t)) => {
597 let unify_check = UnifyCheck::non_dynamic_equality(engines);
598
599 let implementing_for = engines.de().get(&t.decl_id).implementing_for.type_id();
600
601 if unify_check.check(type_id, implementing_for)
607 && unify_check.check(type_id, self.return_type.type_id())
608 {
609 Some(true)
610 } else {
611 None
612 }
613 }
614 _ => Some(false),
615 }
616 }
617
618 pub fn is_from_blanket_impl(&self, engines: &Engines) -> bool {
619 if let Some(TyDecl::ImplSelfOrTrait(existing_impl_trait)) = self.implementing_type.clone() {
620 let existing_trait_decl = engines
621 .de()
622 .get_impl_self_or_trait(&existing_impl_trait.decl_id);
623 if !existing_trait_decl.impl_type_parameters.is_empty()
624 && matches!(
625 *engines
626 .te()
627 .get(existing_trait_decl.implementing_for.type_id()),
628 TypeInfo::UnknownGeneric { .. }
629 )
630 {
631 return true;
632 }
633 }
634 false
635 }
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
639pub struct TyFunctionParameter {
640 pub name: Ident,
641 pub is_reference: bool,
642 pub is_mutable: bool,
643 pub mutability_span: Span,
644 pub type_argument: GenericArgument,
645}
646
647impl EqWithEngines for TyFunctionParameter {}
648impl PartialEqWithEngines for TyFunctionParameter {
649 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
650 self.name == other.name
651 && self.type_argument.eq(&other.type_argument, ctx)
652 && self.is_reference == other.is_reference
653 && self.is_mutable == other.is_mutable
654 }
655}
656
657impl HashWithEngines for TyFunctionParameter {
658 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
659 let TyFunctionParameter {
660 name,
661 is_reference,
662 is_mutable,
663 type_argument,
664 mutability_span: _,
667 } = self;
668 name.hash(state);
669 type_argument.hash(state, engines);
670 is_reference.hash(state);
671 is_mutable.hash(state);
672 }
673}
674
675impl SubstTypes for TyFunctionParameter {
676 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
677 self.type_argument.type_id_mut().subst(ctx)
678 }
679}
680
681impl TyFunctionParameter {
682 pub fn is_self(&self) -> bool {
683 self.name.as_str() == "self"
684 }
685}
686
687#[derive(Clone, Debug, PartialEq, Eq, Hash)]
688pub enum TyFunctionSigTypeParameter {
689 Type(TypeId),
690 Const(ConstGenericExpr),
691}
692
693#[derive(Clone, Debug, PartialEq, Eq, Hash)]
694pub struct TyFunctionSig {
695 pub return_type: TypeId,
696 pub parameters: Vec<TypeId>,
697 pub type_parameters: Vec<TyFunctionSigTypeParameter>,
698}
699
700impl DisplayWithEngines for TyFunctionSig {
701 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
702 write!(f, "{:?}", engines.help_out(self))
703 }
704}
705
706impl DebugWithEngines for TyFunctionSig {
707 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
708 let tp_str = if self.type_parameters.is_empty() {
709 "".to_string()
710 } else {
711 format!(
712 "<{}>",
713 self.type_parameters
714 .iter()
715 .map(|p| match p {
716 TyFunctionSigTypeParameter::Type(t) => format!("{:?}", engines.help_out(t)),
717 TyFunctionSigTypeParameter::Const(expr) =>
718 format!("{:?}", engines.help_out(expr)),
719 })
720 .collect::<Vec<_>>()
721 .join(", "),
722 )
723 };
724 write!(
725 f,
726 "fn{}({}) -> {}",
727 tp_str,
728 self.parameters
729 .iter()
730 .map(|p| format!("{}", engines.help_out(p)))
731 .collect::<Vec<_>>()
732 .join(", "),
733 engines.help_out(self.return_type),
734 )
735 }
736}
737
738impl TyFunctionSig {
739 pub fn from_fn_decl(fn_decl: &TyFunctionDecl) -> Self {
740 Self {
741 return_type: fn_decl.return_type.type_id(),
742 parameters: fn_decl
743 .parameters
744 .iter()
745 .map(|p| p.type_argument.type_id())
746 .collect::<Vec<_>>(),
747 type_parameters: fn_decl
748 .type_parameters
749 .iter()
750 .map(|x| match x {
751 TypeParameter::Type(p) => TyFunctionSigTypeParameter::Type(p.type_id),
752 TypeParameter::Const(p) => {
753 let expr = ConstGenericExpr::AmbiguousVariableExpression {
754 ident: p.name.clone(),
755 };
756 TyFunctionSigTypeParameter::Const(p.expr.clone().unwrap_or(expr))
757 }
758 })
759 .collect(),
760 }
761 }
762
763 pub fn is_concrete(&self, engines: &Engines) -> bool {
764 self.return_type
765 .is_concrete(engines, TreatNumericAs::Concrete)
766 && self
767 .parameters
768 .iter()
769 .all(|p| p.is_concrete(engines, TreatNumericAs::Concrete))
770 && self
771 .type_parameters
772 .iter()
773 .filter_map(|x| match x {
774 TyFunctionSigTypeParameter::Type(type_id) => Some(type_id),
775 TyFunctionSigTypeParameter::Const(_) => None,
776 })
777 .all(|type_id| type_id.is_concrete(engines, TreatNumericAs::Concrete))
778 }
779
780 pub fn get_type_str(&self, engines: &Engines) -> String {
784 let tp_str = if self.type_parameters.is_empty() {
785 "".to_string()
786 } else {
787 format!(
788 "<{}>",
789 self.type_parameters
790 .iter()
791 .map(|x| match x {
792 TyFunctionSigTypeParameter::Type(type_id) => type_id.get_type_str(engines),
793 TyFunctionSigTypeParameter::Const(p) => {
794 match p {
795 ConstGenericExpr::Literal { val, .. } => val.to_string(),
796 ConstGenericExpr::AmbiguousVariableExpression { .. } => todo!(),
797 }
798 }
799 })
800 .collect::<Vec<_>>()
801 .join(", "),
802 )
803 };
804 format!(
805 "fn{}({}) -> {}",
806 tp_str,
807 self.parameters
808 .iter()
809 .map(|p| p.get_type_str(engines))
810 .collect::<Vec<_>>()
811 .join(", "),
812 self.return_type.get_type_str(engines),
813 )
814 }
815}