Skip to main content

husk_types/
lib.rs

1//! Core type system representations for Husk.
2//!
3//! This crate defines the internal type language used by the type checker.
4
5/// Primitive types built into Husk.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum PrimitiveType {
8    I32,
9    I64,
10    F64,
11    Bool,
12    String,
13    Unit,
14}
15
16/// Identifier for a type variable used during type checking / inference.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct TypeVarId(pub u32);
19
20/// A type in Husk's core type language.
21#[derive(Debug, Clone, PartialEq)]
22pub enum Type {
23    /// A primitive type such as `i32`, `bool`, `String`, or `()`.
24    Primitive(PrimitiveType),
25    /// A named, possibly generic type such as `Option<T>` or `Result<T, E>`.
26    Named {
27        /// The name of the type constructor (e.g., "Option", "Result", "MyType").
28        name: String,
29        /// Type arguments applied to the constructor.
30        args: Vec<Type>,
31    },
32    /// A function type: `(T1, T2, ...) -> R`.
33    Function { params: Vec<Type>, ret: Box<Type> },
34    /// A type variable introduced during type checking.
35    Var(TypeVarId),
36    /// An array type: `[T]`.
37    Array(Box<Type>),
38    /// A tuple type: `(T1, T2, ...)`.
39    Tuple(Vec<Type>),
40}
41
42impl Type {
43    pub fn i32() -> Self {
44        Type::Primitive(PrimitiveType::I32)
45    }
46
47    pub fn i64() -> Self {
48        Type::Primitive(PrimitiveType::I64)
49    }
50
51    pub fn f64() -> Self {
52        Type::Primitive(PrimitiveType::F64)
53    }
54
55    pub fn bool() -> Self {
56        Type::Primitive(PrimitiveType::Bool)
57    }
58
59    pub fn string() -> Self {
60        Type::Primitive(PrimitiveType::String)
61    }
62
63    pub fn unit() -> Self {
64        Type::Primitive(PrimitiveType::Unit)
65    }
66
67    pub fn named(name: impl Into<String>, args: Vec<Type>) -> Self {
68        Type::Named {
69            name: name.into(),
70            args,
71        }
72    }
73
74    pub fn function(params: Vec<Type>, ret: Type) -> Self {
75        Type::Function {
76            params,
77            ret: Box::new(ret),
78        }
79    }
80
81    pub fn tuple(elements: Vec<Type>) -> Self {
82        Type::Tuple(elements)
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn primitives_constructors_work() {
92        assert_eq!(Type::i32(), Type::Primitive(PrimitiveType::I32));
93        assert_eq!(Type::i64(), Type::Primitive(PrimitiveType::I64));
94        assert_eq!(Type::bool(), Type::Primitive(PrimitiveType::Bool));
95        assert_eq!(Type::string(), Type::Primitive(PrimitiveType::String));
96        assert_eq!(Type::unit(), Type::Primitive(PrimitiveType::Unit));
97    }
98
99    #[test]
100    fn named_type_with_args() {
101        let t = Type::named("Option", vec![Type::string()]);
102        match t {
103            Type::Named { name, args } => {
104                assert_eq!(name, "Option");
105                assert_eq!(args.len(), 1);
106                assert_eq!(args[0], Type::string());
107            }
108            _ => panic!("expected named type"),
109        }
110    }
111
112    #[test]
113    fn function_type() {
114        let t = Type::function(vec![Type::i32(), Type::bool()], Type::string());
115        match t {
116            Type::Function { params, ret } => {
117                assert_eq!(params.len(), 2);
118                assert_eq!(params[0], Type::i32());
119                assert_eq!(params[1], Type::bool());
120                assert_eq!(*ret, Type::string());
121            }
122            _ => panic!("expected function type"),
123        }
124    }
125
126    #[test]
127    fn tuple_type() {
128        let t = Type::tuple(vec![Type::i32(), Type::string(), Type::bool()]);
129        match t {
130            Type::Tuple(elements) => {
131                assert_eq!(elements.len(), 3);
132                assert_eq!(elements[0], Type::i32());
133                assert_eq!(elements[1], Type::string());
134                assert_eq!(elements[2], Type::bool());
135            }
136            _ => panic!("expected tuple type"),
137        }
138    }
139}