solar_sema/ty/
common.rs

1use super::{Interner, Ty, TyFlags, TyKind};
2use solar_ast::{DataLocation, ElementaryType, TypeSize};
3
4/// Pre-interned types.
5pub struct CommonTypes<'gcx> {
6    /// Empty tuple `()`, AKA unit, void.
7    pub unit: Ty<'gcx>,
8    /// `bool`.
9    pub bool: Ty<'gcx>,
10
11    /// `address`.
12    pub address: Ty<'gcx>,
13    /// `address payable`.
14    pub address_payable: Ty<'gcx>,
15
16    /// `string`.
17    pub string: Ty<'gcx>,
18    /// `string` references.
19    pub string_ref: EachDataLoc<Ty<'gcx>>,
20
21    /// `bytes`.
22    pub bytes: Ty<'gcx>,
23    /// `bytes` references.
24    pub bytes_ref: EachDataLoc<Ty<'gcx>>,
25
26    ints: [Ty<'gcx>; 32],
27    uints: [Ty<'gcx>; 32],
28    fbs: [Ty<'gcx>; 32],
29}
30
31impl<'gcx> CommonTypes<'gcx> {
32    #[instrument(name = "new_common_types", level = "debug", skip_all)]
33    #[inline]
34    pub(super) fn new(interner: &Interner<'gcx>, bump: &'gcx bumpalo::Bump) -> Self {
35        use ElementaryType::*;
36        use TyKind::*;
37        use std::array::from_fn;
38
39        // NOTE: We need to skip calculating flags here because it would require `Gcx` when we
40        // haven't built one yet. This is fine since elementary types don't have any flags.
41        // If that ever changes, then this closure should also reflect that.
42        let mk = |kind| interner.intern_ty_with_flags(bump, kind, |_| TyFlags::empty());
43        let mk_refs = |ty| EachDataLoc {
44            storage: mk(Ref(ty, DataLocation::Storage)),
45            transient: mk(Ref(ty, DataLocation::Transient)),
46            memory: mk(Ref(ty, DataLocation::Memory)),
47            calldata: mk(Ref(ty, DataLocation::Calldata)),
48        };
49
50        let string = mk(Elementary(String));
51        let bytes = mk(Elementary(Bytes));
52
53        Self {
54            unit: mk(Tuple(&[])),
55            // never: mk(Elementary(Never)),
56            bool: mk(Elementary(Bool)),
57
58            address: mk(Elementary(Address(false))),
59            address_payable: mk(Elementary(Address(true))),
60
61            string,
62            string_ref: mk_refs(string),
63
64            bytes,
65            bytes_ref: mk_refs(bytes),
66
67            ints: from_fn(|i| mk(Elementary(Int(TypeSize::new(i as u8 + 1).unwrap())))),
68            uints: from_fn(|i| mk(Elementary(UInt(TypeSize::new(i as u8 + 1).unwrap())))),
69            fbs: from_fn(|i| mk(Elementary(FixedBytes(TypeSize::new(i as u8 + 1).unwrap())))),
70        }
71    }
72
73    /// `int<bits>`.
74    #[inline]
75    #[track_caller]
76    pub fn int(&self, bits: u16) -> Ty<'gcx> {
77        self.int_(TypeSize::new_int_bits(bits))
78    }
79    /// `int<size>`.
80    pub fn int_(&self, size: TypeSize) -> Ty<'gcx> {
81        self.ints[size.bytes() as usize - 1]
82    }
83
84    /// `uint<bits>`.
85    #[inline]
86    #[track_caller]
87    pub fn uint(&self, bits: u16) -> Ty<'gcx> {
88        self.uint_(TypeSize::new_int_bits(bits))
89    }
90    /// `uint<size>`.
91    pub fn uint_(&self, size: TypeSize) -> Ty<'gcx> {
92        self.uints[size.bytes() as usize - 1]
93    }
94
95    /// `bytes<bytes>`.
96    #[inline]
97    #[track_caller]
98    pub fn fixed_bytes(&self, bytes: u8) -> Ty<'gcx> {
99        self.fixed_bytes_(TypeSize::new_fb_bytes(bytes))
100    }
101    /// `bytes<size>`.
102    pub fn fixed_bytes_(&self, size: TypeSize) -> Ty<'gcx> {
103        self.fbs[size.bytes() as usize - 1]
104    }
105}
106
107/// Holds an instance of `T` for each data location.
108pub struct EachDataLoc<T> {
109    pub storage: T,
110    pub transient: T,
111    pub memory: T,
112    pub calldata: T,
113}
114
115impl<T> EachDataLoc<T> {
116    /// Gets a copy for the given data location.
117    #[inline]
118    pub fn get(&self, loc: DataLocation) -> T
119    where
120        T: Copy,
121    {
122        match loc {
123            DataLocation::Storage => self.storage,
124            DataLocation::Transient => self.transient,
125            DataLocation::Memory => self.memory,
126            DataLocation::Calldata => self.calldata,
127        }
128    }
129
130    /// Gets a reference for the given data location.
131    #[inline]
132    pub fn get_ref(&self, loc: DataLocation) -> &T {
133        match loc {
134            DataLocation::Storage => &self.storage,
135            DataLocation::Transient => &self.transient,
136            DataLocation::Memory => &self.memory,
137            DataLocation::Calldata => &self.calldata,
138        }
139    }
140
141    /// Gets a mutable reference for the given data location.
142    #[inline]
143    pub fn get_mut(&mut self, loc: DataLocation) -> &mut T {
144        match loc {
145            DataLocation::Storage => &mut self.storage,
146            DataLocation::Transient => &mut self.transient,
147            DataLocation::Memory => &mut self.memory,
148            DataLocation::Calldata => &mut self.calldata,
149        }
150    }
151}
152
153impl<T> std::ops::Index<DataLocation> for EachDataLoc<T> {
154    type Output = T;
155
156    #[inline]
157    fn index(&self, loc: DataLocation) -> &Self::Output {
158        self.get_ref(loc)
159    }
160}
161
162impl<T> std::ops::IndexMut<DataLocation> for EachDataLoc<T> {
163    #[inline]
164    fn index_mut(&mut self, loc: DataLocation) -> &mut Self::Output {
165        self.get_mut(loc)
166    }
167}