1use crate::position::Position;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7#[serde(tag = "kind", rename_all = "snake_case")]
8pub enum TypeError {
9 TypeMismatch {
10 at_node: String,
11 expected: String,
12 got: String,
13 context: Vec<String>,
14 },
15 EffectRowMismatch {
24 at_node: String,
25 expected: String,
27 got: String,
29 context: Vec<String>,
30 },
31 UnknownIdentifier {
32 at_node: String,
33 name: String,
34 },
35 ArityMismatch {
36 at_node: String,
37 expected: usize,
38 got: usize,
39 },
40 NonExhaustiveMatch {
41 at_node: String,
42 missing: Vec<String>,
43 },
44 UnknownField {
45 at_node: String,
46 record_type: String,
47 field: String,
48 },
49 DuplicateField {
50 at_node: String,
51 field: String,
52 },
53 UnknownVariant {
54 at_node: String,
55 constructor: String,
56 },
57 EffectNotDeclared {
58 at_node: String,
59 effect: String,
60 },
61 InfiniteType {
62 at_node: String,
63 },
64 AmbiguousType {
65 at_node: String,
66 },
67 RecursiveTypeWithoutConstructor {
68 at_node: String,
69 name: String,
70 },
71 RefinementViolation {
77 at_node: String,
78 fn_name: String,
79 param_index: usize,
80 binding: String,
81 reason: String,
82 },
83 ExamplesOnEffectfulFn {
88 at_node: String,
89 fn_name: String,
90 },
91 ExampleArityMismatch {
94 at_node: String,
95 fn_name: String,
96 case_index: usize,
98 expected: usize,
99 got: usize,
100 },
101 ExampleMismatch {
106 at_node: String,
107 fn_name: String,
108 case_index: usize,
109 expected: String,
111 got: String,
113 },
114}
115
116impl TypeError {
117 pub fn node(&self) -> &str {
118 match self {
119 TypeError::TypeMismatch { at_node, .. }
120 | TypeError::EffectRowMismatch { at_node, .. }
121 | TypeError::UnknownIdentifier { at_node, .. }
122 | TypeError::ArityMismatch { at_node, .. }
123 | TypeError::NonExhaustiveMatch { at_node, .. }
124 | TypeError::UnknownField { at_node, .. }
125 | TypeError::DuplicateField { at_node, .. }
126 | TypeError::UnknownVariant { at_node, .. }
127 | TypeError::EffectNotDeclared { at_node, .. }
128 | TypeError::InfiniteType { at_node, .. }
129 | TypeError::AmbiguousType { at_node, .. }
130 | TypeError::RecursiveTypeWithoutConstructor { at_node, .. }
131 | TypeError::RefinementViolation { at_node, .. }
132 | TypeError::ExamplesOnEffectfulFn { at_node, .. }
133 | TypeError::ExampleArityMismatch { at_node, .. }
134 | TypeError::ExampleMismatch { at_node, .. } => at_node,
135 }
136 }
137}
138
139impl std::fmt::Display for TypeError {
140 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
141 match self {
142 TypeError::TypeMismatch { at_node, expected, got, context } => {
143 write!(f, "type mismatch at {at_node}: expected {expected}, got {got}")?;
144 if !context.is_empty() { write!(f, " ({})", context.join(" / "))?; }
145 Ok(())
146 }
147 TypeError::EffectRowMismatch { at_node, expected, got, context } => {
148 write!(f, "effect-row mismatch at {at_node}: declared row is invariant — expected {expected}, got {got}; narrow the body, don't broaden the row")?;
149 if !context.is_empty() { write!(f, " ({})", context.join(" / "))?; }
150 Ok(())
151 }
152 TypeError::UnknownIdentifier { at_node, name } => write!(f, "unknown identifier `{name}` at {at_node}"),
153 TypeError::ArityMismatch { at_node, expected, got } => write!(f, "arity mismatch at {at_node}: expected {expected}, got {got}"),
154 TypeError::NonExhaustiveMatch { at_node, missing } => write!(f, "non-exhaustive match at {at_node}: missing {missing:?}"),
155 TypeError::UnknownField { at_node, record_type, field } => write!(f, "unknown field `{field}` on {record_type} at {at_node}"),
156 TypeError::DuplicateField { at_node, field } => write!(f, "duplicate field `{field}` at {at_node}"),
157 TypeError::UnknownVariant { at_node, constructor } => write!(f, "unknown constructor `{constructor}` at {at_node}"),
158 TypeError::EffectNotDeclared { at_node, effect } => write!(f, "effect `{effect}` not declared at {at_node}"),
159 TypeError::InfiniteType { at_node } => write!(f, "infinite type (occurs check) at {at_node}"),
160 TypeError::AmbiguousType { at_node } => write!(f, "ambiguous type at {at_node}"),
161 TypeError::RecursiveTypeWithoutConstructor { at_node, name } => write!(f, "recursive type {name} has no constructor at {at_node}"),
162 TypeError::RefinementViolation { at_node, fn_name, param_index, binding, reason } =>
163 write!(f, "refinement violated at {at_node}: argument {} of `{fn_name}` (binding `{binding}`): {reason}",
164 param_index + 1),
165 TypeError::ExamplesOnEffectfulFn { at_node, fn_name } =>
166 write!(f, "function `{fn_name}` at {at_node} carries `examples` but declares effects; \
167 v1 restricts examples to pure functions"),
168 TypeError::ExampleArityMismatch { at_node, fn_name, case_index, expected, got } =>
169 write!(f, "example #{} of `{fn_name}` at {at_node}: expected {expected} argument(s), got {got}",
170 case_index + 1),
171 TypeError::ExampleMismatch { at_node, fn_name, case_index, expected, got } =>
172 write!(f, "example #{} of `{fn_name}` at {at_node}: expected {expected}, got {got}",
173 case_index + 1),
174 }
175 }
176}
177
178impl std::error::Error for TypeError {}
179
180#[derive(Debug, Clone)]
195pub struct PositionedError {
196 pub error: TypeError,
197 pub position: Option<Position>,
198}
199
200impl Serialize for PositionedError {
201 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
202 use serde::ser::SerializeMap;
203 let inner = serde_json::to_value(&self.error)
208 .map_err(serde::ser::Error::custom)?;
209 let obj = inner
210 .as_object()
211 .ok_or_else(|| serde::ser::Error::custom("TypeError did not serialize as an object"))?;
212 let extra = if self.position.is_some() { 3 } else { 2 };
213 let mut map = serializer.serialize_map(Some(obj.len() + extra))?;
214 for (k, v) in obj {
215 map.serialize_entry(k, v)?;
216 }
217 map.serialize_entry("rule_tag", self.error.rule_tag())?;
218 map.serialize_entry("rule_explanation", self.error.rule_explanation())?;
219 if let Some(p) = &self.position {
220 map.serialize_entry("position", p)?;
221 }
222 map.end()
223 }
224}
225
226impl<'de> Deserialize<'de> for PositionedError {
227 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
228 let mut value = serde_json::Value::deserialize(deserializer)?;
233 let position = value
234 .as_object_mut()
235 .and_then(|o| o.remove("position"))
236 .and_then(|p| serde_json::from_value::<Position>(p).ok());
237 if let Some(o) = value.as_object_mut() {
238 o.remove("rule_tag");
239 o.remove("rule_explanation");
240 }
241 let error: TypeError =
242 serde_json::from_value(value).map_err(serde::de::Error::custom)?;
243 Ok(PositionedError { error, position })
244 }
245}
246
247impl PositionedError {
248 pub fn new(error: TypeError, position: Option<Position>) -> Self {
249 Self { error, position }
250 }
251
252 pub fn without_position(error: TypeError) -> Self {
253 Self { error, position: None }
254 }
255
256 pub fn node(&self) -> &str {
257 self.error.node()
258 }
259}
260
261impl std::fmt::Display for PositionedError {
262 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
263 match &self.position {
264 Some(p) => write!(f, "[{}] {}", p.render(), self.error),
265 None => self.error.fmt(f),
266 }
267 }
268}
269
270impl std::error::Error for PositionedError {}
271
272impl From<TypeError> for PositionedError {
273 fn from(e: TypeError) -> Self {
274 Self::without_position(e)
275 }
276}