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