Skip to main content

cl_typeck/
type_expression.rs

1//! A [TypeExpression] is a [syntactic](cl_ast) representation of a [TypeKind], and is used to
2//! construct type bindings in a [Table]'s typing context.
3
4use crate::{consteval::ConstEval, handle::Handle, table::Table, type_kind::TypeKind};
5use cl_ast::{AstNode, AstTypes, At, Expr, Pat, PatOp, types::Symbol};
6
7#[derive(Clone, Debug, PartialEq, Eq)] // TODO: impl Display and Error
8pub enum Error {
9    BadPath { parent: Handle, path: Vec<Symbol> },
10    ConstEval { parent: Handle, eval: Box<At<Expr>> },
11}
12
13impl std::error::Error for Error {}
14impl std::fmt::Display for Error {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        match self {
17            Error::BadPath { parent, path } => {
18                write!(f, "No item at path {parent}")?;
19                for part in path {
20                    write!(f, "::{part}")?;
21                }
22            }
23            Error::ConstEval { parent, eval } => {
24                write!(f, "Failed to evaluate constant {eval} in {parent}")?;
25            }
26        }
27        Ok(())
28    }
29}
30
31/// A [TypeExpression] is a syntactic representation of a [TypeKind], and is used to construct
32/// type bindings in a [Table]'s typing context.
33pub trait TypeExpression<Out = Handle> {
34    /// Evaluates a type expression, recursively creating intermediate bindings.
35    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Out, Error>;
36}
37
38impl TypeExpression for Pat {
39    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
40        match self {
41            Pat::Ignore => Ok(table.inferred_type()),
42            Pat::Never => Ok(table.get_lang_item("never")),
43            Pat::MetId(_) => todo!(),
44            Pat::Name(name) => name.evaluate(table, node),
45            Pat::Value(expr) => expr.0.evaluate(table, node),
46
47            Pat::Op(PatOp::MetaInner | PatOp::MetaOuter, pats) if let [pat] = &pats[..] => {
48                pat.evaluate(table, node)
49            }
50            Pat::Op(PatOp::Pub, pats) if let [pat] = &pats[..] => pat.evaluate(table, node),
51            Pat::Op(PatOp::Mut, pats) if let [pat] = &pats[..] => pat.evaluate(table, node),
52            Pat::Op(PatOp::Ref, pats) if let [pat] = &pats[..] => {
53                let ty = pat.evaluate(table, node)?;
54                Ok(table.anon_type(TypeKind::Ref(ty)))
55            }
56            Pat::Op(PatOp::Ptr, pats) if let [pat] = &pats[..] => {
57                let ty = pat.evaluate(table, node)?;
58                Ok(table.anon_type(TypeKind::Ptr(ty)))
59            }
60            Pat::Op(PatOp::Guard, pats) if let [pat, _g] = &pats[..] => pat.evaluate(table, node),
61            Pat::Op(PatOp::Rest, _pats) => Ok(table.inferred_type()),
62            Pat::Op(PatOp::RangeEx, _pats) => todo!(),
63            Pat::Op(PatOp::RangeIn, _pats) => todo!(),
64            Pat::Op(PatOp::Record, pats) => {
65                let tys = pats.evaluate(table, node)?;
66                todo!("Anonymous record destructuring {tys:?} in {self}")
67            }
68            Pat::Op(PatOp::Tuple, pats) => {
69                let tys = pats.evaluate(table, node)?;
70                Ok(table.anon_type(TypeKind::Tuple(tys)))
71            }
72            Pat::Op(PatOp::Slice, _) => todo!(""),
73            Pat::Op(PatOp::ArRep, pats) if let [pat, rep] = &pats[..] => {
74                let ty = pat.evaluate(table, node)?;
75                let rep = match rep.value() {
76                    Self::Value(at) => at
77                        .const_eval()
78                        .ok_or_else(|| Error::ConstEval { parent: node, eval: at.clone() }),
79                    _ => todo!("{rep} in array-repetition patterns"),
80                }?;
81                Ok(table.anon_type(TypeKind::Array(ty, rep as _)))
82            }
83            Pat::Op(PatOp::Typed, pats) if let [_, pat] = &pats[..] => {
84                Ok(pat.evaluate(table, node)?)
85            }
86            Pat::Op(PatOp::TypePrefixed, pats) => todo!("TypePrefixed {pats:?}"),
87            Pat::Op(PatOp::Generic, pats) if let [pat, ..] = &pats[..] => {
88                Ok(pat.evaluate(table, node)?)
89            }
90            Pat::Op(PatOp::Fn, pats) => todo!("Fn {pats:?}"),
91            Pat::Op(PatOp::Alt, pats) => todo!("Alt {pats:?}"),
92            _ => unreachable!(),
93        }
94    }
95}
96
97impl TypeExpression for cl_ast::Expr {
98    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
99        match self {
100            Self::Omitted => Ok(table.anon_type(TypeKind::Tuple(vec![]))),
101            Self::Id(path) => path.evaluate(table, node),
102            Self::MetId(_) => todo!("Metaidentifiers in resolver"),
103            Self::Lit(lit) => todo!("Literals ({lit}) in type expressions!"),
104            Self::Use(item) => todo!("Use-items ({item}) in type expressions!??!"),
105            Self::Bind(bind) => todo!("Bind-items ({bind}) in type expressions!"),
106            Self::Make(make) => todo!("Make-items ({make}) in type expressions!"),
107            Self::Match(mtch) => todo!("Match-exprs ({mtch}) in type expressions!"),
108            Self::Op(op, ats) => todo!("Op({op}, {ats:?})"),
109        }
110    }
111}
112
113impl TypeExpression for cl_ast::types::Path {
114    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
115        let Self { parts } = self;
116        parts.evaluate(table, node)
117    }
118}
119
120impl TypeExpression for [Symbol] {
121    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
122        table
123            .nav(node, self)
124            .ok_or_else(|| Error::BadPath { parent: node, path: self.to_owned() })
125    }
126}
127
128impl TypeExpression for Symbol {
129    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
130        let path = [*self];
131        table
132            .nav(node, &path)
133            .ok_or_else(|| Error::BadPath { parent: node, path: path.to_vec() })
134    }
135}
136
137impl<T: TypeExpression<U>, U> TypeExpression<Vec<U>> for [T] {
138    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Vec<U>, Error> {
139        let mut out = Vec::with_capacity(self.len());
140        for te in self {
141            out.push(te.evaluate(table, node)?) // try_collect is unstable
142        }
143        Ok(out)
144    }
145}
146
147impl<T: TypeExpression<U> + AstNode, U, A: AstTypes> TypeExpression<U> for At<T, A> {
148    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<U, Error> {
149        self.0.evaluate(table, node)
150    }
151}