midenc_hir_type/
lib.rs

1#![no_std]
2#![deny(warnings)]
3
4extern crate alloc;
5
6mod alignable;
7mod array_type;
8mod function_type;
9mod layout;
10mod pointer_type;
11mod struct_type;
12
13use alloc::{boxed::Box, sync::Arc};
14use core::fmt;
15
16use miden_formatting::prettier::PrettyPrint;
17
18pub use self::{
19    alignable::Alignable, array_type::ArrayType, function_type::*, pointer_type::*, struct_type::*,
20};
21
22/// Represents the type of a value in the HIR type system
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub enum Type {
26    /// This indicates a failure to type a value, or a value which is untypable
27    Unknown,
28    /// This type is the bottom type, and represents divergence, akin to Rust's Never/! type
29    Never,
30    /// A 1-bit integer, i.e. a boolean value.
31    ///
32    /// When the bit is 1, the value is true; 0 is false.
33    I1,
34    /// An 8-bit signed integer.
35    I8,
36    /// An 8-bit unsigned integer.
37    U8,
38    /// A 16-bit signed integer.
39    I16,
40    /// A 16-bit unsigned integer.
41    U16,
42    /// A 32-bit signed integer.
43    I32,
44    /// A 32-bit unsigned integer.
45    U32,
46    /// A 64-bit signed integer.
47    I64,
48    /// A 64-bit unsigned integer.
49    U64,
50    /// A 128-bit signed integer.
51    I128,
52    /// A 128-bit unsigned integer.
53    U128,
54    /// A 256-bit unsigned integer.
55    U256,
56    /// A 64-bit IEEE-754 floating-point value.
57    ///
58    /// NOTE: These are currently unsupported in practice, but is reserved here for future use.
59    F64,
60    /// A field element corresponding to the native Miden field (currently the Goldilocks field)
61    Felt,
62    /// A pointer to a value in a byte-addressable address space.
63    ///
64    /// Pointers of this type are _not_ equivalent to element addresses as referred to in the
65    /// Miden Assembly documentation, but do have a straightforward conversion.
66    Ptr(Arc<PointerType>),
67    /// A compound type of fixed shape and size
68    Struct(Arc<StructType>),
69    /// A vector of fixed size
70    Array(Arc<ArrayType>),
71    /// A dynamically sized list of values of the given type
72    ///
73    /// NOTE: Currently this only exists to support the Wasm Canonical ABI,
74    /// but it has no defined represenation yet, so in practice cannot be
75    /// used in most places except during initial translation in the Wasm frontend.
76    List(Arc<Type>),
77    /// A reference to a function with the given type signature
78    Function(Arc<FunctionType>),
79}
80impl Type {
81    /// Returns true if this type is a zero-sized type, which includes:
82    ///
83    /// * Types with no size, e.g. `Never`
84    /// * Zero-sized arrays
85    /// * Arrays with a zero-sized element type
86    /// * Structs composed of nothing but zero-sized fields
87    pub fn is_zst(&self) -> bool {
88        match self {
89            Self::Unknown => false,
90            Self::Never => true,
91            Self::Array(ref ty) => ty.is_zst(),
92            Self::Struct(ref struct_ty) => struct_ty.fields.iter().all(|f| f.ty.is_zst()),
93            Self::I1
94            | Self::I8
95            | Self::U8
96            | Self::I16
97            | Self::U16
98            | Self::I32
99            | Self::U32
100            | Self::I64
101            | Self::U64
102            | Self::I128
103            | Self::U128
104            | Self::U256
105            | Self::F64
106            | Self::Felt
107            | Self::Ptr(_)
108            | Self::List(_)
109            | Self::Function(_) => false,
110        }
111    }
112
113    /// Returns true if this type is any numeric type
114    pub fn is_numeric(&self) -> bool {
115        matches!(
116            self,
117            Self::I1
118                | Self::I8
119                | Self::U8
120                | Self::I16
121                | Self::U16
122                | Self::I32
123                | Self::U32
124                | Self::I64
125                | Self::U64
126                | Self::I128
127                | Self::U128
128                | Self::U256
129                | Self::F64
130                | Self::Felt
131        )
132    }
133
134    /// Returns true if this type is any integral type
135    pub fn is_integer(&self) -> bool {
136        matches!(
137            self,
138            Self::I1
139                | Self::I8
140                | Self::U8
141                | Self::I16
142                | Self::U16
143                | Self::I32
144                | Self::U32
145                | Self::I64
146                | Self::U64
147                | Self::I128
148                | Self::U128
149                | Self::U256
150                | Self::Felt
151        )
152    }
153
154    /// Returns true if this type is any signed integral type
155    pub fn is_signed_integer(&self) -> bool {
156        matches!(self, Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128)
157    }
158
159    /// Returns true if this type is any unsigned integral type
160    pub fn is_unsigned_integer(&self) -> bool {
161        matches!(self, Self::I1 | Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::U128)
162    }
163
164    /// Get this type as its unsigned integral twin, e.g. i32 becomes u32.
165    ///
166    /// This function will panic if the type is not an integer type, or has no unsigned
167    /// representation
168    pub fn as_unsigned(&self) -> Type {
169        match self {
170            Self::I8 | Self::U8 => Self::U8,
171            Self::I16 | Self::U16 => Self::U16,
172            Self::I32 | Self::U32 => Self::U32,
173            Self::I64 | Self::U64 => Self::U64,
174            Self::I128 | Self::U128 => Self::U128,
175            Self::Felt => Self::Felt,
176            ty => panic!("invalid conversion to unsigned integer type: {ty} is not an integer"),
177        }
178    }
179
180    /// Get this type as its signed integral twin, e.g. u32 becomes i32.
181    ///
182    /// This function will panic if the type is not an integer type, or has no signed representation
183    pub fn as_signed(&self) -> Type {
184        match self {
185            Self::I8 | Self::U8 => Self::I8,
186            Self::I16 | Self::U16 => Self::I16,
187            Self::I32 | Self::U32 => Self::I32,
188            Self::I64 | Self::U64 => Self::I64,
189            Self::I128 | Self::U128 => Self::I128,
190            Self::Felt => {
191                panic!("invalid conversion to signed integer type: felt has no signed equivalent")
192            }
193            ty => panic!("invalid conversion to signed integer type: {ty} is not an integer"),
194        }
195    }
196
197    /// Returns true if this type is a floating-point type
198    #[inline]
199    pub fn is_float(&self) -> bool {
200        matches!(self, Self::F64)
201    }
202
203    /// Returns true if this type is the field element type
204    #[inline]
205    pub fn is_felt(&self) -> bool {
206        matches!(self, Self::Felt)
207    }
208
209    /// Returns true if this type is a pointer type
210    #[inline]
211    pub fn is_pointer(&self) -> bool {
212        matches!(self, Self::Ptr(_))
213    }
214
215    /// Returns the type of the pointee, if this type is a pointer type
216    #[inline]
217    pub fn pointee(&self) -> Option<&Type> {
218        match self {
219            Self::Ptr(ty) => Some(ty.pointee()),
220            _ => None,
221        }
222    }
223
224    /// Returns true if this type is a struct type
225    #[inline]
226    pub fn is_struct(&self) -> bool {
227        matches!(self, Self::Struct(_))
228    }
229
230    /// Returns true if this type is an array type
231    #[inline]
232    pub fn is_array(&self) -> bool {
233        matches!(self, Self::Array(_))
234    }
235
236    /// Returns true if this type is a dynamically-sized vector/list type
237    #[inline]
238    pub fn is_list(&self) -> bool {
239        matches!(self, Self::List(_))
240    }
241
242    /// Returns true if this type is a function reference type
243    #[inline]
244    pub fn is_function(&self) -> bool {
245        matches!(self, Self::Function(_))
246    }
247}
248
249impl From<StructType> for Type {
250    #[inline]
251    fn from(ty: StructType) -> Type {
252        Type::Struct(Arc::new(ty))
253    }
254}
255
256impl From<Box<StructType>> for Type {
257    #[inline]
258    fn from(ty: Box<StructType>) -> Type {
259        Type::Struct(Arc::from(ty))
260    }
261}
262
263impl From<Arc<StructType>> for Type {
264    #[inline]
265    fn from(ty: Arc<StructType>) -> Type {
266        Type::Struct(ty)
267    }
268}
269
270impl From<ArrayType> for Type {
271    #[inline]
272    fn from(ty: ArrayType) -> Type {
273        Type::Array(Arc::new(ty))
274    }
275}
276
277impl From<Box<ArrayType>> for Type {
278    #[inline]
279    fn from(ty: Box<ArrayType>) -> Type {
280        Type::Array(Arc::from(ty))
281    }
282}
283
284impl From<Arc<ArrayType>> for Type {
285    #[inline]
286    fn from(ty: Arc<ArrayType>) -> Type {
287        Type::Array(ty)
288    }
289}
290
291impl From<PointerType> for Type {
292    #[inline]
293    fn from(ty: PointerType) -> Type {
294        Type::Ptr(Arc::new(ty))
295    }
296}
297
298impl From<Box<PointerType>> for Type {
299    #[inline]
300    fn from(ty: Box<PointerType>) -> Type {
301        Type::Ptr(Arc::from(ty))
302    }
303}
304
305impl From<Arc<PointerType>> for Type {
306    #[inline]
307    fn from(ty: Arc<PointerType>) -> Type {
308        Type::Ptr(ty)
309    }
310}
311
312impl From<FunctionType> for Type {
313    #[inline]
314    fn from(ty: FunctionType) -> Type {
315        Type::Function(Arc::new(ty))
316    }
317}
318
319impl From<Box<FunctionType>> for Type {
320    #[inline]
321    fn from(ty: Box<FunctionType>) -> Type {
322        Type::Function(Arc::from(ty))
323    }
324}
325
326impl From<Arc<FunctionType>> for Type {
327    #[inline]
328    fn from(ty: Arc<FunctionType>) -> Type {
329        Type::Function(ty)
330    }
331}
332
333impl fmt::Display for Type {
334    /// Print this type for display using the provided module context
335    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
336        self.pretty_print(f)
337    }
338}
339
340impl PrettyPrint for Type {
341    fn render(&self) -> miden_formatting::prettier::Document {
342        use miden_formatting::prettier::*;
343
344        match self {
345            Self::Unknown => const_text("?"),
346            Self::Never => const_text("!"),
347            Self::I1 => const_text("i1"),
348            Self::I8 => const_text("i8"),
349            Self::U8 => const_text("u8"),
350            Self::I16 => const_text("i16"),
351            Self::U16 => const_text("u16"),
352            Self::I32 => const_text("i32"),
353            Self::U32 => const_text("u32"),
354            Self::I64 => const_text("i64"),
355            Self::U64 => const_text("u64"),
356            Self::I128 => const_text("i128"),
357            Self::U128 => const_text("u128"),
358            Self::U256 => const_text("u256"),
359            Self::F64 => const_text("f64"),
360            Self::Felt => const_text("felt"),
361            Self::Ptr(ptr_ty) => ptr_ty.render(),
362            Self::Struct(struct_ty) => struct_ty.render(),
363            Self::Array(array_ty) => array_ty.render(),
364            Self::List(ty) => const_text("list<") + ty.render() + const_text(">"),
365            Self::Function(ty) => ty.render(),
366        }
367    }
368}