fusabi_frontend/
types.rs

1//! Type System Infrastructure for Fusabi
2//!
3//! This module implements the foundational type system for Hindley-Milner type inference.
4//! It provides the core type representation, type variables, type schemes, substitutions,
5//! and type environments needed for type checking F# expressions.
6//!
7//! # Architecture
8//!
9//! The type system follows the Hindley-Milner type inference algorithm with:
10//! - **Type**: Core type representation (primitives, functions, type variables)
11//! - **TypeVar**: Type variables ('a, 'b, etc.) for polymorphism
12//! - **TypeScheme**: Type schemes for let-polymorphism (∀a. τ)
13//! - **Substitution**: Type variable substitutions [α ↦ τ]
14//! - **TypeEnv**: Type environment (Γ) mapping names to type schemes
15//!
16//! # Example
17//!
18//! ```rust
19//! use fusabi_frontend::types::{Type, TypeVar, TypeEnv, Substitution};
20//!
21//! // Create a type variable 'a
22//! let var_a = TypeVar::new(0, "a");
23//! let ty = Type::Var(var_a.clone());
24//!
25//! // Create a substitution ['a -> int]
26//! let subst = Substitution::singleton(var_a, Type::Int);
27//!
28//! // Apply substitution
29//! let result = subst.apply_type(&ty);
30//! assert_eq!(result, Type::Int);
31//! ```
32
33use std::collections::{HashMap, HashSet};
34use std::fmt;
35use std::rc::Rc;
36use std::sync::Arc;
37
38/// Type variable identifier.
39///
40/// Type variables represent unknown types during type inference.
41/// Examples: 'a, 'b, 't1, 't2
42#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub struct TypeVar {
44    /// Unique identifier for this type variable
45    pub id: usize,
46    /// Human-readable name (e.g., "a", "b", "t1")
47    pub name: String,
48}
49
50impl TypeVar {
51    /// Create a new type variable with the given id and name.
52    pub fn new(id: usize, name: impl Into<String>) -> Self {
53        TypeVar {
54            id,
55            name: name.into(),
56        }
57    }
58
59    /// Create a fresh type variable with a generated name.
60    pub fn fresh(id: usize) -> Self {
61        TypeVar {
62            id,
63            name: format!("t{}", id),
64        }
65    }
66}
67
68impl fmt::Display for TypeVar {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(f, "'{}", self.name)
71    }
72}
73
74/// Core type representation.
75///
76/// Represents all types in the Fusabi type system, including:
77/// - Primitive types (int, bool, string, unit)
78/// - Composite types (tuples, lists, arrays, records)
79/// - Function types
80/// - Type variables (for inference)
81/// - Discriminated unions
82#[derive(Debug, Clone, PartialEq)]
83pub enum Type {
84    /// Type variable (e.g., 'a, 'b)
85    Var(TypeVar),
86
87    /// Integer type
88    Int,
89
90    /// Boolean type
91    Bool,
92
93    /// String type
94    String,
95
96    /// Unit type ()
97    Unit,
98
99    /// Float type
100    Float,
101
102    /// Tuple type (e.g., int * string * bool)
103    Tuple(Vec<Type>),
104
105    /// List type (e.g., int list, 'a list)
106    List(Box<Type>),
107
108    /// Array type (e.g., int[], 'a[])
109    Array(Box<Type>),
110
111    /// Function type (e.g., int -> int, 'a -> 'b)
112    Function(Box<Type>, Box<Type>),
113
114    /// Record type with named fields
115    Record(HashMap<String, Type>),
116
117    /// Discriminated union variant (type name, type parameters)
118    Variant(String, Vec<Type>),
119}
120
121impl Type {
122    /// Get all free type variables in this type.
123    ///
124    /// A free type variable is one that is not bound by any quantifier.
125    /// Used for generalization and substitution.
126    pub fn free_vars(&self) -> HashSet<TypeVar> {
127        match self {
128            Type::Var(v) => {
129                let mut set = HashSet::new();
130                set.insert(v.clone());
131                set
132            }
133            Type::Int | Type::Bool | Type::String | Type::Unit | Type::Float => HashSet::new(),
134            Type::Tuple(types) => types.iter().flat_map(|t| t.free_vars()).collect(),
135            Type::List(t) | Type::Array(t) => t.free_vars(),
136            Type::Function(arg, ret) => {
137                let mut set = arg.free_vars();
138                set.extend(ret.free_vars());
139                set
140            }
141            Type::Record(fields) => fields.values().flat_map(|t| t.free_vars()).collect(),
142            Type::Variant(_, params) => params.iter().flat_map(|t| t.free_vars()).collect(),
143        }
144    }
145
146    /// Apply a substitution to this type.
147    ///
148    /// Replaces all occurrences of type variables according to the substitution.
149    pub fn apply(&self, subst: &Substitution) -> Type {
150        match self {
151            Type::Var(v) => subst.lookup(v).unwrap_or_else(|| self.clone()),
152            Type::Int | Type::Bool | Type::String | Type::Unit | Type::Float => self.clone(),
153            Type::Tuple(types) => Type::Tuple(types.iter().map(|t| t.apply(subst)).collect()),
154            Type::List(t) => Type::List(Box::new(t.apply(subst))),
155            Type::Array(t) => Type::Array(Box::new(t.apply(subst))),
156            Type::Function(arg, ret) => {
157                Type::Function(Box::new(arg.apply(subst)), Box::new(ret.apply(subst)))
158            }
159            Type::Record(fields) => Type::Record(
160                fields
161                    .iter()
162                    .map(|(name, ty)| (name.clone(), ty.apply(subst)))
163                    .collect(),
164            ),
165            Type::Variant(name, params) => Type::Variant(
166                name.clone(),
167                params.iter().map(|t| t.apply(subst)).collect(),
168            ),
169        }
170    }
171
172    /// Occurs check: does this type variable occur in this type?
173    ///
174    /// Used to prevent infinite types during unification.
175    /// Returns true if the variable appears anywhere in the type structure.
176    pub fn occurs_check(&self, var: &TypeVar) -> bool {
177        match self {
178            Type::Var(v) => v == var,
179            Type::Int | Type::Bool | Type::String | Type::Unit | Type::Float => false,
180            Type::Tuple(types) => types.iter().any(|t| t.occurs_check(var)),
181            Type::List(t) | Type::Array(t) => t.occurs_check(var),
182            Type::Function(arg, ret) => arg.occurs_check(var) || ret.occurs_check(var),
183            Type::Record(fields) => fields.values().any(|t| t.occurs_check(var)),
184            Type::Variant(_, params) => params.iter().any(|t| t.occurs_check(var)),
185        }
186    }
187
188    /// Helper to create a function type with multiple arguments.
189    ///
190    /// Creates a right-associative chain of function types.
191    /// Example: `function_multi(&[int, bool], string)` creates `int -> bool -> string`
192    pub fn function_multi(args: &[Type], ret: Type) -> Type {
193        args.iter().rev().fold(ret, |acc, arg| {
194            Type::Function(Box::new(arg.clone()), Box::new(acc))
195        })
196    }
197}
198
199impl fmt::Display for Type {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        match self {
202            Type::Var(v) => write!(f, "{}", v),
203            Type::Int => write!(f, "int"),
204            Type::Bool => write!(f, "bool"),
205            Type::String => write!(f, "string"),
206            Type::Unit => write!(f, "unit"),
207            Type::Float => write!(f, "float"),
208            Type::Tuple(types) => {
209                write!(f, "(")?;
210                for (i, ty) in types.iter().enumerate() {
211                    if i > 0 {
212                        write!(f, " * ")?;
213                    }
214                    write!(f, "{}", ty)?;
215                }
216                write!(f, ")")
217            }
218            Type::List(t) => write!(f, "{} list", t),
219            Type::Array(t) => write!(f, "{}[]", t),
220            Type::Function(arg, ret) => {
221                // Add parentheses for nested function types
222                match **arg {
223                    Type::Function(_, _) => write!(f, "({}) -> {}", arg, ret),
224                    _ => write!(f, "{} -> {}", arg, ret),
225                }
226            }
227            Type::Record(fields) => {
228                write!(f, "{{")?;
229                let mut first = true;
230                for (name, ty) in fields {
231                    if !first {
232                        write!(f, "; ")?;
233                    }
234                    write!(f, "{}: {}", name, ty)?;
235                    first = false;
236                }
237                write!(f, "}}")
238            }
239            Type::Variant(name, params) if params.is_empty() => write!(f, "{}", name),
240            Type::Variant(name, params) => {
241                write!(f, "{}<", name)?;
242                for (i, param) in params.iter().enumerate() {
243                    if i > 0 {
244                        write!(f, ", ")?;
245                    }
246                    write!(f, "{}", param)?;
247                }
248                write!(f, ">")
249            }
250        }
251    }
252}
253
254/// Type substitution mapping type variables to types.
255///
256/// Represents the substitution [α ↦ τ] in the type inference algorithm.
257/// Substitutions are composed during unification.
258#[derive(Debug, Clone, PartialEq)]
259pub struct Substitution {
260    /// Map from type variables to their substituted types
261    mappings: HashMap<TypeVar, Type>,
262}
263
264impl Substitution {
265    /// Create an empty substitution (identity).
266    pub fn empty() -> Self {
267        Substitution {
268            mappings: HashMap::new(),
269        }
270    }
271
272    /// Create a substitution with a single mapping [var ↦ ty].
273    pub fn singleton(var: TypeVar, ty: Type) -> Self {
274        let mut mappings = HashMap::new();
275        mappings.insert(var, ty);
276        Substitution { mappings }
277    }
278
279    /// Lookup a type variable in the substitution.
280    ///
281    /// Returns the substituted type if present, None otherwise.
282    pub fn lookup(&self, var: &TypeVar) -> Option<Type> {
283        self.mappings.get(var).cloned()
284    }
285
286    /// Insert or update a mapping in the substitution.
287    pub fn insert(&mut self, var: TypeVar, ty: Type) {
288        self.mappings.insert(var, ty);
289    }
290
291    /// Compose two substitutions: s1 ∘ s2
292    ///
293    /// The result applies s2 first, then s1.
294    /// For all types t: (s1 ∘ s2)(t) = s1(s2(t))
295    pub fn compose(s1: &Self, s2: &Self) -> Self {
296        let mut mappings = HashMap::new();
297
298        // Apply s1 to all values in s2
299        for (var, ty) in &s2.mappings {
300            mappings.insert(var.clone(), ty.apply(s1));
301        }
302
303        // Add mappings from s1 that aren't in s2
304        for (var, ty) in &s1.mappings {
305            if !mappings.contains_key(var) {
306                mappings.insert(var.clone(), ty.clone());
307            }
308        }
309
310        Substitution { mappings }
311    }
312
313    /// Apply this substitution to a type.
314    pub fn apply_type(&self, ty: &Type) -> Type {
315        ty.apply(self)
316    }
317
318    /// Apply this substitution to a type scheme.
319    pub fn apply_scheme(&self, scheme: &TypeScheme) -> TypeScheme {
320        // Remove quantified variables from substitution before applying
321        let mut subst = self.clone();
322        for var in &scheme.vars {
323            subst.mappings.remove(var);
324        }
325        TypeScheme {
326            vars: scheme.vars.clone(),
327            ty: scheme.ty.apply(&subst),
328        }
329    }
330
331    /// Check if this substitution is empty.
332    pub fn is_empty(&self) -> bool {
333        self.mappings.is_empty()
334    }
335
336    /// Get the number of mappings in this substitution.
337    pub fn len(&self) -> usize {
338        self.mappings.len()
339    }
340
341    /// Iterate over the mappings in this substitution.
342    pub fn iter(&self) -> impl Iterator<Item = (&TypeVar, &Type)> {
343        self.mappings.iter()
344    }
345}
346
347impl fmt::Display for Substitution {
348    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349        write!(f, "[")?;
350        let mut first = true;
351        for (var, ty) in &self.mappings {
352            if !first {
353                write!(f, ", ")?;
354            }
355            write!(f, "{} ↦ {}", var, ty)?;
356            first = false;
357        }
358        write!(f, "]")
359    }
360}
361
362/// Type scheme for let-polymorphism.
363///
364/// Represents a polymorphic type ∀a b c. τ
365/// Used to type let-bound variables with generalization.
366#[derive(Debug, Clone, PartialEq)]
367pub struct TypeScheme {
368    /// Quantified type variables
369    pub vars: Vec<TypeVar>,
370    /// The body type
371    pub ty: Type,
372}
373
374impl TypeScheme {
375    /// Create a monomorphic type scheme (no quantified variables).
376    pub fn mono(ty: Type) -> Self {
377        TypeScheme {
378            vars: Vec::new(),
379            ty,
380        }
381    }
382
383    /// Create a polymorphic type scheme.
384    pub fn poly(vars: Vec<TypeVar>, ty: Type) -> Self {
385        TypeScheme { vars, ty }
386    }
387
388    /// Get free type variables in this scheme.
389    ///
390    /// Returns variables that appear in the type but aren't quantified.
391    pub fn free_vars(&self) -> HashSet<TypeVar> {
392        let mut free = self.ty.free_vars();
393        for var in &self.vars {
394            free.remove(var);
395        }
396        free
397    }
398
399    /// Apply a substitution to this type scheme.
400    ///
401    /// Quantified variables are protected from substitution.
402    pub fn apply(&self, subst: &Substitution) -> TypeScheme {
403        subst.apply_scheme(self)
404    }
405
406    /// Check if this scheme is monomorphic (no quantified variables).
407    pub fn is_mono(&self) -> bool {
408        self.vars.is_empty()
409    }
410
411    /// Get the underlying type (ignoring quantifiers).
412    pub fn inner_type(&self) -> &Type {
413        &self.ty
414    }
415}
416
417impl fmt::Display for TypeScheme {
418    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419        if self.vars.is_empty() {
420            write!(f, "{}", self.ty)
421        } else {
422            write!(f, "∀")?;
423            for (i, var) in self.vars.iter().enumerate() {
424                if i > 0 {
425                    write!(f, " ")?;
426                }
427                write!(f, "{}", var)?;
428            }
429            write!(f, ". {}", self.ty)
430        }
431    }
432}
433
434/// Type environment (Γ) mapping names to type schemes.
435///
436/// Represents the typing context during type inference.
437/// Supports scoping through parent environments.
438#[derive(Debug, Clone, PartialEq)]
439pub struct TypeEnv {
440    /// Bindings in this environment
441    bindings: HashMap<String, TypeScheme>,
442    /// Parent environment for scoping
443    parent: Option<Rc<TypeEnv>>,
444}
445
446impl TypeEnv {
447    /// Create an empty type environment.
448    pub fn new() -> Self {
449        TypeEnv {
450            bindings: HashMap::new(),
451            parent: None,
452        }
453    }
454
455    /// Create a type environment with a parent.
456    pub fn with_parent(parent: Rc<TypeEnv>) -> Self {
457        TypeEnv {
458            bindings: HashMap::new(),
459            parent: Some(parent),
460        }
461    }
462
463    /// Extend the environment with a new binding.
464    ///
465    /// Returns a new environment with the binding added.
466    /// The new environment has this environment as its parent.
467    pub fn extend(&self, name: String, scheme: TypeScheme) -> Self {
468        let mut bindings = HashMap::new();
469        bindings.insert(name, scheme);
470        TypeEnv {
471            bindings,
472            parent: Some(Rc::new(self.clone())),
473        }
474    }
475
476    /// Add a binding to this environment (mutating).
477    pub fn insert(&mut self, name: String, scheme: TypeScheme) {
478        self.bindings.insert(name, scheme);
479    }
480
481    /// Lookup a name in the environment.
482    ///
483    /// Searches this environment and all parent environments.
484    pub fn lookup(&self, name: &str) -> Option<&TypeScheme> {
485        self.bindings
486            .get(name)
487            .or_else(|| self.parent.as_ref().and_then(|parent| parent.lookup(name)))
488    }
489
490    /// Get all free type variables in the environment.
491    ///
492    /// Returns the union of free variables in all type schemes.
493    pub fn free_vars(&self) -> HashSet<TypeVar> {
494        let mut free: HashSet<TypeVar> = self
495            .bindings
496            .values()
497            .flat_map(|scheme| scheme.free_vars())
498            .collect();
499
500        if let Some(parent) = &self.parent {
501            free.extend(parent.free_vars());
502        }
503
504        free
505    }
506
507    /// Apply a substitution to all bindings in the environment.
508    pub fn apply(&self, subst: &Substitution) -> TypeEnv {
509        TypeEnv {
510            bindings: self
511                .bindings
512                .iter()
513                .map(|(name, scheme)| (name.clone(), scheme.apply(subst)))
514                .collect(),
515            parent: self.parent.as_ref().map(|p| Rc::new(p.apply(subst))),
516        }
517    }
518
519    /// Generalize a type to a type scheme.
520    ///
521    /// Quantifies over all type variables free in the type
522    /// but not free in the environment (closure).
523    pub fn generalize(&self, ty: &Type) -> TypeScheme {
524        let env_vars = self.free_vars();
525        let type_vars = ty.free_vars();
526
527        let quantified: Vec<TypeVar> = type_vars
528            .into_iter()
529            .filter(|v| !env_vars.contains(v))
530            .collect();
531
532        TypeScheme::poly(quantified, ty.clone())
533    }
534
535    /// Instantiate a type scheme with fresh type variables.
536    ///
537    /// Replaces all quantified variables with fresh type variables.
538    /// This is the opposite of generalization.
539    pub fn instantiate(
540        &self,
541        scheme: &TypeScheme,
542        fresh_var: &mut impl FnMut() -> TypeVar,
543    ) -> Type {
544        if scheme.vars.is_empty() {
545            return scheme.ty.clone();
546        }
547
548        let mut subst = Substitution::empty();
549        for var in &scheme.vars {
550            let fresh = fresh_var();
551            subst.insert(var.clone(), Type::Var(fresh));
552        }
553
554        scheme.ty.apply(&subst)
555    }
556
557    /// Check if the environment is empty.
558    pub fn is_empty(&self) -> bool {
559        self.bindings.is_empty() && self.parent.is_none()
560    }
561
562    /// Get the number of bindings in this environment (not including parent).
563    pub fn len(&self) -> usize {
564        self.bindings.len()
565    }
566
567    /// Get all bindings in this environment (not including parent).
568    pub fn bindings(&self) -> impl Iterator<Item = (&String, &TypeScheme)> {
569        self.bindings.iter()
570    }
571}
572
573impl Default for TypeEnv {
574    fn default() -> Self {
575        Self::new()
576    }
577}
578
579impl fmt::Display for TypeEnv {
580    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581        write!(f, "{{")?;
582        let mut first = true;
583        for (name, scheme) in &self.bindings {
584            if !first {
585                write!(f, ", ")?;
586            }
587            write!(f, "{}: {}", name, scheme)?;
588            first = false;
589        }
590        if let Some(parent) = &self.parent {
591            if !first {
592                write!(f, ", ")?;
593            }
594            write!(f, "parent: {}", parent)?;
595        }
596        write!(f, "}}")
597    }
598}
599
600#[cfg(test)]
601mod tests {
602    use super::*;
603
604    // ========================================================================
605    // TypeVar Tests
606    // ========================================================================
607
608    #[test]
609    fn test_typevar_new() {
610        let var = TypeVar::new(0, "a");
611        assert_eq!(var.id, 0);
612        assert_eq!(var.name, "a");
613    }
614
615    #[test]
616    fn test_typevar_fresh() {
617        let var = TypeVar::fresh(42);
618        assert_eq!(var.id, 42);
619        assert_eq!(var.name, "t42");
620    }
621
622    #[test]
623    fn test_typevar_display() {
624        let var = TypeVar::new(0, "a");
625        assert_eq!(format!("{}", var), "'a");
626    }
627
628    #[test]
629    fn test_typevar_equality() {
630        let var1 = TypeVar::new(0, "a");
631        let var2 = TypeVar::new(0, "a");
632        let var3 = TypeVar::new(1, "a");
633        assert_eq!(var1, var2);
634        assert_ne!(var1, var3);
635    }
636
637    #[test]
638    fn test_typevar_hash() {
639        let mut set = HashSet::new();
640        let var1 = TypeVar::new(0, "a");
641        let var2 = TypeVar::new(0, "a");
642        set.insert(var1.clone());
643        set.insert(var2);
644        assert_eq!(set.len(), 1);
645    }
646
647    // ========================================================================
648    // Type Tests
649    // ========================================================================
650
651    #[test]
652    fn test_type_primitives() {
653        assert_eq!(format!("{}", Type::Int), "int");
654        assert_eq!(format!("{}", Type::Bool), "bool");
655        assert_eq!(format!("{}", Type::String), "string");
656        assert_eq!(format!("{}", Type::Unit), "unit");
657        assert_eq!(format!("{}", Type::Float), "float");
658    }
659
660    #[test]
661    fn test_type_var() {
662        let var = TypeVar::new(0, "a");
663        let ty = Type::Var(var);
664        assert_eq!(format!("{}", ty), "'a");
665    }
666
667    #[test]
668    fn test_type_function() {
669        let ty = Type::Function(Box::new(Type::Int), Box::new(Type::Bool));
670        assert_eq!(format!("{}", ty), "int -> bool");
671    }
672
673    #[test]
674    fn test_type_function_nested() {
675        let ty = Type::Function(
676            Box::new(Type::Function(Box::new(Type::Int), Box::new(Type::Bool))),
677            Box::new(Type::String),
678        );
679        assert_eq!(format!("{}", ty), "(int -> bool) -> string");
680    }
681
682    #[test]
683    fn test_type_tuple() {
684        let ty = Type::Tuple(vec![Type::Int, Type::Bool, Type::String]);
685        assert_eq!(format!("{}", ty), "(int * bool * string)");
686    }
687
688    #[test]
689    fn test_type_list() {
690        let ty = Type::List(Box::new(Type::Int));
691        assert_eq!(format!("{}", ty), "int list");
692    }
693
694    #[test]
695    fn test_type_array() {
696        let ty = Type::Array(Box::new(Type::Bool));
697        assert_eq!(format!("{}", ty), "bool[]");
698    }
699
700    #[test]
701    fn test_type_record() {
702        let mut fields = HashMap::new();
703        fields.insert("x".to_string(), Type::Int);
704        fields.insert("y".to_string(), Type::Int);
705        let ty = Type::Record(fields);
706        let display = format!("{}", ty);
707        assert!(display.contains("x: int"));
708        assert!(display.contains("y: int"));
709    }
710
711    #[test]
712    fn test_type_variant_simple() {
713        let ty = Type::Variant("Option".to_string(), vec![]);
714        assert_eq!(format!("{}", ty), "Option");
715    }
716
717    #[test]
718    fn test_type_variant_with_params() {
719        let ty = Type::Variant("Option".to_string(), vec![Type::Int]);
720        assert_eq!(format!("{}", ty), "Option<int>");
721    }
722
723    #[test]
724    fn test_type_function_multi() {
725        let ty = Type::function_multi(&[Type::Int, Type::Bool], Type::String);
726        assert_eq!(format!("{}", ty), "int -> bool -> string");
727    }
728
729    // ========================================================================
730    // Type Free Variables Tests
731    // ========================================================================
732
733    #[test]
734    fn test_free_vars_primitives() {
735        assert!(Type::Int.free_vars().is_empty());
736        assert!(Type::Bool.free_vars().is_empty());
737        assert!(Type::String.free_vars().is_empty());
738        assert!(Type::Unit.free_vars().is_empty());
739    }
740
741    #[test]
742    fn test_free_vars_var() {
743        let var = TypeVar::new(0, "a");
744        let ty = Type::Var(var.clone());
745        let free = ty.free_vars();
746        assert_eq!(free.len(), 1);
747        assert!(free.contains(&var));
748    }
749
750    #[test]
751    fn test_free_vars_function() {
752        let var_a = TypeVar::new(0, "a");
753        let var_b = TypeVar::new(1, "b");
754        let ty = Type::Function(
755            Box::new(Type::Var(var_a.clone())),
756            Box::new(Type::Var(var_b.clone())),
757        );
758        let free = ty.free_vars();
759        assert_eq!(free.len(), 2);
760        assert!(free.contains(&var_a));
761        assert!(free.contains(&var_b));
762    }
763
764    #[test]
765    fn test_free_vars_tuple() {
766        let var = TypeVar::new(0, "a");
767        let ty = Type::Tuple(vec![Type::Int, Type::Var(var.clone()), Type::Bool]);
768        let free = ty.free_vars();
769        assert_eq!(free.len(), 1);
770        assert!(free.contains(&var));
771    }
772
773    #[test]
774    fn test_free_vars_list() {
775        let var = TypeVar::new(0, "a");
776        let ty = Type::List(Box::new(Type::Var(var.clone())));
777        let free = ty.free_vars();
778        assert_eq!(free.len(), 1);
779        assert!(free.contains(&var));
780    }
781
782    // ========================================================================
783    // Occurs Check Tests
784    // ========================================================================
785
786    #[test]
787    fn test_occurs_check_var_in_var() {
788        let var = TypeVar::new(0, "a");
789        let ty = Type::Var(var.clone());
790        assert!(ty.occurs_check(&var));
791    }
792
793    #[test]
794    fn test_occurs_check_var_not_in_primitive() {
795        let var = TypeVar::new(0, "a");
796        assert!(!Type::Int.occurs_check(&var));
797        assert!(!Type::Bool.occurs_check(&var));
798    }
799
800    #[test]
801    fn test_occurs_check_var_in_function() {
802        let var = TypeVar::new(0, "a");
803        let ty = Type::Function(Box::new(Type::Var(var.clone())), Box::new(Type::Int));
804        assert!(ty.occurs_check(&var));
805    }
806
807    #[test]
808    fn test_occurs_check_var_not_in_function() {
809        let var = TypeVar::new(0, "a");
810        let ty = Type::Function(Box::new(Type::Int), Box::new(Type::Bool));
811        assert!(!ty.occurs_check(&var));
812    }
813
814    #[test]
815    fn test_occurs_check_var_in_tuple() {
816        let var = TypeVar::new(0, "a");
817        let ty = Type::Tuple(vec![Type::Int, Type::Var(var.clone())]);
818        assert!(ty.occurs_check(&var));
819    }
820
821    #[test]
822    fn test_occurs_check_var_in_list() {
823        let var = TypeVar::new(0, "a");
824        let ty = Type::List(Box::new(Type::Var(var.clone())));
825        assert!(ty.occurs_check(&var));
826    }
827
828    // ========================================================================
829    // Substitution Tests
830    // ========================================================================
831
832    #[test]
833    fn test_substitution_empty() {
834        let subst = Substitution::empty();
835        assert!(subst.is_empty());
836        assert_eq!(subst.len(), 0);
837    }
838
839    #[test]
840    fn test_substitution_singleton() {
841        let var = TypeVar::new(0, "a");
842        let subst = Substitution::singleton(var.clone(), Type::Int);
843        assert_eq!(subst.len(), 1);
844        assert_eq!(subst.lookup(&var), Some(Type::Int));
845    }
846
847    #[test]
848    fn test_substitution_lookup() {
849        let var = TypeVar::new(0, "a");
850        let subst = Substitution::singleton(var.clone(), Type::Int);
851        assert_eq!(subst.lookup(&var), Some(Type::Int));
852
853        let other_var = TypeVar::new(1, "b");
854        assert_eq!(subst.lookup(&other_var), None);
855    }
856
857    #[test]
858    fn test_substitution_apply_var() {
859        let var = TypeVar::new(0, "a");
860        let subst = Substitution::singleton(var.clone(), Type::Int);
861        let ty = Type::Var(var);
862        assert_eq!(subst.apply_type(&ty), Type::Int);
863    }
864
865    #[test]
866    fn test_substitution_apply_function() {
867        let var_a = TypeVar::new(0, "a");
868        let var_b = TypeVar::new(1, "b");
869        let mut subst = Substitution::empty();
870        subst.insert(var_a.clone(), Type::Int);
871        subst.insert(var_b.clone(), Type::Bool);
872
873        let ty = Type::Function(Box::new(Type::Var(var_a)), Box::new(Type::Var(var_b)));
874        let result = subst.apply_type(&ty);
875        assert_eq!(
876            result,
877            Type::Function(Box::new(Type::Int), Box::new(Type::Bool))
878        );
879    }
880
881    #[test]
882    fn test_substitution_compose_empty() {
883        let s1 = Substitution::empty();
884        let s2 = Substitution::empty();
885        let result = Substitution::compose(&s1, &s2);
886        assert!(result.is_empty());
887    }
888
889    #[test]
890    fn test_substitution_compose_basic() {
891        let var_a = TypeVar::new(0, "a");
892        let var_b = TypeVar::new(1, "b");
893
894        let s1 = Substitution::singleton(var_a.clone(), Type::Int);
895        let s2 = Substitution::singleton(var_b.clone(), Type::Var(var_a.clone()));
896
897        let result = Substitution::compose(&s1, &s2);
898
899        // s2[b -> a], then s1[a -> int], so b -> int
900        assert_eq!(result.lookup(&var_b), Some(Type::Int));
901    }
902
903    #[test]
904    fn test_substitution_display() {
905        let var = TypeVar::new(0, "a");
906        let subst = Substitution::singleton(var, Type::Int);
907        let display = format!("{}", subst);
908        assert!(display.contains("'a"));
909        assert!(display.contains("int"));
910    }
911
912    // ========================================================================
913    // TypeScheme Tests
914    // ========================================================================
915
916    #[test]
917    fn test_typescheme_mono() {
918        let scheme = TypeScheme::mono(Type::Int);
919        assert!(scheme.is_mono());
920        assert_eq!(scheme.inner_type(), &Type::Int);
921        assert_eq!(format!("{}", scheme), "int");
922    }
923
924    #[test]
925    fn test_typescheme_poly() {
926        let var = TypeVar::new(0, "a");
927        let scheme = TypeScheme::poly(vec![var.clone()], Type::Var(var));
928        assert!(!scheme.is_mono());
929        assert_eq!(format!("{}", scheme), "∀'a. 'a");
930    }
931
932    #[test]
933    fn test_typescheme_free_vars_mono() {
934        let var = TypeVar::new(0, "a");
935        let scheme = TypeScheme::mono(Type::Var(var.clone()));
936        let free = scheme.free_vars();
937        assert_eq!(free.len(), 1);
938        assert!(free.contains(&var));
939    }
940
941    #[test]
942    fn test_typescheme_free_vars_poly() {
943        let var = TypeVar::new(0, "a");
944        let scheme = TypeScheme::poly(vec![var.clone()], Type::Var(var.clone()));
945        let free = scheme.free_vars();
946        assert!(free.is_empty()); // 'a is quantified
947    }
948
949    #[test]
950    fn test_typescheme_apply() {
951        let var_a = TypeVar::new(0, "a");
952        let var_b = TypeVar::new(1, "b");
953        let scheme = TypeScheme::poly(
954            vec![var_a.clone()],
955            Type::Function(
956                Box::new(Type::Var(var_a.clone())),
957                Box::new(Type::Var(var_b.clone())),
958            ),
959        );
960
961        let subst = Substitution::singleton(var_b.clone(), Type::Int);
962        let result = scheme.apply(&subst);
963
964        // 'a should not be substituted (quantified), but 'b should
965        assert_eq!(
966            result.ty,
967            Type::Function(Box::new(Type::Var(var_a)), Box::new(Type::Int))
968        );
969    }
970
971    // ========================================================================
972    // TypeEnv Tests
973    // ========================================================================
974
975    #[test]
976    fn test_typeenv_new() {
977        let env = TypeEnv::new();
978        assert!(env.is_empty());
979        assert_eq!(env.len(), 0);
980    }
981
982    #[test]
983    fn test_typeenv_insert() {
984        let mut env = TypeEnv::new();
985        env.insert("x".to_string(), TypeScheme::mono(Type::Int));
986        assert_eq!(env.len(), 1);
987        assert!(env.lookup("x").is_some());
988    }
989
990    #[test]
991    fn test_typeenv_lookup() {
992        let mut env = TypeEnv::new();
993        env.insert("x".to_string(), TypeScheme::mono(Type::Int));
994        assert_eq!(env.lookup("x").unwrap().inner_type(), &Type::Int);
995        assert!(env.lookup("y").is_none());
996    }
997
998    #[test]
999    fn test_typeenv_extend() {
1000        let env1 = TypeEnv::new();
1001        let env2 = env1.extend("x".to_string(), TypeScheme::mono(Type::Int));
1002        assert!(env1.lookup("x").is_none());
1003        assert!(env2.lookup("x").is_some());
1004    }
1005
1006    #[test]
1007    fn test_typeenv_lookup_parent() {
1008        let mut env1 = TypeEnv::new();
1009        env1.insert("x".to_string(), TypeScheme::mono(Type::Int));
1010        let env2 = TypeEnv::with_parent(Rc::new(env1));
1011        assert!(env2.lookup("x").is_some());
1012    }
1013
1014    #[test]
1015    fn test_typeenv_free_vars() {
1016        let var = TypeVar::new(0, "a");
1017        let mut env = TypeEnv::new();
1018        env.insert("x".to_string(), TypeScheme::mono(Type::Var(var.clone())));
1019        let free = env.free_vars();
1020        assert_eq!(free.len(), 1);
1021        assert!(free.contains(&var));
1022    }
1023
1024    #[test]
1025    fn test_typeenv_generalize() {
1026        let var = TypeVar::new(0, "a");
1027        let env = TypeEnv::new();
1028        let scheme = env.generalize(&Type::Var(var.clone()));
1029        assert_eq!(scheme.vars.len(), 1);
1030        assert_eq!(scheme.vars[0], var);
1031    }
1032
1033    #[test]
1034    fn test_typeenv_generalize_with_env_vars() {
1035        let var_a = TypeVar::new(0, "a");
1036        let var_b = TypeVar::new(1, "b");
1037
1038        let mut env = TypeEnv::new();
1039        env.insert("x".to_string(), TypeScheme::mono(Type::Var(var_a.clone())));
1040
1041        // Type contains both 'a and 'b, but 'a is in environment
1042        let ty = Type::Function(
1043            Box::new(Type::Var(var_a.clone())),
1044            Box::new(Type::Var(var_b.clone())),
1045        );
1046        let scheme = env.generalize(&ty);
1047
1048        // Only 'b should be quantified
1049        assert_eq!(scheme.vars.len(), 1);
1050        assert_eq!(scheme.vars[0], var_b);
1051    }
1052
1053    #[test]
1054    fn test_typeenv_instantiate() {
1055        let var = TypeVar::new(0, "a");
1056        let scheme = TypeScheme::poly(vec![var.clone()], Type::Var(var));
1057
1058        let env = TypeEnv::new();
1059        let mut counter = 100;
1060        let result = env.instantiate(&scheme, &mut || {
1061            counter += 1;
1062            TypeVar::fresh(counter)
1063        });
1064
1065        // Should get a fresh type variable
1066        match result {
1067            Type::Var(v) => {
1068                assert_eq!(v.id, 101);
1069                assert_eq!(v.name, "t101");
1070            }
1071            _ => panic!("Expected type variable"),
1072        }
1073    }
1074
1075    #[test]
1076    fn test_typeenv_apply() {
1077        let var = TypeVar::new(0, "a");
1078        let mut env = TypeEnv::new();
1079        env.insert("x".to_string(), TypeScheme::mono(Type::Var(var.clone())));
1080
1081        let subst = Substitution::singleton(var, Type::Int);
1082        let new_env = env.apply(&subst);
1083
1084        assert_eq!(new_env.lookup("x").unwrap().inner_type(), &Type::Int);
1085    }
1086
1087    #[test]
1088    fn test_typeenv_bindings() {
1089        let mut env = TypeEnv::new();
1090        env.insert("x".to_string(), TypeScheme::mono(Type::Int));
1091        env.insert("y".to_string(), TypeScheme::mono(Type::Bool));
1092
1093        let bindings: Vec<_> = env.bindings().collect();
1094        assert_eq!(bindings.len(), 2);
1095    }
1096
1097    // ========================================================================
1098    // Integration Tests
1099    // ========================================================================
1100
1101    #[test]
1102    fn test_integration_simple_substitution() {
1103        let var = TypeVar::new(0, "a");
1104        let ty = Type::Function(
1105            Box::new(Type::Var(var.clone())),
1106            Box::new(Type::Var(var.clone())),
1107        );
1108        let subst = Substitution::singleton(var, Type::Int);
1109        let result = ty.apply(&subst);
1110        assert_eq!(
1111            result,
1112            Type::Function(Box::new(Type::Int), Box::new(Type::Int))
1113        );
1114    }
1115
1116    #[test]
1117    fn test_integration_generalize_instantiate() {
1118        let var = TypeVar::new(0, "a");
1119        let ty = Type::Var(var.clone());
1120
1121        let env = TypeEnv::new();
1122        let scheme = env.generalize(&ty);
1123
1124        let mut counter = 0;
1125        let result = env.instantiate(&scheme, &mut || {
1126            counter += 1;
1127            TypeVar::fresh(counter)
1128        });
1129
1130        // Should get a fresh variable different from the original
1131        match result {
1132            Type::Var(v) => assert_ne!(v.id, var.id),
1133            _ => panic!("Expected type variable"),
1134        }
1135    }
1136
1137    #[test]
1138    fn test_integration_complex_type() {
1139        // (int -> 'a) -> 'a list
1140        let var = TypeVar::new(0, "a");
1141        let ty = Type::Function(
1142            Box::new(Type::Function(
1143                Box::new(Type::Int),
1144                Box::new(Type::Var(var.clone())),
1145            )),
1146            Box::new(Type::List(Box::new(Type::Var(var.clone())))),
1147        );
1148
1149        let free = ty.free_vars();
1150        assert_eq!(free.len(), 1);
1151        assert!(free.contains(&var));
1152
1153        let subst = Substitution::singleton(var, Type::Bool);
1154        let result = ty.apply(&subst);
1155
1156        assert_eq!(
1157            result,
1158            Type::Function(
1159                Box::new(Type::Function(Box::new(Type::Int), Box::new(Type::Bool))),
1160                Box::new(Type::List(Box::new(Type::Bool))),
1161            )
1162        );
1163    }
1164}