lust/typechecker/expr_checker/
collections.rs

1use super::*;
2use alloc::{
3    boxed::Box,
4    format,
5    string::{String, ToString},
6    vec::Vec,
7};
8impl TypeChecker {
9    pub fn check_array_literal(
10        &mut self,
11        elements: &[Expr],
12        expected_type: Option<&Type>,
13    ) -> Result<Type> {
14        if elements.is_empty() {
15            if let Some(expected) = expected_type {
16                return Ok(expected.clone());
17            }
18
19            let span = Self::dummy_span();
20            return Ok(Type::new(
21                TypeKind::Array(Box::new(Type::new(TypeKind::Unknown, span))),
22                span,
23            ));
24        }
25
26        let expected_elem_type = expected_type.and_then(|t| {
27            if let TypeKind::Array(elem_type) = &t.kind {
28                Some(elem_type.as_ref())
29            } else {
30                None
31            }
32        });
33        if let Some(expected_elem) = expected_elem_type {
34            if let TypeKind::Union(union_types) = &expected_elem.kind {
35                for elem in elements {
36                    let elem_type = self.check_expr(elem)?;
37                    let mut matches = false;
38                    for union_variant in union_types {
39                        if self.types_equal(&elem_type, union_variant) {
40                            matches = true;
41                            break;
42                        }
43                    }
44
45                    if !matches {
46                        let union_desc = union_types
47                            .iter()
48                            .map(|t| t.to_string())
49                            .collect::<Vec<_>>()
50                            .join(" | ");
51                        return Err(self.type_error(format!(
52                            "Array element type '{}' does not match any type in union [{}]",
53                            elem_type, union_desc
54                        )));
55                    }
56                }
57
58                return Ok(expected_type.unwrap().clone());
59            }
60        }
61
62        if let Some(expected_elem) = expected_elem_type {
63            if matches!(expected_elem.kind, TypeKind::Unknown) {
64                for elem in elements {
65                    self.check_expr(elem)?;
66                }
67
68                return Ok(expected_type.unwrap().clone());
69            }
70
71            if let TypeKind::Option(inner) = &expected_elem.kind {
72                if matches!(inner.kind, TypeKind::Unknown) {
73                    for elem in elements {
74                        let elem_type = self.check_expr(elem)?;
75                        let is_option = matches!(&elem_type.kind, TypeKind::Option(_))
76                            || matches!(&elem_type.kind, TypeKind::Named(name) if name == "Option");
77                        if !is_option {
78                            return Err(self.type_error(format!(
79                                "Expected Option type for Array<Option<unknown>>, got '{}'",
80                                elem_type
81                            )));
82                        }
83                    }
84
85                    return Ok(expected_type.unwrap().clone());
86                }
87            }
88
89            if let TypeKind::Result(ok_inner, err_inner) = &expected_elem.kind {
90                if matches!(ok_inner.kind, TypeKind::Unknown)
91                    || matches!(err_inner.kind, TypeKind::Unknown)
92                {
93                    for elem in elements {
94                        let elem_type = self.check_expr(elem)?;
95                        let is_result = matches!(&elem_type.kind, TypeKind::Result(_, _))
96                            || matches!(&elem_type.kind, TypeKind::Named(name) if name == "Result");
97                        if !is_result {
98                            return Err(self.type_error(format!(
99                                "Expected Result type for Array<Result<unknown, ...>>, got '{}'",
100                                elem_type
101                            )));
102                        }
103                    }
104
105                    return Ok(expected_type.unwrap().clone());
106                }
107            }
108        }
109
110        let first_type = self.check_expr(&elements[0])?;
111        for elem in &elements[1..] {
112            let elem_type = self.check_expr(elem)?;
113            self.unify(&first_type, &elem_type)?;
114        }
115
116        Ok(Type::new(
117            TypeKind::Array(Box::new(first_type)),
118            Self::dummy_span(),
119        ))
120    }
121
122    pub fn check_map_literal(
123        &mut self,
124        entries: &[(Expr, Expr)],
125        expected_type: Option<&Type>,
126    ) -> Result<Type> {
127        let mut expected_key_ty: Option<&Type> = None;
128        let mut expected_value_ty: Option<&Type> = None;
129        let mut allow_mixed_keys = false;
130        let mut allow_mixed_values = false;
131        if let Some(expected) = expected_type {
132            match &expected.kind {
133                TypeKind::Map(key, value) => {
134                    expected_key_ty = Some(key.as_ref());
135                    expected_value_ty = Some(value.as_ref());
136                    allow_mixed_keys = matches!(key.kind, TypeKind::Unknown | TypeKind::Infer);
137                    allow_mixed_values = matches!(value.kind, TypeKind::Unknown | TypeKind::Infer);
138                }
139
140                TypeKind::Table => {
141                    allow_mixed_keys = true;
142                    allow_mixed_values = true;
143                }
144
145                _ => {}
146            }
147        }
148
149        if entries.is_empty() {
150            if let Some(expected) = expected_type {
151                match &expected.kind {
152                    TypeKind::Map(_, _) => {
153                        return Ok(self.canonicalize_type(expected));
154                    }
155
156                    TypeKind::Table => {
157                        let span = Self::dummy_span();
158                        return Ok(Type::new(
159                            TypeKind::Map(
160                                Box::new(Type::new(TypeKind::Unknown, span)),
161                                Box::new(Type::new(TypeKind::Unknown, span)),
162                            ),
163                            span,
164                        ));
165                    }
166
167                    _ => {}
168                }
169            }
170
171            let span = Self::dummy_span();
172            return Ok(Type::new(
173                TypeKind::Map(
174                    Box::new(Type::new(TypeKind::Unknown, span)),
175                    Box::new(Type::new(TypeKind::Unknown, span)),
176                ),
177                span,
178            ));
179        }
180
181        let key_hint = expected_key_ty.and_then(|ty| {
182            if matches!(ty.kind, TypeKind::Unknown | TypeKind::Infer) {
183                None
184            } else {
185                Some(ty)
186            }
187        });
188        let value_hint = expected_value_ty.and_then(|ty| {
189            if matches!(ty.kind, TypeKind::Unknown | TypeKind::Infer) {
190                None
191            } else {
192                Some(ty)
193            }
194        });
195
196        let mut inferred_key_type: Option<Type> = None;
197        let mut inferred_value_type: Option<Type> = None;
198        for (key_expr, value_expr) in entries {
199            let raw_key_type = if let Some(hint) = key_hint {
200                self.check_expr_with_hint(key_expr, Some(hint))?
201            } else {
202                self.check_expr(key_expr)?
203            };
204            if !self.env.type_implements_trait(&raw_key_type, "Hashable") {
205                return Err(self.type_error(format!(
206                    "Map key type '{}' must implement Hashable trait",
207                    raw_key_type
208                )));
209            }
210            let canonical_key = self.canonicalize_type(&raw_key_type);
211
212            let raw_value_type = if let Some(hint) = value_hint {
213                self.check_expr_with_hint(value_expr, Some(hint))?
214            } else {
215                self.check_expr(value_expr)?
216            };
217            let canonical_value = self.canonicalize_type(&raw_value_type);
218
219            if let Some(existing_key) = &inferred_key_type {
220                if !allow_mixed_keys {
221                    self.unify(existing_key, &canonical_key)?;
222                }
223            } else {
224                inferred_key_type = Some(canonical_key.clone());
225            }
226
227            if let Some(existing_value) = &inferred_value_type {
228                if !allow_mixed_values {
229                    self.unify(existing_value, &canonical_value)?;
230                }
231            } else {
232                inferred_value_type = Some(canonical_value.clone());
233            }
234        }
235
236        let span = Self::dummy_span();
237        let key_type = if allow_mixed_keys {
238            expected_key_ty
239                .and_then(|ty| Some(self.canonicalize_type(ty)))
240                .unwrap_or_else(|| Type::new(TypeKind::Unknown, span))
241        } else {
242            inferred_key_type.unwrap_or_else(|| Type::new(TypeKind::Unknown, span))
243        };
244        let value_type = if allow_mixed_values {
245            expected_value_ty
246                .and_then(|ty| Some(self.canonicalize_type(ty)))
247                .unwrap_or_else(|| Type::new(TypeKind::Unknown, span))
248        } else {
249            inferred_value_type.unwrap_or_else(|| Type::new(TypeKind::Unknown, span))
250        };
251
252        Ok(Type::new(
253            TypeKind::Map(Box::new(key_type), Box::new(value_type)),
254            Self::dummy_span(),
255        ))
256    }
257
258    pub fn check_struct_literal(
259        &mut self,
260        span: Span,
261        name: &str,
262        fields: &[StructLiteralField],
263    ) -> Result<Type> {
264        let key = self.resolve_type_key(name);
265        let struct_def = self
266            .env
267            .lookup_struct(&key)
268            .or_else(|| self.env.lookup_struct(name))
269            .ok_or_else(|| self.type_error_at(format!("Undefined struct '{}'", name), span))?
270            .clone();
271        if fields.len() != struct_def.fields.len() {
272            return Err(self.type_error_at(
273                format!(
274                    "Struct '{}' has {} fields, but {} were provided",
275                    name,
276                    struct_def.fields.len(),
277                    fields.len()
278                ),
279                span,
280            ));
281        }
282
283        for field in fields {
284            let expected_type = struct_def
285                .fields
286                .iter()
287                .find(|f| f.name == field.name)
288                .map(|f| &f.ty)
289                .ok_or_else(|| {
290                    self.type_error_at(
291                        format!("Struct '{}' has no field '{}'", name, field.name),
292                        field.span,
293                    )
294                })?;
295            let actual_type = self.check_expr(&field.value)?;
296            match &expected_type.kind {
297                TypeKind::Option(inner_expected) => {
298                    if self.unify(inner_expected, &actual_type).is_err() {
299                        self.unify(expected_type, &actual_type)?;
300                    }
301                }
302
303                _ => {
304                    self.unify(expected_type, &actual_type)?;
305                }
306            }
307        }
308
309        let ty_name = if self.env.lookup_struct(&key).is_some() {
310            key
311        } else {
312            name.to_string()
313        };
314        Ok(Type::new(TypeKind::Named(ty_name), Self::dummy_span()))
315    }
316
317    pub fn check_lambda(
318        &mut self,
319        params: &[(String, Option<Type>)],
320        return_type: Option<&Type>,
321        body: &Expr,
322    ) -> Result<Type> {
323        self.env.push_scope();
324        let expected_signature = self.expected_lambda_signature.take();
325        let mut param_types = Vec::new();
326        for (i, (param_name, param_type)) in params.iter().enumerate() {
327            let ty = if let Some(explicit_type) = param_type {
328                explicit_type.clone()
329            } else if let Some((ref expected_params, _)) = expected_signature {
330                if i < expected_params.len() {
331                    expected_params[i].clone()
332                } else {
333                    Type::new(TypeKind::Infer, Self::dummy_span())
334                }
335            } else {
336                Type::new(TypeKind::Infer, Self::dummy_span())
337            };
338            self.env.declare_variable(param_name.clone(), ty.clone())?;
339            param_types.push(ty);
340        }
341
342        let saved_return_type = self.current_function_return_type.clone();
343        let inferred_return_type = if let Some(explicit) = return_type {
344            Some(explicit.clone())
345        } else if let Some((_, expected_ret)) = expected_signature {
346            expected_ret.or_else(|| Some(Type::new(TypeKind::Infer, Self::dummy_span())))
347        } else {
348            Some(Type::new(TypeKind::Infer, Self::dummy_span()))
349        };
350        self.current_function_return_type = inferred_return_type.clone();
351        let body_type = self.check_expr(body)?;
352        self.current_function_return_type = saved_return_type;
353        let actual_return_type = if let Some(expected) = return_type {
354            expected.clone()
355        } else if let Some(inferred) = &inferred_return_type {
356            if !matches!(inferred.kind, TypeKind::Infer) {
357                inferred.clone()
358            } else {
359                body_type
360            }
361        } else {
362            body_type
363        };
364        self.env.pop_scope();
365        Ok(Type::new(
366            TypeKind::Function {
367                params: param_types,
368                return_type: Box::new(actual_return_type),
369            },
370            Self::dummy_span(),
371        ))
372    }
373
374    pub fn check_if_expr(
375        &mut self,
376        condition: &Expr,
377        then_branch: &Expr,
378        else_branch: &Option<Box<Expr>>,
379    ) -> Result<Type> {
380        let cond_type = self.check_expr(condition)?;
381        self.unify(&Type::new(TypeKind::Bool, Self::dummy_span()), &cond_type)?;
382        let then_type = self.check_expr(then_branch)?;
383        if let Some(else_expr) = else_branch {
384            let else_type = self.check_expr(else_expr)?;
385            self.unify(&then_type, &else_type)?;
386            Ok(then_type)
387        } else {
388            Ok(Type::new(TypeKind::Unit, Self::dummy_span()))
389        }
390    }
391}