cl_typeck/
type_expression.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! A [TypeExpression] is a [syntactic](cl_ast) representation of a [TypeKind], and is used to
//! construct type bindings in a [Table]'s typing context.

use crate::{handle::Handle, table::Table, type_kind::TypeKind};
use cl_ast::{PathPart, Ty, TyArray, TyFn, TyKind, TyRef, TySlice, TyTuple};

#[derive(Clone, Debug, PartialEq, Eq)] // TODO: impl Display and Error
pub enum Error {
    BadPath { parent: Handle, path: Vec<PathPart> },
}

impl std::error::Error for Error {}
impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Error::BadPath { parent, path } => {
                write!(f, "No item at path {parent}")?;
                for part in path {
                    write!(f, "::{part}")?;
                }
            }
        }
        Ok(())
    }
}

/// A [TypeExpression] is a syntactic representation of a [TypeKind], and is used to construct
/// type bindings in a [Table]'s typing context.
pub trait TypeExpression<Out = Handle> {
    /// Evaluates a type expression, recursively creating intermediate bindings.
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Out, Error>;
}

impl TypeExpression for Ty {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        self.kind.evaluate(table, node)
    }
}

impl TypeExpression for TyKind {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        match self {
            TyKind::Never => Ok(table.anon_type(TypeKind::Never)),
            TyKind::Empty => Ok(table.anon_type(TypeKind::Empty)),
            TyKind::Path(p) => p.evaluate(table, node),
            TyKind::Array(a) => a.evaluate(table, node),
            TyKind::Slice(s) => s.evaluate(table, node),
            TyKind::Tuple(t) => t.evaluate(table, node),
            TyKind::Ref(r) => r.evaluate(table, node),
            TyKind::Fn(f) => f.evaluate(table, node),
        }
    }
}

impl TypeExpression for cl_ast::Path {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        let Self { absolute, parts } = self;
        parts.evaluate(table, if *absolute { table.root() } else { node })
    }
}

impl TypeExpression for [PathPart] {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        table
            .nav(node, self)
            .ok_or_else(|| Error::BadPath { parent: node, path: self.to_owned() })
    }
}

impl TypeExpression for TyArray {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        let Self { ty, count } = self;
        let kind = TypeKind::Array(ty.evaluate(table, node)?, *count);
        Ok(table.anon_type(kind))
    }
}

impl TypeExpression for TySlice {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        let Self { ty } = self;
        let kind = TypeKind::Slice(ty.evaluate(table, node)?);
        Ok(table.anon_type(kind))
    }
}

impl TypeExpression for TyTuple {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        let Self { types } = self;
        let kind = match types.len() {
            0 => TypeKind::Empty,
            _ => TypeKind::Tuple(types.evaluate(table, node)?),
        };
        Ok(table.anon_type(kind))
    }
}

impl TypeExpression for TyRef {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        let Self { mutable: _, count, to } = self;
        let mut t = to.evaluate(table, node)?;
        for _ in 0..*count {
            let kind = TypeKind::Ref(t);
            t = table.anon_type(kind)
        }
        Ok(t)
    }
}

impl TypeExpression for TyFn {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
        let Self { args, rety } = self;
        let kind = TypeKind::FnSig {
            args: args.evaluate(table, node)?,
            rety: match rety {
                Some(ty) => ty.evaluate(table, node)?,
                None => TyKind::Empty.evaluate(table, node)?,
            },
        };
        Ok(table.anon_type(kind))
    }
}

impl<T: TypeExpression<U>, U> TypeExpression<Vec<U>> for [T] {
    fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Vec<U>, Error> {
        let mut out = Vec::with_capacity(self.len());
        for te in self {
            out.push(te.evaluate(table, node)?) // try_collect is unstable
        }
        Ok(out)
    }
}