lust/typechecker/expr_checker/
entry.rs

1use super::*;
2use alloc::{boxed::Box, format, string::ToString, vec::Vec};
3use hashbrown::HashMap;
4impl TypeChecker {
5    pub fn check_expr(&mut self, expr: &Expr) -> Result<Type> {
6        let mut ty = self.check_expr_with_hint(expr, None)?;
7        if ty.span.start_line == 0 && expr.span.start_line > 0 {
8            ty.span = expr.span;
9        }
10
11        if expr.span.start_line > 0 {
12            if let Some(module) = &self.current_module {
13                self.expr_types_by_module
14                    .entry(module.clone())
15                    .or_default()
16                    .insert(expr.span, ty.clone());
17            }
18        }
19
20        Ok(ty)
21    }
22
23    pub fn check_expr_with_hint(
24        &mut self,
25        expr: &Expr,
26        expected_type: Option<&Type>,
27    ) -> Result<Type> {
28        match &expr.kind {
29            ExprKind::Literal(lit) => self.check_literal(lit),
30            ExprKind::Identifier(name) => self.env.lookup_variable(name).ok_or_else(|| {
31                self.type_error_at(format!("Undefined variable '{}'", name), expr.span)
32            }),
33            ExprKind::Binary { left, op, right } => self.check_binary_expr(left, op, right),
34            ExprKind::Unary { op, operand } => self.check_unary_expr(op, operand),
35            ExprKind::Call { callee, args } => self.check_call_expr(expr.span, callee, args),
36            ExprKind::MethodCall {
37                receiver,
38                method,
39                type_args,
40                args,
41            } => {
42                if method == "as" && type_args.is_some() {
43                    let _receiver_type = self.check_expr(receiver)?;
44                    if !args.is_empty() {
45                        return Err(self.type_error(":as<T>() takes no arguments".to_string()));
46                    }
47
48                    let target_type = &type_args.as_ref().unwrap()[0];
49                    let actual_target_type = if let TypeKind::Named(name) = &target_type.kind {
50                        let resolved = self.resolve_type_key(name);
51                        if self.env.lookup_trait(&resolved).is_some() {
52                            Type::new(TypeKind::Trait(name.clone()), target_type.span)
53                        } else {
54                            target_type.clone()
55                        }
56                    } else {
57                        target_type.clone()
58                    };
59                    let span = Self::dummy_span();
60                    return Ok(Type::new(
61                        TypeKind::Option(Box::new(actual_target_type)),
62                        span,
63                    ));
64                }
65
66                let _ = type_args;
67                self.check_method_call(receiver, method, args)
68            }
69
70            ExprKind::FieldAccess { object, field } => {
71                self.check_field_access_with_hint(expr.span, object, field, expected_type)
72            }
73
74            ExprKind::Index { object, index } => self.check_index_expr(object, index),
75            ExprKind::Array(elements) => self.check_array_literal(elements, expected_type),
76            ExprKind::Map(entries) => self.check_map_literal(entries),
77            ExprKind::StructLiteral { name, fields } => {
78                self.check_struct_literal(expr.span, name, fields)
79            }
80
81            ExprKind::Lambda {
82                params,
83                return_type,
84                body,
85            } => self.check_lambda(params, return_type.as_ref(), body),
86            ExprKind::Cast { expr, target_type } => {
87                let _expr_type = self.check_expr(expr)?;
88                Ok(target_type.clone())
89            }
90
91            ExprKind::TypeCheck {
92                expr,
93                check_type: _,
94            } => {
95                let _expr_type = self.check_expr(expr)?;
96                Ok(Type::new(TypeKind::Bool, Self::dummy_span()))
97            }
98
99            ExprKind::IsPattern { expr, pattern } => {
100                let scrutinee_type = self.check_expr(expr)?;
101                self.validate_is_pattern(pattern, &scrutinee_type)?;
102                Ok(Type::new(TypeKind::Bool, Self::dummy_span()))
103            }
104
105            ExprKind::If {
106                condition,
107                then_branch,
108                else_branch,
109            } => self.check_if_expr(condition, then_branch, else_branch),
110            ExprKind::Block(stmts) => {
111                self.env.push_scope();
112                let mut result_type = Type::new(TypeKind::Unit, Self::dummy_span());
113                for stmt in stmts {
114                    match &stmt.kind {
115                        StmtKind::Expr(expr) => {
116                            result_type = self.check_expr(expr)?;
117                        }
118
119                        StmtKind::Return(values) => {
120                            result_type = if values.is_empty() {
121                                Type::new(TypeKind::Unit, Self::dummy_span())
122                            } else if values.len() == 1 {
123                                let expected = self.current_function_return_type.clone();
124                                let mut raw =
125                                    self.check_expr_with_hint(&values[0], expected.as_ref())?;
126                                if raw.span.start_line == 0 && values[0].span.start_line > 0 {
127                                    raw.span = values[0].span;
128                                }
129
130                                self.canonicalize_type(&raw)
131                            } else {
132                                let mut el_types = Vec::new();
133                                for value in values {
134                                    let raw = self.check_expr(value)?;
135                                    el_types.push(self.canonicalize_type(&raw));
136                                }
137
138                                Type::new(TypeKind::Tuple(el_types), Self::dummy_span())
139                            };
140                            self.pending_generic_instances.take();
141                            self.check_stmt(stmt)?;
142                        }
143
144                        _ => {
145                            self.check_stmt(stmt)?;
146                        }
147                    }
148                }
149
150                self.env.pop_scope();
151                if result_type.span.start_line == 0 {
152                    result_type.span = expr.span;
153                }
154
155                Ok(result_type)
156            }
157
158            ExprKind::Range { .. } => Err(self.type_error_at(
159                "Range expressions are not supported; use numeric for-loops".to_string(),
160                expr.span,
161            )),
162            ExprKind::EnumConstructor {
163                enum_name,
164                variant,
165                args,
166            } => {
167                let enum_def = self
168                    .env
169                    .lookup_enum(enum_name)
170                    .ok_or_else(|| self.type_error(format!("Undefined enum '{}'", enum_name)))?
171                    .clone();
172                let variant_def = enum_def
173                    .variants
174                    .iter()
175                    .find(|v| v.name == *variant)
176                    .ok_or_else(|| {
177                        self.type_error(format!(
178                            "Enum '{}' has no variant '{}'",
179                            enum_name, variant
180                        ))
181                    })?;
182                if let Some(expected_fields) = &variant_def.fields {
183                    if args.len() != expected_fields.len() {
184                        return Err(self.type_error(format!(
185                            "Variant '{}::{}' expects {} arguments, got {}",
186                            enum_name,
187                            variant,
188                            expected_fields.len(),
189                            args.len()
190                        )));
191                    }
192
193                    let mut type_params = HashMap::new();
194                    for (arg, expected_type) in args.iter().zip(expected_fields.iter()) {
195                        let arg_type = self.check_expr(arg)?;
196                        if let TypeKind::Generic(type_param) = &expected_type.kind {
197                            type_params.insert(type_param.clone(), arg_type.clone());
198                        } else {
199                            self.unify(expected_type, &arg_type)?;
200                        }
201                    }
202
203                    if !type_params.is_empty() {
204                        self.pending_generic_instances = Some(type_params.clone());
205                    }
206
207                    if enum_name == "Option" {
208                        if let Some(inner_type) = type_params.get("T") {
209                            return Ok(Type::new(
210                                TypeKind::Option(Box::new(inner_type.clone())),
211                                Self::dummy_span(),
212                            ));
213                        }
214                    } else if enum_name == "Result" {
215                        if let (Some(ok_type), Some(err_type)) =
216                            (type_params.get("T"), type_params.get("E"))
217                        {
218                            return Ok(Type::new(
219                                TypeKind::Result(
220                                    Box::new(ok_type.clone()),
221                                    Box::new(err_type.clone()),
222                                ),
223                                Self::dummy_span(),
224                            ));
225                        }
226                    }
227                } else {
228                    if !args.is_empty() {
229                        return Err(self.type_error(format!(
230                            "Variant '{}::{}' is a unit variant and takes no arguments",
231                            enum_name, variant
232                        )));
233                    }
234                }
235
236                Ok(Type::new(
237                    TypeKind::Named(enum_name.clone()),
238                    Self::dummy_span(),
239                ))
240            }
241
242            ExprKind::Tuple(elements) => {
243                let expected_elements = expected_type.and_then(|ty| {
244                    if let TypeKind::Tuple(elems) = &ty.kind {
245                        Some(elems.clone())
246                    } else {
247                        None
248                    }
249                });
250                let mut element_types = Vec::new();
251                for (index, element) in elements.iter().enumerate() {
252                    let hint = expected_elements
253                        .as_ref()
254                        .and_then(|elems| elems.get(index));
255                    let mut raw_ty = if let Some(hint_ty) = hint {
256                        self.check_expr_with_hint(element, Some(hint_ty))?
257                    } else {
258                        self.check_expr(element)?
259                    };
260                    if raw_ty.span.start_line == 0 && element.span.start_line > 0 {
261                        raw_ty.span = element.span;
262                    }
263
264                    self.pending_generic_instances.take();
265                    element_types.push(self.canonicalize_type(&raw_ty));
266                }
267
268                Ok(Type::new(TypeKind::Tuple(element_types), expr.span))
269            }
270
271            ExprKind::Return(exprs) => {
272                let mut return_type = if exprs.is_empty() {
273                    Type::new(TypeKind::Unit, Self::dummy_span())
274                } else if exprs.len() == 1 {
275                    let expected = self.current_function_return_type.clone();
276                    let mut raw_ty = self.check_expr_with_hint(&exprs[0], expected.as_ref())?;
277                    if raw_ty.span.start_line == 0 && exprs[0].span.start_line > 0 {
278                        raw_ty.span = exprs[0].span;
279                    }
280
281                    self.pending_generic_instances.take();
282                    raw_ty
283                } else {
284                    let mut types = Vec::new();
285                    for value in exprs {
286                        let raw_ty = self.check_expr(value)?;
287                        let ty = self.canonicalize_type(&raw_ty);
288                        self.pending_generic_instances.take();
289                        types.push(ty);
290                    }
291
292                    Type::new(TypeKind::Tuple(types), Self::dummy_span())
293                };
294                if return_type.span.start_line == 0 {
295                    if let Some(first) = exprs.first() {
296                        return_type.span = first.span;
297                    } else {
298                        return_type.span = expr.span;
299                    }
300                }
301
302                if let Some(expected_return) = &self.current_function_return_type {
303                    self.unify(expected_return, &return_type)?;
304                } else {
305                    return Err(self.type_error("'return' outside of function".to_string()));
306                }
307
308                Ok(return_type)
309            }
310
311            ExprKind::Paren(inner) => self.check_expr(inner),
312        }
313    }
314}