lust/typechecker/expr_checker/
entry.rs

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