Skip to main content

aver/ast/
types.rs

1/// Aver static type representation.
2///
3/// Lives under `crate::ast` so that `Spanned<T>` can carry an optional
4/// `Type` annotation without forming a cycle through `crate::types`
5/// (which depends on `crate::ast`). The original `crate::types::Type`
6/// is re-exported from here for backward compatibility.
7
8#[derive(Debug, Clone, PartialEq)]
9pub enum Type {
10    Int,
11    Float,
12    Str,
13    Bool,
14    Unit,
15    Result(Box<Type>, Box<Type>),
16    Option(Box<Type>),
17    List(Box<Type>),
18    Tuple(Vec<Type>),
19    Map(Box<Type>, Box<Type>),
20    Vector(Box<Type>),
21    Fn(Vec<Type>, Box<Type>, Vec<String>),
22    Var(String), // named type variable in polymorphic builtin signatures (instantiated at call site)
23    Invalid,     // checker recovery after an earlier error; never compatible with concrete types
24    Named(String), // user-defined type: Shape, User, etc.
25}
26
27impl Type {
28    /// `a.compatible(b)` — can a value of type `self` be used where `other` is expected?
29    /// Two concrete types must be equal (structurally) to be compatible. Type variables
30    /// are resolved by the type checker at call sites, not by this raw relation.
31    pub fn compatible(&self, other: &Type) -> bool {
32        match (self, other) {
33            (Type::Int, Type::Int) => true,
34            (Type::Float, Type::Float) => true,
35            (Type::Str, Type::Str) => true,
36            (Type::Bool, Type::Bool) => true,
37            (Type::Unit, Type::Unit) => true,
38            (Type::Var(a), Type::Var(b)) => a == b,
39            (Type::Invalid, _) | (_, Type::Invalid) => false,
40            (Type::Result(a1, b1), Type::Result(a2, b2)) => a1.compatible(a2) && b1.compatible(b2),
41            (Type::Option(a), Type::Option(b)) => a.compatible(b),
42            (Type::List(a), Type::List(b)) => a.compatible(b),
43            (Type::Tuple(a), Type::Tuple(b)) => {
44                a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.compatible(y))
45            }
46            (Type::Map(k1, v1), Type::Map(k2, v2)) => k1.compatible(k2) && v1.compatible(v2),
47            (Type::Vector(a), Type::Vector(b)) => a.compatible(b),
48            (Type::Fn(p1, r1, e1), Type::Fn(p2, r2, e2)) => {
49                p1.len() == p2.len()
50                    && p1.iter().zip(p2.iter()).all(|(a, b)| a.compatible(b))
51                    && r1.compatible(r2)
52                    && e1.iter().all(|actual| {
53                        e2.iter()
54                            .any(|expected| crate::effects::effect_satisfies(expected, actual))
55                    })
56            }
57            (Type::Named(a), Type::Named(b)) => {
58                a == b || a.ends_with(&format!(".{}", b)) || b.ends_with(&format!(".{}", a))
59            }
60            _ => false,
61        }
62    }
63
64    pub fn display(&self) -> String {
65        match self {
66            Type::Int => "Int".to_string(),
67            Type::Float => "Float".to_string(),
68            Type::Str => "String".to_string(),
69            Type::Bool => "Bool".to_string(),
70            Type::Unit => "Unit".to_string(),
71            Type::Result(ok, err) => format!("Result<{}, {}>", ok.display(), err.display()),
72            Type::Option(inner) => format!("Option<{}>", inner.display()),
73            Type::List(inner) => format!("List<{}>", inner.display()),
74            Type::Tuple(items) => format!(
75                "({})",
76                items
77                    .iter()
78                    .map(Type::display)
79                    .collect::<Vec<_>>()
80                    .join(", ")
81            ),
82            Type::Map(key, value) => format!("Map<{}, {}>", key.display(), value.display()),
83            Type::Vector(inner) => format!("Vector<{}>", inner.display()),
84            Type::Fn(params, ret, effects) => {
85                let ps: Vec<String> = params.iter().map(|p| p.display()).collect();
86                if effects.is_empty() {
87                    format!("Fn({}) -> {}", ps.join(", "), ret.display())
88                } else {
89                    format!(
90                        "Fn({}) -> {} ! [{}]",
91                        ps.join(", "),
92                        ret.display(),
93                        effects.join(", ")
94                    )
95                }
96            }
97            Type::Var(name) => name.clone(),
98            Type::Invalid => "Invalid".to_string(),
99            Type::Named(n) => n.clone(),
100        }
101    }
102}