glyph_types/
lib.rs

1//! Glyph Type System
2//!
3//! Implements the gradual type system for Glyph with support for
4//! type inference and runtime type checking.
5
6use serde::{Deserialize, Serialize};
7use std::fmt;
8use thiserror::Error;
9
10pub mod inference;
11pub mod value;
12
13pub use value::Value;
14
15/// Type representation in the Glyph type system
16#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
17pub enum Type {
18    // Primitives
19    Int,
20    Float,
21    Str,
22    Bool,
23    Bytes,
24    Unit,
25
26    // Containers
27    List(Box<Type>),
28    Dict(Box<Type>, Box<Type>),
29    Optional(Box<Type>),
30
31    // Special types
32    Promise(Box<Type>),
33    Result(Box<Type>, Box<Type>),
34
35    // Functions
36    Function {
37        params: Vec<(String, Type)>,
38        return_type: Box<Type>,
39    },
40
41    // Type variables for inference
42    TypeVar(u32),
43
44    // Unknown type (for gradual typing)
45    Unknown,
46}
47
48impl Type {
49    /// Check if this type is assignable to another type
50    pub fn is_assignable_to(&self, other: &Type) -> bool {
51        match (self, other) {
52            // Exact match
53            (t1, t2) if t1 == t2 => true,
54
55            // Unknown is assignable to/from anything (gradual typing)
56            (Type::Unknown, _) | (_, Type::Unknown) => true,
57
58            // Container types
59            (Type::List(t1), Type::List(t2)) => t1.is_assignable_to(t2),
60            (Type::Optional(t1), Type::Optional(t2)) => t1.is_assignable_to(t2),
61            (Type::Promise(t1), Type::Promise(t2)) => t1.is_assignable_to(t2),
62
63            // Result types
64            (Type::Result(ok1, err1), Type::Result(ok2, err2)) => {
65                ok1.is_assignable_to(ok2) && err1.is_assignable_to(err2)
66            }
67
68            // Dict types
69            (Type::Dict(k1, v1), Type::Dict(k2, v2)) => {
70                k1.is_assignable_to(k2) && v1.is_assignable_to(v2)
71            }
72
73            // Function types (contravariant in params, covariant in return)
74            (
75                Type::Function {
76                    params: p1,
77                    return_type: r1,
78                },
79                Type::Function {
80                    params: p2,
81                    return_type: r2,
82                },
83            ) => {
84                p1.len() == p2.len()
85                    && p1
86                        .iter()
87                        .zip(p2.iter())
88                        .all(|((_, t1), (_, t2))| t2.is_assignable_to(t1))
89                    && r1.is_assignable_to(r2)
90            }
91
92            _ => false,
93        }
94    }
95}
96
97impl fmt::Display for Type {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        match self {
100            Type::Int => write!(f, "int"),
101            Type::Float => write!(f, "float"),
102            Type::Str => write!(f, "str"),
103            Type::Bool => write!(f, "bool"),
104            Type::Bytes => write!(f, "bytes"),
105            Type::Unit => write!(f, "unit"),
106            Type::List(t) => write!(f, "list[{t}]"),
107            Type::Dict(k, v) => write!(f, "dict[{k}, {v}]"),
108            Type::Optional(t) => write!(f, "optional[{t}]"),
109            Type::Promise(t) => write!(f, "promise[{t}]"),
110            Type::Result(ok, err) => write!(f, "result[{ok}, {err}]"),
111            Type::Function {
112                params,
113                return_type,
114            } => {
115                write!(f, "(")?;
116                for (i, (name, typ)) in params.iter().enumerate() {
117                    if i > 0 {
118                        write!(f, ", ")?;
119                    }
120                    write!(f, "{name}: {typ}")?;
121                }
122                write!(f, ") -> {return_type}")
123            }
124            Type::TypeVar(id) => write!(f, "T{id}"),
125            Type::Unknown => write!(f, "?"),
126        }
127    }
128}
129
130#[derive(Debug, Error)]
131pub enum TypeError {
132    #[error("Type mismatch: expected {expected}, found {found}")]
133    TypeMismatch { expected: Type, found: Type },
134
135    #[error("Undefined variable: {0}")]
136    UndefinedVariable(String),
137
138    #[error("Cannot call non-function type: {0}")]
139    NotCallable(Type),
140
141    #[error("Wrong number of arguments: expected {expected}, found {found}")]
142    ArgumentCountMismatch { expected: usize, found: usize },
143
144    #[error("Cannot access attribute '{attr}' on type {typ}")]
145    AttributeError { attr: String, typ: Type },
146
147    #[error("Type inference failed: {0}")]
148    InferenceFailed(String),
149}