1use crate::context::AnalyzerContext;
2use crate::display::DisplayWithDb;
3use crate::display::Displayable;
4use crate::errors::TypeError;
5use crate::namespace::items::{
6 ContractId, EnumId, FunctionId, FunctionSigId, ImplId, Item, StructId, TraitId,
7};
8use crate::AnalyzerDb;
9
10use fe_common::impl_intern_key;
11use fe_common::Span;
12use num_bigint::BigInt;
13use num_traits::ToPrimitive;
14use smol_str::SmolStr;
15use std::fmt;
16use std::rc::Rc;
17use std::str::FromStr;
18use strum::{AsRefStr, EnumIter, EnumString};
19
20pub fn u256_min() -> BigInt {
21 BigInt::from(0)
22}
23
24pub fn u256_max() -> BigInt {
25 BigInt::from(2).pow(256) - 1
26}
27
28pub fn i256_max() -> BigInt {
29 BigInt::from(2).pow(255) - 1
30}
31
32pub fn i256_min() -> BigInt {
33 BigInt::from(-2).pow(255)
34}
35
36pub fn address_max() -> BigInt {
37 BigInt::from(2).pow(160) - 1
38}
39
40pub trait SafeNames {
42 fn lower_snake(&self) -> String;
44}
45
46#[derive(Clone, Debug, PartialEq, Eq, Hash)]
47pub enum Type {
48 Base(Base),
49 Array(Array),
50 Map(Map),
51 Tuple(Tuple),
52 String(FeString),
53 Contract(ContractId),
55 SelfContract(ContractId),
58 SelfType(TraitOrType),
60 Struct(StructId),
61 Enum(EnumId),
62 Generic(Generic),
63 SPtr(TypeId),
64 Mut(TypeId),
65}
66
67#[derive(Clone, Debug, PartialEq, Eq, Hash)]
68pub enum TraitOrType {
69 TraitId(TraitId),
70 TypeId(TypeId),
71}
72
73type TraitFunctionLookup = (Vec<(FunctionId, ImplId)>, Vec<(FunctionId, ImplId)>);
74
75#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
76pub struct TypeId(pub(crate) u32);
77impl_intern_key!(TypeId);
78impl TypeId {
79 pub fn unit(db: &dyn AnalyzerDb) -> Self {
80 db.intern_type(Type::unit())
81 }
82 pub fn bool(db: &dyn AnalyzerDb) -> Self {
83 db.intern_type(Type::bool())
84 }
85 pub fn int(db: &dyn AnalyzerDb, int: Integer) -> Self {
86 db.intern_type(Type::int(int))
87 }
88 pub fn address(db: &dyn AnalyzerDb) -> Self {
89 db.intern_type(Type::Base(Base::Address))
90 }
91 pub fn base(db: &dyn AnalyzerDb, t: Base) -> Self {
92 db.intern_type(Type::Base(t))
93 }
94 pub fn tuple(db: &dyn AnalyzerDb, items: &[TypeId]) -> Self {
95 db.intern_type(Type::Tuple(Tuple {
96 items: items.into(),
97 }))
98 }
99
100 pub fn typ(&self, db: &dyn AnalyzerDb) -> Type {
101 db.lookup_intern_type(*self)
102 }
103 pub fn deref_typ(&self, db: &dyn AnalyzerDb) -> Type {
104 self.deref(db).typ(db)
105 }
106 pub fn deref(self, db: &dyn AnalyzerDb) -> TypeId {
107 match self.typ(db) {
108 Type::SPtr(inner) => inner,
109 Type::Mut(inner) => inner.deref(db),
110 Type::SelfType(TraitOrType::TypeId(inner)) => inner,
111 _ => self,
112 }
113 }
114 pub fn make_sptr(self, db: &dyn AnalyzerDb) -> TypeId {
115 Type::SPtr(self).id(db)
116 }
117
118 pub fn has_fixed_size(&self, db: &dyn AnalyzerDb) -> bool {
119 self.typ(db).has_fixed_size(db)
120 }
121
122 pub fn is_primitive(&self, db: &dyn AnalyzerDb) -> bool {
124 matches!(self.typ(db), Type::Base(_) | Type::Contract(_))
125 }
126 pub fn is_bool(&self, db: &dyn AnalyzerDb) -> bool {
127 matches!(self.typ(db), Type::Base(Base::Bool))
128 }
129 pub fn is_contract(&self, db: &dyn AnalyzerDb) -> bool {
130 matches!(self.typ(db), Type::Contract(_) | Type::SelfContract(_))
131 }
132 pub fn is_integer(&self, db: &dyn AnalyzerDb) -> bool {
133 matches!(self.typ(db), Type::Base(Base::Numeric(_)))
134 }
135 pub fn is_map(&self, db: &dyn AnalyzerDb) -> bool {
136 matches!(self.typ(db), Type::Map(_))
137 }
138 pub fn is_string(&self, db: &dyn AnalyzerDb) -> bool {
139 matches!(self.typ(db), Type::String(_))
140 }
141 pub fn is_self_ty(&self, db: &dyn AnalyzerDb) -> bool {
142 matches!(self.typ(db), Type::SelfType(_))
143 }
144 pub fn as_struct(&self, db: &dyn AnalyzerDb) -> Option<StructId> {
145 if let Type::Struct(id) = self.typ(db) {
146 Some(id)
147 } else {
148 None
149 }
150 }
151 pub fn as_trait_or_type(&self) -> TraitOrType {
152 TraitOrType::TypeId(*self)
153 }
154 pub fn is_struct(&self, db: &dyn AnalyzerDb) -> bool {
155 matches!(self.typ(db), Type::Struct(_))
156 }
157 pub fn is_sptr(&self, db: &dyn AnalyzerDb) -> bool {
158 match self.typ(db) {
159 Type::SPtr(_) => true,
160 Type::Mut(inner) => inner.is_sptr(db),
161 _ => false,
162 }
163 }
164 pub fn is_generic(&self, db: &dyn AnalyzerDb) -> bool {
165 matches!(self.deref(db).typ(db), Type::Generic(_))
166 }
167
168 pub fn is_mut(&self, db: &dyn AnalyzerDb) -> bool {
169 matches!(self.typ(db), Type::Mut(_))
170 }
171
172 pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
173 self.typ(db).name(db)
174 }
175
176 pub fn kind_display_name(&self, db: &dyn AnalyzerDb) -> &str {
177 match self.typ(db) {
178 Type::Contract(_) | Type::SelfContract(_) => "contract",
179 Type::Struct(_) => "struct",
180 Type::Array(_) => "array",
181 Type::Tuple(_) => "tuple",
182 _ => "type",
183 }
184 }
185
186 pub fn get_impl_for(&self, db: &dyn AnalyzerDb, trait_: TraitId) -> Option<ImplId> {
189 db.impl_for(*self, trait_)
190 }
191
192 pub fn trait_function_candidates(
196 &self,
197 context: &mut dyn AnalyzerContext,
198 fn_name: &str,
199 ) -> TraitFunctionLookup {
200 let candidates = context
201 .db()
202 .all_impls(*self)
203 .iter()
204 .cloned()
205 .filter_map(|_impl| {
206 _impl
207 .function(context.db(), fn_name)
208 .map(|fun| (fun, _impl))
209 })
210 .collect::<Vec<_>>();
211
212 let in_scope_candidates = candidates
213 .iter()
214 .cloned()
215 .filter(|(_, _impl)| {
216 context
217 .module()
218 .is_in_scope(context.db(), Item::Trait(_impl.trait_id(context.db())))
219 })
220 .collect::<Vec<_>>();
221
222 (candidates, in_scope_candidates)
223 }
224
225 pub fn function_sig(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
228 match self.typ(db) {
229 Type::SPtr(inner) => inner.function_sig(db, name),
230 Type::Contract(id) => id.function(db, name).map(|fun| fun.sig(db)),
231 Type::SelfContract(id) => id.function(db, name).map(|fun| fun.sig(db)),
232 Type::Struct(id) => id.function(db, name).map(|fun| fun.sig(db)),
233 Type::Enum(id) => id.function(db, name).map(|fun| fun.sig(db)),
234 Type::Generic(inner) => inner
236 .bounds
237 .first()
238 .and_then(|bound| bound.function(db, name)),
239 _ => None,
240 }
241 }
242
243 pub fn function_sigs(&self, db: &dyn AnalyzerDb, name: &str) -> Rc<[FunctionSigId]> {
247 db.function_sigs(*self, name.into())
248 }
249
250 pub fn self_function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
251 let fun = self.function_sig(db, name)?;
252 fun.takes_self(db).then_some(fun)
253 }
254
255 pub fn is_emittable(self, db: &dyn AnalyzerDb) -> bool {
259 matches!(self.typ(db), Type::Struct(_)) && self.is_encodable(db).unwrap_or(false)
260 }
261
262 pub fn is_encodable(self, db: &dyn AnalyzerDb) -> Result<bool, TypeError> {
265 match self.typ(db) {
266 Type::Base(_) | Type::String(_) | Type::Contract(_) => Ok(true),
267 Type::Array(arr) => arr.inner.is_encodable(db),
268 Type::Struct(sid) => {
269 if !db.struct_dependency_graph(sid).diagnostics.is_empty() {
273 return Ok(false);
274 };
275 let mut res = true;
276 for (_, &fid) in sid.fields(db).iter() {
280 res &= fid.typ(db)?.is_encodable(db)?;
281 }
282 Ok(res)
283 }
284 Type::Tuple(tup) => {
285 let mut res = true;
286 for item in tup.items.iter() {
290 res &= item.is_encodable(db)?;
291 }
292 Ok(res)
293 }
294 Type::Mut(inner) => inner.is_encodable(db),
295 Type::SelfType(id) => match id {
296 TraitOrType::TraitId(_) => Ok(false),
297 TraitOrType::TypeId(id) => id.is_encodable(db),
298 },
299 Type::Map(_)
300 | Type::SelfContract(_)
301 | Type::Generic(_)
302 | Type::Enum(_)
303 | Type::SPtr(_) => Ok(false),
304 }
305 }
306}
307
308#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
309pub enum Base {
310 Numeric(Integer),
311 Bool,
312 Address,
313 Unit,
314}
315
316impl Base {
317 pub fn name(&self) -> SmolStr {
318 match self {
319 Base::Numeric(num) => num.as_ref().into(),
320 Base::Bool => "bool".into(),
321 Base::Address => "address".into(),
322 Base::Unit => "()".into(),
323 }
324 }
325 pub fn u256() -> Base {
326 Base::Numeric(Integer::U256)
327 }
328}
329
330#[derive(
331 Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, AsRefStr, EnumString, EnumIter,
332)]
333#[strum(serialize_all = "snake_case")]
334pub enum Integer {
335 U256,
336 U128,
337 U64,
338 U32,
339 U16,
340 U8,
341 I256,
342 I128,
343 I64,
344 I32,
345 I16,
346 I8,
347}
348
349pub const U256: Base = Base::Numeric(Integer::U256);
350
351#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
352pub struct Array {
353 pub size: usize,
354 pub inner: TypeId,
355}
356
357#[derive(Clone, Debug, PartialEq, Eq, Hash)]
358pub struct Map {
359 pub key: TypeId,
360 pub value: TypeId,
361}
362
363#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
364pub struct Generic {
365 pub name: SmolStr,
366 pub bounds: Rc<[TraitId]>,
367}
368
369#[derive(Clone, Debug, PartialEq, Eq, Hash)]
370pub struct Tuple {
371 pub items: Rc<[TypeId]>,
372}
373
374#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
375pub struct FeString {
376 pub max_size: usize,
377}
378
379#[derive(Clone, Debug, PartialEq, Eq, Hash)]
380pub struct FunctionSignature {
381 pub self_decl: Option<SelfDecl>,
382 pub ctx_decl: Option<CtxDecl>,
383 pub params: Vec<FunctionParam>,
384 pub return_type: Result<TypeId, TypeError>,
385}
386
387#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
388pub struct SelfDecl {
389 pub span: Span,
390 pub mut_: Option<Span>,
391}
392
393impl SelfDecl {
394 pub fn is_mut(&self) -> bool {
395 self.mut_.is_some()
396 }
397}
398
399#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
400pub struct CtxDecl {
401 pub span: Span,
402 pub mut_: Option<Span>,
403}
404
405#[derive(Clone, Debug, PartialEq, Eq, Hash)]
406pub struct FunctionParam {
407 label: Option<SmolStr>,
408 pub name: SmolStr,
409 pub typ: Result<TypeId, TypeError>,
410}
411impl FunctionParam {
412 pub fn new(label: Option<&str>, name: &str, typ: Result<TypeId, TypeError>) -> Self {
413 Self {
414 label: label.map(SmolStr::new),
415 name: name.into(),
416 typ,
417 }
418 }
419 pub fn label(&self) -> Option<&str> {
420 match &self.label {
421 Some(label) if label == "_" => None,
422 Some(label) => Some(label),
423 None => Some(&self.name),
424 }
425 }
426}
427
428#[derive(
429 Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, EnumString, AsRefStr, EnumIter,
430)]
431pub enum GenericType {
432 Array,
433 String,
434 Map,
435}
436
437impl GenericType {
438 pub fn name(&self) -> SmolStr {
439 self.as_ref().into()
440 }
441 pub fn params(&self) -> Vec<GenericParam> {
442 match self {
443 GenericType::String => vec![GenericParam {
444 name: "max size".into(),
445 kind: GenericParamKind::Int,
446 }],
447 GenericType::Map => vec![
448 GenericParam {
449 name: "key".into(),
450 kind: GenericParamKind::PrimitiveType,
451 },
452 GenericParam {
453 name: "value".into(),
454 kind: GenericParamKind::AnyType,
455 },
456 ],
457 GenericType::Array => vec![
458 GenericParam {
459 name: "element type".into(),
460 kind: GenericParamKind::AnyType,
461 },
462 GenericParam {
463 name: "size".into(),
464 kind: GenericParamKind::Int,
465 },
466 ],
467 }
468 }
469
470 pub fn apply(&self, db: &dyn AnalyzerDb, args: &[GenericArg]) -> Option<TypeId> {
472 let typ = match self {
473 GenericType::String => match args {
474 [GenericArg::Int(max_size)] => Some(Type::String(FeString {
475 max_size: *max_size,
476 })),
477 _ => None,
478 },
479 GenericType::Map => match args {
480 [GenericArg::Type(key), GenericArg::Type(value)] => Some(Type::Map(Map {
481 key: *key,
482 value: *value,
483 })),
484 _ => None,
485 },
486 GenericType::Array => match args {
487 [GenericArg::Type(element), GenericArg::Int(size)] => Some(Type::Array(Array {
488 size: *size,
489 inner: *element,
490 })),
491 _ => None,
492 },
493 }?;
494 Some(db.intern_type(typ))
495 }
496}
497
498pub struct GenericParam {
499 pub name: SmolStr,
500 pub kind: GenericParamKind,
501}
502
503#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
504pub enum GenericParamKind {
505 Int,
506
507 PrimitiveType,
509 AnyType,
511}
512
513#[derive(Clone, Debug, PartialEq, Eq, Hash)]
514pub enum GenericArg {
515 Int(usize),
516 Type(TypeId),
517}
518
519impl Integer {
520 pub fn is_signed(&self) -> bool {
522 matches!(
523 self,
524 Integer::I256
525 | Integer::I128
526 | Integer::I64
527 | Integer::I32
528 | Integer::I16
529 | Integer::I8
530 )
531 }
532
533 pub fn size(&self) -> usize {
534 match self {
535 Integer::U256 | Integer::I256 => 32,
536 Integer::U128 | Integer::I128 => 16,
537 Integer::U64 | Integer::I64 => 8,
538 Integer::U32 | Integer::I32 => 4,
539 Integer::U16 | Integer::I16 => 2,
540 Integer::U8 | Integer::I8 => 1,
541 }
542 }
543
544 pub fn bits(&self) -> usize {
546 self.size() * 8
547 }
548
549 pub fn can_hold(&self, other: Integer) -> bool {
552 self.size() >= other.size()
553 }
554
555 pub fn fits(&self, num: BigInt) -> bool {
557 match self {
558 Integer::U8 => num.to_u8().is_some(),
559 Integer::U16 => num.to_u16().is_some(),
560 Integer::U32 => num.to_u32().is_some(),
561 Integer::U64 => num.to_u64().is_some(),
562 Integer::U128 => num.to_u128().is_some(),
563 Integer::I8 => num.to_i8().is_some(),
564 Integer::I16 => num.to_i16().is_some(),
565 Integer::I32 => num.to_i32().is_some(),
566 Integer::I64 => num.to_i64().is_some(),
567 Integer::I128 => num.to_i128().is_some(),
568 Integer::U256 => num >= u256_min() && num <= u256_max(),
569 Integer::I256 => num >= i256_min() && num <= i256_max(),
570 }
571 }
572
573 pub fn max_value(&self) -> BigInt {
575 match self {
576 Integer::U256 => u256_max(),
577 Integer::U128 => u128::MAX.into(),
578 Integer::U64 => u64::MAX.into(),
579 Integer::U32 => u32::MAX.into(),
580 Integer::U16 => u16::MAX.into(),
581 Integer::U8 => u8::MAX.into(),
582 Integer::I256 => i256_max(),
583 Integer::I128 => i128::MAX.into(),
584 Integer::I64 => i64::MAX.into(),
585 Integer::I32 => i32::MAX.into(),
586 Integer::I16 => i16::MAX.into(),
587 Integer::I8 => i8::MAX.into(),
588 }
589 }
590
591 pub fn min_value(&self) -> BigInt {
593 match self {
594 Integer::U256 => u256_min(),
595 Integer::U128 => u128::MIN.into(),
596 Integer::U64 => u64::MIN.into(),
597 Integer::U32 => u32::MIN.into(),
598 Integer::U16 => u16::MIN.into(),
599 Integer::U8 => u8::MIN.into(),
600 Integer::I256 => i256_min(),
601 Integer::I128 => i128::MIN.into(),
602 Integer::I64 => i64::MIN.into(),
603 Integer::I32 => i32::MIN.into(),
604 Integer::I16 => i16::MIN.into(),
605 Integer::I8 => i8::MIN.into(),
606 }
607 }
608}
609
610impl Type {
611 pub fn id(&self, db: &dyn AnalyzerDb) -> TypeId {
612 db.intern_type(self.clone())
613 }
614
615 pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
616 match self {
617 Type::Base(inner) => inner.name(),
618 _ => self.display(db).to_string().into(),
619 }
620 }
621
622 pub fn def_span(&self, context: &dyn AnalyzerContext) -> Option<Span> {
623 match self {
624 Self::Struct(id) => Some(id.span(context.db())),
625 Self::Contract(id) | Self::SelfContract(id) => Some(id.span(context.db())),
626 _ => None,
627 }
628 }
629
630 pub fn bool() -> Self {
632 Type::Base(Base::Bool)
633 }
634
635 pub fn address() -> Self {
637 Type::Base(Base::Address)
638 }
639
640 pub fn u256() -> Self {
642 Type::Base(Base::Numeric(Integer::U256))
643 }
644
645 pub fn u8() -> Self {
647 Type::Base(Base::Numeric(Integer::U8))
648 }
649
650 pub fn unit() -> Self {
652 Type::Base(Base::Unit)
653 }
654
655 pub fn is_unit(&self) -> bool {
656 *self == Type::Base(Base::Unit)
657 }
658
659 pub fn int(int_type: Integer) -> Self {
660 Type::Base(Base::Numeric(int_type))
661 }
662
663 pub fn has_fixed_size(&self, db: &dyn AnalyzerDb) -> bool {
664 match self {
665 Type::Base(_)
666 | Type::Array(_)
667 | Type::Tuple(_)
668 | Type::String(_)
669 | Type::Struct(_)
670 | Type::Enum(_)
671 | Type::Generic(_)
672 | Type::Contract(_) => true,
673 Type::Map(_) | Type::SelfContract(_) => false,
674 Type::SelfType(inner) => match inner {
675 TraitOrType::TraitId(_) => true,
676 TraitOrType::TypeId(id) => id.has_fixed_size(db),
677 },
678 Type::SPtr(inner) | Type::Mut(inner) => inner.has_fixed_size(db),
679 }
680 }
681}
682
683pub trait TypeDowncast {
684 fn as_array(&self, db: &dyn AnalyzerDb) -> Option<Array>;
685 fn as_tuple(&self, db: &dyn AnalyzerDb) -> Option<Tuple>;
686 fn as_string(&self, db: &dyn AnalyzerDb) -> Option<FeString>;
687 fn as_map(&self, db: &dyn AnalyzerDb) -> Option<Map>;
688 fn as_int(&self, db: &dyn AnalyzerDb) -> Option<Integer>;
689}
690
691impl TypeDowncast for TypeId {
692 fn as_array(&self, db: &dyn AnalyzerDb) -> Option<Array> {
693 match self.typ(db) {
694 Type::Array(inner) => Some(inner),
695 _ => None,
696 }
697 }
698 fn as_tuple(&self, db: &dyn AnalyzerDb) -> Option<Tuple> {
699 match self.typ(db) {
700 Type::Tuple(inner) => Some(inner),
701 _ => None,
702 }
703 }
704 fn as_string(&self, db: &dyn AnalyzerDb) -> Option<FeString> {
705 match self.typ(db) {
706 Type::String(inner) => Some(inner),
707 _ => None,
708 }
709 }
710 fn as_map(&self, db: &dyn AnalyzerDb) -> Option<Map> {
711 match self.typ(db) {
712 Type::Map(inner) => Some(inner),
713 _ => None,
714 }
715 }
716 fn as_int(&self, db: &dyn AnalyzerDb) -> Option<Integer> {
717 match self.typ(db) {
718 Type::Base(Base::Numeric(int)) => Some(int),
719 _ => None,
720 }
721 }
722}
723
724impl From<Base> for Type {
725 fn from(value: Base) -> Self {
726 Type::Base(value)
727 }
728}
729
730impl DisplayWithDb for Type {
731 fn format(&self, db: &dyn AnalyzerDb, f: &mut fmt::Formatter<'_>) -> fmt::Result {
732 use std::fmt::Display;
733 match self {
734 Type::Base(inner) => inner.fmt(f),
735 Type::String(inner) => inner.fmt(f),
736 Type::Array(arr) => {
737 write!(f, "Array<{}, {}>", arr.inner.display(db), arr.size)
738 }
739 Type::Map(map) => {
740 let Map { key, value } = map;
741 write!(f, "Map<{}, {}>", key.display(db), value.display(db),)
742 }
743 Type::Tuple(id) => {
744 write!(f, "(")?;
745 let mut delim = "";
746 for item in id.items.iter() {
747 write!(f, "{}{}", delim, item.display(db))?;
748 delim = ", ";
749 }
750 write!(f, ")")
751 }
752 Type::Contract(id) | Type::SelfContract(id) => write!(f, "{}", id.name(db)),
753 Type::Struct(id) => write!(f, "{}", id.name(db)),
754 Type::Enum(id) => write!(f, "{}", id.name(db)),
755 Type::Generic(inner) => inner.fmt(f),
756 Type::SPtr(inner) => write!(f, "SPtr<{}>", inner.display(db)),
757 Type::Mut(inner) => write!(f, "mut {}", inner.display(db)),
758 Type::SelfType(_) => write!(f, "Self"),
759 }
760 }
761}
762impl DisplayWithDb for TypeId {
763 fn format(&self, db: &dyn AnalyzerDb, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764 self.typ(db).format(db, f)
765 }
766}
767
768impl fmt::Display for Base {
769 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770 let name = match self {
771 Base::Numeric(int) => return int.fmt(f),
772 Base::Bool => "bool",
773 Base::Address => "address",
774 Base::Unit => "()",
775 };
776 write!(f, "{name}")
777 }
778}
779
780impl fmt::Display for Integer {
781 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
782 let name = match self {
783 Integer::U256 => "u256",
784 Integer::U128 => "u128",
785 Integer::U64 => "u64",
786 Integer::U32 => "u32",
787 Integer::U16 => "u16",
788 Integer::U8 => "u8",
789 Integer::I256 => "i256",
790 Integer::I128 => "i128",
791 Integer::I64 => "i64",
792 Integer::I32 => "i32",
793 Integer::I16 => "i16",
794 Integer::I8 => "i8",
795 };
796 write!(f, "{name}")
797 }
798}
799
800impl fmt::Display for FeString {
801 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802 write!(f, "String<{}>", self.max_size)
803 }
804}
805
806impl DisplayWithDb for FunctionSignature {
807 fn format(&self, db: &dyn AnalyzerDb, f: &mut fmt::Formatter<'_>) -> fmt::Result {
808 let FunctionSignature {
809 self_decl,
810 ctx_decl: _,
811 params,
812 return_type,
813 } = self;
814
815 write!(f, "params: [")?;
816 let mut delim = "";
817 if let Some(s) = self_decl {
818 write!(f, "{}self", if s.mut_.is_some() { "mut " } else { "" },)?;
819 delim = ", ";
820 }
821
822 for p in params {
823 write!(
824 f,
825 "{}{{ label: {:?}, name: {}, typ: {} }}",
826 delim,
827 p.label,
828 p.name,
829 p.typ.as_ref().unwrap().display(db),
830 )?;
831 delim = ", ";
832 }
833 write!(f, "] -> {}", return_type.as_ref().unwrap().display(db))
834 }
835}
836
837impl fmt::Display for Generic {
838 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
839 write!(f, "{}", self.name)
840 }
841}
842
843impl FromStr for Base {
844 type Err = strum::ParseError;
845
846 fn from_str(s: &str) -> Result<Self, Self::Err> {
847 match s {
848 "bool" => Ok(Base::Bool),
849 "address" => Ok(Base::Address),
850 "()" => Ok(Base::Unit),
851 _ => Ok(Base::Numeric(Integer::from_str(s)?)),
852 }
853 }
854}