Skip to main content

syn_sem/semantic/tree/
ty.rs

1use super::PathId;
2use crate::ds::vec::BoxedSlice;
3use any_intern::Interned;
4use logic_eval_util::unique::{PairIter, UniqueContainer};
5use std::{
6    cell::Cell,
7    fmt::{self, Write},
8    hash::{Hash, Hasher},
9    iter, ops,
10    ptr::NonNull,
11};
12
13#[derive(Debug, Clone)]
14pub enum Type<'gcx> {
15    Scalar(TypeScalar),
16    Path(TypePath<'gcx>),
17    Tuple(TypeTuple),
18    Array(TypeArray),
19    Ref(TypeRef),
20    Mut(TypeMut),
21    Unit,
22}
23
24impl<'gcx> Hash for Type<'gcx> {
25    fn hash<H: Hasher>(&self, state: &mut H) {
26        #[repr(u8)]
27        enum TypeKind {
28            Scalar,
29            Path,
30            Tuple,
31            Array,
32            Ref,
33            Mut,
34            Unit,
35        }
36
37        match self {
38            Self::Scalar(scalar) => {
39                state.write_u8(TypeKind::Scalar as u8);
40                scalar.hash(state);
41            }
42            Self::Path(TypePath { pid, params: _ }) => {
43                // We don't have to hash `params` because `pid` is sufficient to identify a type.
44                state.write_u8(TypeKind::Path as u8);
45                pid.hash(state);
46            }
47            Self::Tuple(elems) => {
48                state.write_u8(TypeKind::Tuple as u8);
49                elems.hash(state);
50            }
51            Self::Array(arr) => {
52                state.write_u8(TypeKind::Array as u8);
53                arr.hash(state);
54            }
55            Self::Ref(ref_) => {
56                state.write_u8(TypeKind::Ref as u8);
57                ref_.hash(state);
58            }
59            Self::Mut(mut_) => {
60                state.write_u8(TypeKind::Mut as u8);
61                mut_.hash(state);
62            }
63            Self::Unit => state.write_u8(TypeKind::Unit as u8),
64        }
65    }
66}
67
68impl<'gcx> PartialEq for Type<'gcx> {
69    fn eq(&self, other: &Self) -> bool {
70        match self {
71            Self::Scalar(l) => matches!(other, Self::Scalar(r) if l == r),
72            Self::Path(l) => {
73                // We don't have to compare `params` because `pid` is sufficient to identify a
74                // type.
75                matches!(other, Self::Path(r) if l.pid == r.pid)
76            }
77            Self::Tuple(l) => matches!(other, Self::Tuple(r) if l == r),
78            Self::Array(l) => matches!(other, Self::Array(r) if l == r),
79            Self::Ref(l) => matches!(other, Self::Ref(r) if l == r),
80            Self::Mut(l) => matches!(other, Self::Mut(r) if l == r),
81            Self::Unit => matches!(other, Self::Unit),
82        }
83    }
84}
85
86impl Eq for Type<'_> {}
87
88#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
89pub enum TypeScalar {
90    Int,
91    Float,
92    I8,
93    I16,
94    I32,
95    I64,
96    I128,
97    Isize,
98    U8,
99    U16,
100    U32,
101    U64,
102    U128,
103    Usize,
104    F32,
105    F64,
106    Bool,
107}
108
109impl TypeScalar {
110    pub(crate) fn from_type_name(name: &str) -> Option<Self> {
111        match name {
112            "i8" => Some(Self::I8),
113            "i16" => Some(Self::I16),
114            "i32" => Some(Self::I32),
115            "i64" => Some(Self::I64),
116            "i128" => Some(Self::I128),
117            "isize" => Some(Self::Isize),
118            "u8" => Some(Self::U8),
119            "u16" => Some(Self::U16),
120            "u32" => Some(Self::U32),
121            "u64" => Some(Self::U64),
122            "u128" => Some(Self::U128),
123            "usize" => Some(Self::Usize),
124            "f32" => Some(Self::F32),
125            "f64" => Some(Self::F64),
126            "bool" => Some(Self::Bool),
127            _ => None,
128        }
129    }
130
131    pub(crate) fn to_type_name(self) -> &'static str {
132        match self {
133            Self::Int => "i32",
134            Self::Float => "f32",
135            Self::I8 => "i8",
136            Self::I16 => "i16",
137            Self::I32 => "i32",
138            Self::I64 => "i64",
139            Self::I128 => "i128",
140            Self::Isize => "isize",
141            Self::U8 => "u8",
142            Self::U16 => "u16",
143            Self::U32 => "u32",
144            Self::U64 => "u64",
145            Self::U128 => "u128",
146            Self::Usize => "usize",
147            Self::F32 => "f32",
148            Self::F64 => "f64",
149            Self::Bool => "bool",
150        }
151    }
152}
153
154#[derive(Debug, Clone)]
155pub struct TypePath<'gcx> {
156    pub pid: PathId,
157    pub params: BoxedSlice<Param<'gcx>>,
158}
159
160#[derive(Debug, Clone)]
161pub enum Param<'gcx> {
162    Self_,
163    Other {
164        name: Interned<'gcx, str>,
165        tid: TypeId,
166    },
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Hash)]
170pub struct TypeTuple {
171    pub elems: BoxedSlice<TypeId>,
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Hash)]
175pub struct TypeArray {
176    pub elem: TypeId,
177    pub len: ArrayLen,
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
181pub enum ArrayLen {
182    Fixed(usize),
183    Dynamic,
184    Generic,
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
188pub struct TypeRef {
189    pub elem: TypeId,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, Hash)]
193pub struct TypeMut {
194    pub elem: TypeId,
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
198pub struct TypeId(pub(crate) usize);
199
200impl TypeId {
201    /// # Safety
202    ///
203    /// Undefined behavior if the given index is out of bounds.
204    pub unsafe fn new(index: usize) -> Self {
205        Self(index)
206    }
207}
208
209/// Unlike [`Type`], this type owns the whole type information, which means you don't need to refer
210/// to other data structures to investigate the type.
211#[derive(PartialEq, Eq, Hash, Clone, Default)]
212pub enum OwnedType {
213    /// Corresponds to [`Type::Scalar`] and [`Type::Path`].
214    Path {
215        name: String,
216        params: BoxedSlice<OwnedParam>,
217    },
218    /// Corresponds to [`Type::Tuple`].
219    Tuple(BoxedSlice<OwnedType>),
220    /// Corresponds to [`Type::Array`].
221    Array { elem: Box<OwnedType>, len: ArrayLen },
222    /// Corresponds to [`Type::Ref`].
223    Ref { elem: Box<OwnedType> },
224    /// Corresponds to [`Type::Mut`].
225    Mut { elem: Box<OwnedType> },
226    /// Corresponds to [`Type::Unit`].
227    #[default]
228    Unit,
229}
230
231impl fmt::Debug for OwnedType {
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        match self {
234            Self::Path { name, .. } if name == "int" => f.write_str("int"),
235            Self::Path { name, .. } if name == "float" => f.write_str("float"),
236            Self::Path { name, .. } if name == "i8" => f.write_str("i8"),
237            Self::Path { name, .. } if name == "i16" => f.write_str("i16"),
238            Self::Path { name, .. } if name == "i32" => f.write_str("i32"),
239            Self::Path { name, .. } if name == "i64" => f.write_str("i64"),
240            Self::Path { name, .. } if name == "i128" => f.write_str("i128"),
241            Self::Path { name, .. } if name == "isize" => f.write_str("isize"),
242            Self::Path { name, .. } if name == "u8" => f.write_str("u8"),
243            Self::Path { name, .. } if name == "u16" => f.write_str("u16"),
244            Self::Path { name, .. } if name == "u32" => f.write_str("u32"),
245            Self::Path { name, .. } if name == "u64" => f.write_str("u64"),
246            Self::Path { name, .. } if name == "u128" => f.write_str("u128"),
247            Self::Path { name, .. } if name == "usize" => f.write_str("usize"),
248            Self::Path { name, .. } if name == "f32" => f.write_str("f32"),
249            Self::Path { name, .. } if name == "f64" => f.write_str("f64"),
250            Self::Path { name, .. } if name == "bool" => f.write_str("bool"),
251            Self::Path { name, params } => f
252                .debug_struct("Path")
253                .field("name", name)
254                .field("params", params)
255                .finish(),
256            Self::Tuple(elems) => f.debug_tuple("Tuple").field(elems).finish(),
257            Self::Array { elem, len } => f
258                .debug_struct("Array")
259                .field("elem", elem)
260                .field("len", len)
261                .finish(),
262            Self::Ref { elem } => f.debug_struct("Ref").field("elem", elem).finish(),
263            Self::Mut { elem } => f.debug_struct("Mut").field("elem", elem).finish(),
264            Self::Unit => f.write_str("Unit"),
265        }
266    }
267}
268
269impl fmt::Display for OwnedType {
270    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271        match self {
272            Self::Path { name, .. } => f.write_str(name),
273            Self::Tuple(elems) => {
274                f.write_char('(')?;
275                for elem in elems.iter() {
276                    fmt::Display::fmt(elem, f)?;
277                }
278                f.write_char(')')
279            }
280            Self::Array { elem, len } => match len {
281                ArrayLen::Fixed(n) => f.write_fmt(format_args!("[{elem}; {n}]")),
282                ArrayLen::Dynamic => f.write_fmt(format_args!("[{elem}]")),
283                ArrayLen::Generic => f.write_fmt(format_args!("[{elem}; N]")),
284            },
285            Self::Ref { elem } => f.write_fmt(format_args!("&{elem}")),
286            Self::Mut { elem } => f.write_fmt(format_args!("&mut {elem}")),
287            Self::Unit => f.write_str("()"),
288        }
289    }
290}
291
292#[derive(Debug, Clone, PartialEq, Eq, Hash)]
293pub enum OwnedParam {
294    Self_,
295    Other { name: String, ty: OwnedType },
296}
297
298pub(crate) trait CreateOwnedType {
299    fn create_owned_type(&self, tid: TypeId) -> OwnedType;
300}
301
302thread_local! {
303    pub(crate) static OWNED_TYPE_CREATOR: Cell<Option<NonNull<dyn CreateOwnedType>>> = const {
304        Cell::new(None)
305    };
306}
307
308pub struct UniqueTypes<'gcx>(UniqueContainer<Type<'gcx>>);
309
310impl<'gcx> UniqueTypes<'gcx> {
311    pub(crate) fn new() -> Self {
312        Self(UniqueContainer::new())
313    }
314
315    pub fn get(&self, tid: TypeId) -> Option<&Type<'gcx>> {
316        self.0.get(tid.0)
317    }
318
319    pub fn iter(&self) -> TypeIter<'_, 'gcx> {
320        TypeIter(self.0.iter())
321    }
322
323    pub(crate) fn insert(&mut self, ty: Type<'gcx>) -> TypeId {
324        let index = self.0.insert(ty);
325        TypeId(index)
326    }
327}
328
329impl<'gcx> ops::Deref for UniqueTypes<'gcx> {
330    type Target = UniqueContainer<Type<'gcx>>;
331
332    fn deref(&self) -> &Self::Target {
333        &self.0
334    }
335}
336
337impl ops::DerefMut for UniqueTypes<'_> {
338    fn deref_mut(&mut self) -> &mut Self::Target {
339        &mut self.0
340    }
341}
342
343impl<'gcx> ops::Index<TypeId> for UniqueTypes<'gcx> {
344    type Output = Type<'gcx>;
345
346    fn index(&self, id: TypeId) -> &Self::Output {
347        &self.0[id.0]
348    }
349}
350
351pub struct TypeIter<'a, 'gcx>(PairIter<'a, Type<'gcx>>);
352
353impl<'a, 'gcx> Iterator for TypeIter<'a, 'gcx> {
354    type Item = (TypeId, &'a Type<'gcx>);
355
356    fn next(&mut self) -> Option<Self::Item> {
357        self.0.next().map(|(index, ty)| (TypeId(index), ty))
358    }
359
360    fn size_hint(&self) -> (usize, Option<usize>) {
361        self.0.size_hint()
362    }
363}
364
365impl ExactSizeIterator for TypeIter<'_, '_> {
366    fn len(&self) -> usize {
367        self.0.len()
368    }
369}
370
371impl iter::FusedIterator for TypeIter<'_, '_> {}