Skip to main content

lex_types/
error.rs

1//! Structured type errors per spec ยง6.7.
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(tag = "kind", rename_all = "snake_case")]
7pub enum TypeError {
8    TypeMismatch {
9        at_node: String,
10        expected: String,
11        got: String,
12        context: Vec<String>,
13    },
14    UnknownIdentifier {
15        at_node: String,
16        name: String,
17    },
18    ArityMismatch {
19        at_node: String,
20        expected: usize,
21        got: usize,
22    },
23    NonExhaustiveMatch {
24        at_node: String,
25        missing: Vec<String>,
26    },
27    UnknownField {
28        at_node: String,
29        record_type: String,
30        field: String,
31    },
32    DuplicateField {
33        at_node: String,
34        field: String,
35    },
36    UnknownVariant {
37        at_node: String,
38        constructor: String,
39    },
40    EffectNotDeclared {
41        at_node: String,
42        effect: String,
43    },
44    InfiniteType {
45        at_node: String,
46    },
47    AmbiguousType {
48        at_node: String,
49    },
50    RecursiveTypeWithoutConstructor {
51        at_node: String,
52        name: String,
53    },
54    /// Refinement-type predicate provably violated at a call site
55    /// (#209 slice 2). The type checker statically discharged the
56    /// refinement and found the literal argument doesn't satisfy the
57    /// predicate. Slice 3 will add residual runtime checks for
58    /// arguments that can't be discharged statically.
59    RefinementViolation {
60        at_node: String,
61        fn_name: String,
62        param_index: usize,
63        binding: String,
64        reason: String,
65    },
66}
67
68impl TypeError {
69    pub fn node(&self) -> &str {
70        match self {
71            TypeError::TypeMismatch { at_node, .. }
72            | TypeError::UnknownIdentifier { at_node, .. }
73            | TypeError::ArityMismatch { at_node, .. }
74            | TypeError::NonExhaustiveMatch { at_node, .. }
75            | TypeError::UnknownField { at_node, .. }
76            | TypeError::DuplicateField { at_node, .. }
77            | TypeError::UnknownVariant { at_node, .. }
78            | TypeError::EffectNotDeclared { at_node, .. }
79            | TypeError::InfiniteType { at_node, .. }
80            | TypeError::AmbiguousType { at_node, .. }
81            | TypeError::RecursiveTypeWithoutConstructor { at_node, .. }
82            | TypeError::RefinementViolation { at_node, .. } => at_node,
83        }
84    }
85}
86
87impl std::fmt::Display for TypeError {
88    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
89        match self {
90            TypeError::TypeMismatch { at_node, expected, got, context } => {
91                write!(f, "type mismatch at {at_node}: expected {expected}, got {got}")?;
92                if !context.is_empty() { write!(f, " ({})", context.join(" / "))?; }
93                Ok(())
94            }
95            TypeError::UnknownIdentifier { at_node, name } => write!(f, "unknown identifier `{name}` at {at_node}"),
96            TypeError::ArityMismatch { at_node, expected, got } => write!(f, "arity mismatch at {at_node}: expected {expected}, got {got}"),
97            TypeError::NonExhaustiveMatch { at_node, missing } => write!(f, "non-exhaustive match at {at_node}: missing {missing:?}"),
98            TypeError::UnknownField { at_node, record_type, field } => write!(f, "unknown field `{field}` on {record_type} at {at_node}"),
99            TypeError::DuplicateField { at_node, field } => write!(f, "duplicate field `{field}` at {at_node}"),
100            TypeError::UnknownVariant { at_node, constructor } => write!(f, "unknown constructor `{constructor}` at {at_node}"),
101            TypeError::EffectNotDeclared { at_node, effect } => write!(f, "effect `{effect}` not declared at {at_node}"),
102            TypeError::InfiniteType { at_node } => write!(f, "infinite type (occurs check) at {at_node}"),
103            TypeError::AmbiguousType { at_node } => write!(f, "ambiguous type at {at_node}"),
104            TypeError::RecursiveTypeWithoutConstructor { at_node, name } => write!(f, "recursive type {name} has no constructor at {at_node}"),
105            TypeError::RefinementViolation { at_node, fn_name, param_index, binding, reason } =>
106                write!(f, "refinement violated at {at_node}: argument {} of `{fn_name}` (binding `{binding}`): {reason}",
107                    param_index + 1),
108        }
109    }
110}
111
112impl std::error::Error for TypeError {}