lust/typechecker/expr_checker/
entry.rs1use 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}