ir_lang/ty.rs
1//! The machine-level value types an IR value can have.
2
3use core::fmt;
4
5/// The type of a value in the IR.
6///
7/// This is the IR's own *machine-level* type system, deliberately small and
8/// independent of any source language. A front-end lowering its program decides
9/// how its source types map onto these — a 32-bit and a 64-bit source integer both
10/// lower to [`Type::Int`] here, a source `bool` to [`Type::Bool`], and a value that
11/// produces nothing (a statement, a `void` call) to [`Type::Unit`]. The validator
12/// uses these types to reject operations applied to the wrong kind of value, so the
13/// set is kept to the four cases an arithmetic-and-control-flow core actually needs.
14///
15/// Wider machine types (sized integers, vectors, pointers) are a deliberate later
16/// addition: a new variant is an additive, non-breaking change.
17///
18/// # Examples
19///
20/// ```
21/// use ir_lang::Type;
22///
23/// // Types are small, `Copy`, and print as their lowercase name.
24/// assert_eq!(Type::Int.to_string(), "int");
25/// assert_eq!(Type::Bool.to_string(), "bool");
26/// assert_ne!(Type::Int, Type::Float);
27/// ```
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub enum Type {
31 /// A signed integer value.
32 Int,
33 /// A floating-point value.
34 Float,
35 /// A boolean value, as produced by a comparison or a logical operation.
36 Bool,
37 /// The absence of a value — the result type of an operation that exists only
38 /// for its effect, and the return type of a function that returns nothing.
39 Unit,
40}
41
42impl Type {
43 /// Returns `true` for the numeric types ([`Int`](Type::Int) and
44 /// [`Float`](Type::Float)) that arithmetic and ordering operations accept.
45 ///
46 /// # Examples
47 ///
48 /// ```
49 /// use ir_lang::Type;
50 ///
51 /// assert!(Type::Int.is_numeric());
52 /// assert!(Type::Float.is_numeric());
53 /// assert!(!Type::Bool.is_numeric());
54 /// assert!(!Type::Unit.is_numeric());
55 /// ```
56 #[must_use]
57 pub const fn is_numeric(self) -> bool {
58 matches!(self, Type::Int | Type::Float)
59 }
60}
61
62impl fmt::Display for Type {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 let name = match self {
65 Type::Int => "int",
66 Type::Float => "float",
67 Type::Bool => "bool",
68 Type::Unit => "unit",
69 };
70 f.write_str(name)
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_type_is_numeric_classifies_each_variant() {
80 assert!(Type::Int.is_numeric());
81 assert!(Type::Float.is_numeric());
82 assert!(!Type::Bool.is_numeric());
83 assert!(!Type::Unit.is_numeric());
84 }
85
86 #[test]
87 fn test_type_display_matches_lowercase_name() {
88 assert_eq!(Type::Int.to_string(), "int");
89 assert_eq!(Type::Float.to_string(), "float");
90 assert_eq!(Type::Bool.to_string(), "bool");
91 assert_eq!(Type::Unit.to_string(), "unit");
92 }
93}