Skip to main content

rucc_types/
types.rs

1//! The type table: interning, canonicalisation, and the nominal declarations.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.1.
4//!
5//! There is one [`Types`] per translation unit and every [`TypeId`] belongs to it. Interning
6//! is what makes type identity an integer comparison, which is the single most frequent
7//! question the compiler asks, and it is also what makes the canonical form free to look up:
8//! each entry stores the id of its own canonical type, so stripping a stack of typedefs is one
9//! array read rather than a walk.
10
11use std::collections::HashMap;
12use std::num::NonZeroU32;
13
14use rucc_base::{Idx, Symbol};
15
16use crate::kind::{
17    ArrayLen, EnumId, FloatKind, FunctionId, FunctionType, IntKind, Qualifiers, RecordId,
18    RecordKind, Type, TypeKind,
19};
20use crate::layout::Layout;
21use crate::record::{Field, RecordLayout};
22
23/// The identity of a type.
24///
25/// Four bytes, `Copy`, and equal exactly when the two types are the same type. Ids from two
26/// different [`Types`] tables are not comparable, which is not a restriction in practice
27/// because there is one table per translation unit.
28#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
29pub struct TypeId(Idx<Entry>);
30
31impl std::fmt::Debug for TypeId {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        write!(f, "TypeId#{}", self.0.raw())
34    }
35}
36
37/// One row of the table.
38///
39/// The canonical id is stored rather than computed because almost every read of a type wants
40/// it, and computing it means walking a chain whose length is however many typedefs the header
41/// author felt like writing.
42#[derive(Debug, Clone, Copy)]
43struct Entry {
44    ty: Type,
45    canonical: TypeId,
46}
47
48/// What is known about one `struct` or `union` declaration.
49#[derive(Debug, Clone)]
50pub struct RecordInfo {
51    /// Whether it is a `struct` or a `union`.
52    pub kind: RecordKind,
53    /// The tag, absent for an anonymous one.
54    pub tag: Option<Symbol>,
55    /// The layout, absent until the members have been seen and laid out.
56    ///
57    /// This is also what says whether the type is complete. A record is incomplete from the
58    /// point its tag is first mentioned until its closing brace, and code in between may
59    /// declare pointers to it and nothing else.
60    pub layout: Option<Layout>,
61    /// The members, placed, and empty until the record is complete.
62    ///
63    /// One entry per member the program wrote, in that order, so a caller that kept the
64    /// declarations can index the two together.
65    pub fields: Vec<Field>,
66}
67
68/// What is known about one `enum` declaration.
69#[derive(Debug, Clone)]
70pub struct EnumInfo {
71    /// The tag, absent for an anonymous one.
72    pub tag: Option<Symbol>,
73    /// The type the enumerators are represented in, absent until it is decided.
74    ///
75    /// C23 lets the program write it, and before that it is chosen once every enumerator has
76    /// been seen. Either way it is a fact about the declaration rather than about the type
77    /// system, so it is recorded here and not derived twice.
78    pub underlying: Option<TypeId>,
79    /// Whether the underlying type was written by the program rather than chosen.
80    ///
81    /// It changes the answer to what an enumerator's own type is, and it decides whether an
82    /// enumerator that does not fit is an error or a reason to widen.
83    pub fixed: bool,
84}
85
86/// Every type in one translation unit.
87#[derive(Debug)]
88pub struct Types {
89    entries: Vec<Entry>,
90    map: HashMap<Type, TypeId>,
91    functions: Vec<FunctionType>,
92    function_map: HashMap<FunctionType, FunctionId>,
93    records: Vec<RecordInfo>,
94    enums: Vec<EnumInfo>,
95    void: TypeId,
96    boolean: TypeId,
97    ints: [TypeId; 13],
98    floats: [TypeId; 9],
99}
100
101impl Default for Types {
102    fn default() -> Types {
103        Types::new()
104    }
105}
106
107impl Types {
108    /// A table holding the basic types and nothing else.
109    ///
110    /// The basic types are interned here rather than on first use so that asking for `int` is
111    /// an array read. They are the ones asked for by far the most often, because every
112    /// integer promotion produces one.
113    #[must_use]
114    pub fn new() -> Types {
115        let mut types = Types {
116            entries: Vec::new(),
117            map: HashMap::new(),
118            functions: Vec::new(),
119            function_map: HashMap::new(),
120            records: Vec::new(),
121            enums: Vec::new(),
122            // Fixed up immediately below. There is no id to put here before the table exists,
123            // and an `Option` on each of them would be paid for on every read for the sake of
124            // four lines of construction.
125            void: TypeId(Idx::new(0)),
126            boolean: TypeId(Idx::new(0)),
127            ints: [TypeId(Idx::new(0)); 13],
128            floats: [TypeId(Idx::new(0)); 9],
129        };
130        types.void = types.intern(Type::new(TypeKind::Void));
131        types.boolean = types.intern(Type::new(TypeKind::Bool));
132        for kind in IntKind::ALL {
133            types.ints[kind.index()] = types.intern(Type::new(TypeKind::Int(kind)));
134        }
135        for kind in FloatKind::ALL {
136            types.floats[kind.index()] = types.intern(Type::new(TypeKind::Float(kind)));
137        }
138        types
139    }
140
141    /// How many distinct types there are.
142    #[must_use]
143    pub fn len(&self) -> usize {
144        self.entries.len()
145    }
146
147    /// Whether the table is empty, which it never is once [`Types::new`] has run.
148    #[must_use]
149    pub fn is_empty(&self) -> bool {
150        self.entries.is_empty()
151    }
152
153    /// The type `id` stands for, with its qualifiers.
154    ///
155    /// # Panics
156    ///
157    /// Panics if `id` came from a different table.
158    #[must_use]
159    pub fn get(&self, id: TypeId) -> Type {
160        self.entries[id.0.index()].ty
161    }
162
163    /// What `id` is, ignoring its qualifiers.
164    ///
165    /// # Panics
166    ///
167    /// Panics if `id` came from a different table.
168    #[must_use]
169    pub fn kind(&self, id: TypeId) -> TypeKind {
170        self.get(id).kind
171    }
172
173    /// What `id` is qualified with.
174    ///
175    /// # Panics
176    ///
177    /// Panics if `id` came from a different table.
178    #[must_use]
179    pub fn quals(&self, id: TypeId) -> Qualifiers {
180        self.get(id).quals
181    }
182
183    /// The canonical form of `id`, with every typedef resolved at every depth.
184    ///
185    /// This is what every semantic rule reads. `id` itself is what every diagnostic prints.
186    ///
187    /// # Panics
188    ///
189    /// Panics if `id` came from a different table.
190    #[must_use]
191    pub fn canonical(&self, id: TypeId) -> TypeId {
192        self.entries[id.0.index()].canonical
193    }
194
195    /// Whether `id` is written with a typedef name somewhere inside it.
196    ///
197    /// # Panics
198    ///
199    /// Panics if `id` came from a different table.
200    #[must_use]
201    pub fn is_sugar(&self, id: TypeId) -> bool {
202        self.canonical(id) != id
203    }
204
205    /// `void`.
206    #[must_use]
207    pub fn void(&self) -> TypeId {
208        self.void
209    }
210
211    /// `bool`, which is `_Bool` in the older spellings.
212    ///
213    /// Named this way because `bool` is a Rust keyword and `r#bool` at every call site would
214    /// be a worse trade than one unusual name here.
215    #[must_use]
216    pub fn boolean(&self) -> TypeId {
217        self.boolean
218    }
219
220    /// One of the standard integer types.
221    #[must_use]
222    pub fn int(&self, kind: IntKind) -> TypeId {
223        self.ints[kind.index()]
224    }
225
226    /// One of the real floating types.
227    #[must_use]
228    pub fn float(&self, kind: FloatKind) -> TypeId {
229        self.floats[kind.index()]
230    }
231
232    /// `_Complex T`.
233    pub fn complex(&mut self, kind: FloatKind) -> TypeId {
234        self.intern(Type::new(TypeKind::Complex(kind)))
235    }
236
237    /// `_BitInt(width)`, signed or not.
238    ///
239    /// The width is not checked against the target's maximum here. That check belongs where
240    /// there is a span to point at, and building the type anyway means the rest of the
241    /// declaration still gets checked instead of collapsing into a cascade.
242    pub fn bit_int(&mut self, signed: bool, width: u32) -> TypeId {
243        self.intern(Type::new(TypeKind::BitInt { signed, width }))
244    }
245
246    /// A pointer to `pointee`.
247    pub fn pointer(&mut self, pointee: TypeId) -> TypeId {
248        self.intern(Type::new(TypeKind::Pointer(pointee)))
249    }
250
251    /// `_Atomic(inner)`.
252    pub fn atomic(&mut self, inner: TypeId) -> TypeId {
253        self.intern(Type::new(TypeKind::Atomic(inner)))
254    }
255
256    /// An array of `elem`.
257    pub fn array(&mut self, elem: TypeId, len: ArrayLen) -> TypeId {
258        self.intern(Type::new(TypeKind::Array { elem, len }))
259    }
260
261    /// A GNU vector of `len` elements of `elem`.
262    pub fn vector(&mut self, elem: TypeId, len: u32) -> TypeId {
263        self.intern(Type::new(TypeKind::Vector { elem, len }))
264    }
265
266    /// A function type, deduplicated by content.
267    ///
268    /// # Panics
269    ///
270    /// Panics past four billion distinct function types in one translation unit. The
271    /// alternative to panicking is handing back an id that means a different type, so the
272    /// limit is stated rather than worked around.
273    pub fn function(&mut self, signature: FunctionType) -> TypeId {
274        let id = match self.function_map.get(&signature) {
275            Some(&id) => id,
276            None => {
277                let id = FunctionId(u32::try_from(self.functions.len()).expect("too many types"));
278                self.functions.push(signature.clone());
279                self.function_map.insert(signature, id);
280                id
281            }
282        };
283        self.intern(Type::new(TypeKind::Function(id)))
284    }
285
286    /// The signature behind a function type.
287    ///
288    /// # Panics
289    ///
290    /// Panics if `id` came from a different table.
291    #[must_use]
292    pub fn signature(&self, id: FunctionId) -> &FunctionType {
293        &self.functions[id.0 as usize]
294    }
295
296    /// Declares a `struct` or `union` that has been named but not yet laid out.
297    ///
298    /// Each call makes a new type even for the same tag, because a record type in C is its
299    /// declaration. Redeclaring a tag in an inner scope makes a different type, and the two
300    /// being distinct is what the scope rules mean.
301    ///
302    /// # Panics
303    ///
304    /// Panics past four billion record declarations in one translation unit.
305    pub fn declare_record(&mut self, kind: RecordKind, tag: Option<Symbol>) -> RecordId {
306        let id = RecordId(u32::try_from(self.records.len()).expect("too many types"));
307        self.records.push(RecordInfo { kind, tag, layout: None, fields: Vec::new() });
308        id
309    }
310
311    /// The type of a declared record.
312    pub fn record(&mut self, id: RecordId) -> TypeId {
313        self.intern(Type::new(TypeKind::Record(id)))
314    }
315
316    /// What is known about a declared record.
317    ///
318    /// # Panics
319    ///
320    /// Panics if `id` came from a different table.
321    #[must_use]
322    pub fn record_info(&self, id: RecordId) -> &RecordInfo {
323        &self.records[id.0 as usize]
324    }
325
326    /// Completes a record by recording what [`layout_record`](crate::layout_record) produced.
327    ///
328    /// # Panics
329    ///
330    /// Panics if `id` came from a different table.
331    pub fn complete_record(&mut self, id: RecordId, laid_out: RecordLayout) {
332        let info = &mut self.records[id.0 as usize];
333        info.layout = Some(laid_out.layout);
334        info.fields = laid_out.fields;
335    }
336
337    /// The member of a record with the given name.
338    ///
339    /// Direct members only. Reaching into an anonymous member is a name lookup with a path to
340    /// build rather than a search, so it belongs to whoever is resolving the expression.
341    ///
342    /// # Panics
343    ///
344    /// Panics if `id` came from a different table.
345    #[must_use]
346    pub fn field(&self, id: RecordId, name: Symbol) -> Option<&Field> {
347        self.records[id.0 as usize].fields.iter().find(|field| field.name == Some(name))
348    }
349
350    /// Declares an `enum` whose underlying type is not decided yet.
351    ///
352    /// # Panics
353    ///
354    /// Panics past four billion enumeration declarations in one translation unit.
355    pub fn declare_enum(&mut self, tag: Option<Symbol>) -> EnumId {
356        let id = EnumId(u32::try_from(self.enums.len()).expect("too many types"));
357        self.enums.push(EnumInfo { tag, underlying: None, fixed: false });
358        id
359    }
360
361    /// The type of a declared enumeration.
362    pub fn enumeration(&mut self, id: EnumId) -> TypeId {
363        self.intern(Type::new(TypeKind::Enum(id)))
364    }
365
366    /// What is known about a declared enumeration.
367    ///
368    /// # Panics
369    ///
370    /// Panics if `id` came from a different table.
371    #[must_use]
372    pub fn enum_info(&self, id: EnumId) -> &EnumInfo {
373        &self.enums[id.0 as usize]
374    }
375
376    /// Records what an enumeration is represented in, and whether the program said so.
377    ///
378    /// # Panics
379    ///
380    /// Panics if `id` came from a different table.
381    pub fn complete_enum(&mut self, id: EnumId, underlying: TypeId, fixed: bool) {
382        let info = &mut self.enums[id.0 as usize];
383        info.underlying = Some(underlying);
384        info.fixed = fixed;
385    }
386
387    /// A typedef name standing for `underlying`.
388    pub fn typedef(&mut self, name: Symbol, underlying: TypeId) -> TypeId {
389        self.intern(Type::new(TypeKind::Typedef { name, underlying, align: None }))
390    }
391
392    /// The same, for a typedef that said what an object of it is aligned to.
393    ///
394    /// `align` is in bytes and is what the type is aligned to rather than a floor on it, which
395    /// is what `__attribute__((aligned(n)))` means in this one position. See
396    /// [`TypeKind::Typedef`].
397    pub fn aligned_typedef(
398        &mut self,
399        name: Symbol,
400        underlying: TypeId,
401        align: NonZeroU32,
402    ) -> TypeId {
403        self.intern(Type::new(TypeKind::Typedef { name, underlying, align: Some(align) }))
404    }
405
406    /// What a typedef in `id`'s sugar asked an object of it to be aligned to, and [`None`] when
407    /// none of them asked for anything.
408    ///
409    /// The nearest one wins, because `typedef L M __attribute__((aligned(8)))` over an `L` that
410    /// asked for two is an eight and not a two: the outer typedef is the one the declaration was
411    /// written with. Below the sugar there is nothing to find, since only a typedef can carry one
412    /// of these, so the walk stops at the first node that is not one.
413    ///
414    /// # Panics
415    ///
416    /// Panics if `id` came from a different table.
417    #[must_use]
418    pub fn align_override(&self, id: TypeId) -> Option<NonZeroU32> {
419        let mut id = id;
420        loop {
421            let TypeKind::Typedef { underlying, align, .. } = self.kind(id) else { return None };
422            if align.is_some() {
423                return align;
424            }
425            id = underlying;
426        }
427    }
428
429    /// `id` with `quals` added to whatever it already carries.
430    ///
431    /// Qualifying an array qualifies its element type and leaves the array itself unqualified,
432    /// which is 6.7.3p10 and is not a shortcut. An array type has no qualifiers of its own,
433    /// and if it did then `const` on an array parameter would mean nothing at all.
434    pub fn qualified(&mut self, id: TypeId, quals: Qualifiers) -> TypeId {
435        if quals.is_none() {
436            return id;
437        }
438        let ty = self.get(id);
439        if let TypeKind::Array { elem, len } = ty.kind {
440            let elem = self.qualified(elem, quals);
441            return self.intern(Type { kind: TypeKind::Array { elem, len }, quals: ty.quals });
442        }
443        self.intern(Type { kind: ty.kind, quals: ty.quals.with(quals) })
444    }
445
446    /// `id` with every qualifier removed from its outermost node.
447    ///
448    /// Only the outermost, because that is what the standard means by the unqualified version
449    /// of a type. The pointee of a `const char *` stays `const`.
450    pub fn unqualified(&mut self, id: TypeId) -> TypeId {
451        let ty = self.get(id);
452        if ty.quals.is_none() {
453            return id;
454        }
455        self.intern(Type::new(ty.kind))
456    }
457
458    /// The id for `ty`, making one if this is the first time it has been asked for.
459    fn intern(&mut self, ty: Type) -> TypeId {
460        if let Some(&id) = self.map.get(&ty) {
461            return id;
462        }
463        // Canonicalising can intern other types, which means `self.entries` may have grown by
464        // the time this returns and the id below has to be taken afterwards. It cannot have
465        // interned `ty` itself, because a canonical type differs from the sugar it came from,
466        // but the second lookup is one hash of a cold path against a duplicate entry that
467        // would quietly break the promise that equal ids mean equal types.
468        let canonical = self.canonicalise(&ty);
469        if let Some(&id) = self.map.get(&ty) {
470            return id;
471        }
472        let id = TypeId(Idx::from_usize(self.entries.len()));
473        self.entries.push(Entry { ty, canonical: canonical.unwrap_or(id) });
474        self.map.insert(ty, id);
475        id
476    }
477
478    /// The canonical form of `ty`, or `None` when `ty` is already canonical.
479    ///
480    /// A typedef is not the only place sugar hides. `T *` is sugar when `T` is, and so is an
481    /// array of one, and so is a function that returns one, so this rebuilds the type around
482    /// whatever its parts canonicalise to rather than only looking at the outermost node.
483    fn canonicalise(&mut self, ty: &Type) -> Option<TypeId> {
484        match ty.kind {
485            TypeKind::Typedef { underlying, .. } => {
486                let base = self.canonical(underlying);
487                Some(self.qualified(base, ty.quals))
488            }
489            TypeKind::Pointer(inner) => self.rebuild(ty, inner, TypeKind::Pointer),
490            TypeKind::Atomic(inner) => self.rebuild(ty, inner, TypeKind::Atomic),
491            TypeKind::Array { elem, len } => {
492                self.rebuild(ty, elem, |elem| TypeKind::Array { elem, len })
493            }
494            TypeKind::Vector { elem, len } => {
495                self.rebuild(ty, elem, |elem| TypeKind::Vector { elem, len })
496            }
497            TypeKind::Function(id) => self.canonicalise_function(ty, id),
498            TypeKind::Void
499            | TypeKind::Bool
500            | TypeKind::Int(_)
501            | TypeKind::Float(_)
502            | TypeKind::Complex(_)
503            | TypeKind::BitInt { .. }
504            | TypeKind::Record(_)
505            | TypeKind::Enum(_) => None,
506        }
507    }
508
509    /// The canonical form of a type built out of one other type.
510    fn rebuild(
511        &mut self,
512        ty: &Type,
513        inner: TypeId,
514        make: impl FnOnce(TypeId) -> TypeKind,
515    ) -> Option<TypeId> {
516        let canonical = self.canonical(inner);
517        if canonical == inner {
518            return None;
519        }
520        Some(self.intern(Type { kind: make(canonical), quals: ty.quals }))
521    }
522
523    /// The canonical form of a function type, which is sugar when any part of its signature is.
524    fn canonicalise_function(&mut self, ty: &Type, id: FunctionId) -> Option<TypeId> {
525        let signature = self.signature(id).clone();
526        let ret = self.canonical(signature.ret);
527        let params: Vec<TypeId> =
528            signature.params.iter().map(|&param| self.canonical(param)).collect();
529        if ret == signature.ret && params == signature.params {
530            return None;
531        }
532        let canonical = FunctionType { ret, params, ..signature };
533        let id = self.function(canonical);
534        Some(self.qualified(id, ty.quals))
535    }
536}