/home/noah/src/ruchy/src/middleend/infer.rs
Line | Count | Source |
1 | | //! Type inference engine using Algorithm W |
2 | | |
3 | | use crate::frontend::ast::{BinaryOp, Expr, ExprKind, Literal, Param, Pattern, TypeKind, UnaryOp}; |
4 | | use crate::middleend::environment::TypeEnv; |
5 | | use crate::middleend::types::{MonoType, TyVar, TyVarGenerator, TypeScheme}; |
6 | | use crate::middleend::unify::Unifier; |
7 | | use anyhow::{bail, Result}; |
8 | | |
9 | | /// Type inference context with enhanced constraint solving |
10 | | pub struct InferenceContext { |
11 | | /// Type variable generator |
12 | | gen: TyVarGenerator, |
13 | | /// Unification engine |
14 | | unifier: Unifier, |
15 | | /// Type environment |
16 | | env: TypeEnv, |
17 | | /// Deferred constraints for later resolution |
18 | | constraints: Vec<(TyVar, TyVar)>, |
19 | | /// Enhanced constraint queue for complex type relationships |
20 | | type_constraints: Vec<TypeConstraint>, |
21 | | /// Recursion depth tracker for safety |
22 | | recursion_depth: usize, |
23 | | } |
24 | | |
25 | | /// Enhanced constraint types for self-hosting compiler patterns |
26 | | #[derive(Debug, Clone)] |
27 | | pub enum TypeConstraint { |
28 | | /// Two types must unify |
29 | | Unify(MonoType, MonoType), |
30 | | /// Type must be a function with specific arity |
31 | | FunctionArity(MonoType, usize), |
32 | | /// Type must support method call |
33 | | MethodCall(MonoType, String, Vec<MonoType>), |
34 | | /// Type must be iterable |
35 | | Iterable(MonoType, MonoType), |
36 | | } |
37 | | |
38 | | impl InferenceContext { |
39 | | #[must_use] |
40 | 0 | pub fn new() -> Self { |
41 | 0 | InferenceContext { |
42 | 0 | gen: TyVarGenerator::new(), |
43 | 0 | unifier: Unifier::new(), |
44 | 0 | env: TypeEnv::standard(), |
45 | 0 | constraints: Vec::new(), |
46 | 0 | type_constraints: Vec::new(), |
47 | 0 | recursion_depth: 0, |
48 | 0 | } |
49 | 0 | } |
50 | | |
51 | | #[must_use] |
52 | 0 | pub fn with_env(env: TypeEnv) -> Self { |
53 | 0 | InferenceContext { |
54 | 0 | gen: TyVarGenerator::new(), |
55 | 0 | unifier: Unifier::new(), |
56 | 0 | env, |
57 | 0 | constraints: Vec::new(), |
58 | 0 | type_constraints: Vec::new(), |
59 | 0 | recursion_depth: 0, |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | /// Infer the type of an expression with enhanced constraint solving |
64 | | /// |
65 | | /// # Errors |
66 | | /// |
67 | | /// Returns an error if type inference fails (type error, undefined variable, etc.) |
68 | 0 | pub fn infer(&mut self, expr: &Expr) -> Result<MonoType> { |
69 | | // Check recursion depth to prevent infinite loops |
70 | 0 | if self.recursion_depth > 100 { |
71 | 0 | bail!("Type inference recursion limit exceeded"); |
72 | 0 | } |
73 | | |
74 | 0 | self.recursion_depth += 1; |
75 | 0 | let result = self.infer_expr(expr); |
76 | 0 | self.recursion_depth -= 1; |
77 | | |
78 | 0 | let inferred_type = result?; |
79 | | |
80 | | // Solve all accumulated constraints |
81 | 0 | self.solve_all_constraints()?; |
82 | | |
83 | | // Apply final substitutions |
84 | 0 | Ok(self.unifier.apply(&inferred_type)) |
85 | 0 | } |
86 | | |
87 | | /// Solve all accumulated constraints (enhanced for self-hosting) |
88 | 0 | fn solve_all_constraints(&mut self) -> Result<()> { |
89 | | // First solve simple variable constraints |
90 | 0 | self.solve_constraints(); |
91 | | |
92 | | // Then solve complex type constraints |
93 | 0 | while let Some(constraint) = self.type_constraints.pop() { |
94 | 0 | self.solve_type_constraint(constraint)?; |
95 | | } |
96 | | |
97 | 0 | Ok(()) |
98 | 0 | } |
99 | | |
100 | | /// Solve deferred constraints |
101 | 0 | fn solve_constraints(&mut self) { |
102 | 0 | while let Some((a, b)) = self.constraints.pop() { |
103 | 0 | // Convert TyVar to MonoType for unification |
104 | 0 | let ty_a = MonoType::Var(a); |
105 | 0 | let ty_b = MonoType::Var(b); |
106 | 0 | // Ignore failures for now - this is a simplified implementation |
107 | 0 | let _ = self.unifier.unify(&ty_a, &ty_b); |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | /// Solve complex type constraints for advanced patterns |
112 | 0 | fn solve_type_constraint(&mut self, constraint: TypeConstraint) -> Result<()> { |
113 | 0 | match constraint { |
114 | 0 | TypeConstraint::Unify(t1, t2) => { |
115 | 0 | self.unifier.unify(&t1, &t2)?; |
116 | | } |
117 | 0 | TypeConstraint::FunctionArity(func_ty, expected_arity) => { |
118 | | // Verify function has correct number of parameters |
119 | 0 | let mut current_ty = &func_ty; |
120 | 0 | let mut arity = 0; |
121 | | |
122 | 0 | while let MonoType::Function(_, ret) = current_ty { |
123 | 0 | arity += 1; |
124 | 0 | current_ty = ret; |
125 | 0 | } |
126 | | |
127 | 0 | if arity != expected_arity { |
128 | 0 | bail!( |
129 | 0 | "Function arity mismatch: expected {}, found {}", |
130 | | expected_arity, |
131 | | arity |
132 | | ); |
133 | 0 | } |
134 | | } |
135 | 0 | TypeConstraint::MethodCall(receiver_ty, method_name, arg_types) => { |
136 | | // Verify receiver type supports the method call |
137 | 0 | self.check_method_call_constraint(&receiver_ty, &method_name, &arg_types)?; |
138 | | } |
139 | 0 | TypeConstraint::Iterable(collection_ty, element_ty) => { |
140 | | // Ensure collection_ty is a valid iterable containing element_ty |
141 | 0 | match collection_ty { |
142 | 0 | MonoType::List(inner) => { |
143 | 0 | self.unifier.unify(&inner, &element_ty)?; |
144 | | } |
145 | | MonoType::String => { |
146 | | // String iterates over characters |
147 | 0 | self.unifier.unify(&element_ty, &MonoType::Char)?; |
148 | | } |
149 | 0 | _ => bail!("Type {} is not iterable", collection_ty), |
150 | | } |
151 | | } |
152 | | } |
153 | 0 | Ok(()) |
154 | 0 | } |
155 | | |
156 | | /// Check method call constraints for compiler patterns |
157 | 0 | fn check_method_call_constraint( |
158 | 0 | &mut self, |
159 | 0 | receiver_ty: &MonoType, |
160 | 0 | method_name: &str, |
161 | 0 | _arg_types: &[MonoType], |
162 | 0 | ) -> Result<()> { |
163 | 0 | match (method_name, receiver_ty) { |
164 | | // List methods |
165 | 0 | ("map" | "filter" | "reduce", MonoType::List(_)) => Ok(()), |
166 | 0 | ("len" | "length", MonoType::List(_) | MonoType::String) => Ok(()), |
167 | 0 | ("push", MonoType::List(_)) => Ok(()), |
168 | | |
169 | | // DataFrame methods |
170 | 0 | ("filter" | "groupby" | "agg" | "select" | "col", MonoType::DataFrame(_)) => Ok(()), |
171 | 0 | ("filter" | "groupby" | "agg" | "select" | "col", MonoType::Named(name)) |
172 | 0 | if name == "DataFrame" => Ok(()), |
173 | | |
174 | | // Series methods |
175 | 0 | ("mean" | "std" | "sum" | "count", MonoType::Series(_) | MonoType::DataFrame(_)) => Ok(()), |
176 | 0 | ("mean" | "std" | "sum" | "count", MonoType::Named(name)) |
177 | 0 | if name == "Series" || name == "DataFrame" => Ok(()), |
178 | | |
179 | | // HashMap methods (for compiler symbol tables) |
180 | 0 | ("insert" | "get" | "contains_key", MonoType::Named(name)) |
181 | 0 | if name.starts_with("HashMap") => Ok(()), |
182 | | |
183 | | // String methods |
184 | 0 | ("chars" | "trim" | "to_upper" | "to_lower", MonoType::String) => Ok(()), |
185 | | |
186 | | // For testing purposes, be more permissive with unknown methods |
187 | | _ => { |
188 | | // In a production implementation, this would be stricter |
189 | | // For self-hosting development, we allow more flexibility |
190 | 0 | Ok(()) |
191 | | } |
192 | | } |
193 | 0 | } |
194 | | |
195 | | /// Core type inference dispatcher with complexity <10 |
196 | | /// |
197 | | /// Delegates to specialized handlers for each expression category |
198 | | /// |
199 | | /// # Example Usage |
200 | | /// This method infers types for expressions by delegating to specialized handlers. |
201 | | /// For example, literals get their type directly, while function calls check argument types. |
202 | 0 | fn infer_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
203 | 0 | match &expr.kind { |
204 | | // Literals and identifiers |
205 | 0 | ExprKind::Literal(lit) => Ok(Self::infer_literal(lit)), |
206 | 0 | ExprKind::Identifier(name) => self.infer_identifier(name), |
207 | 0 | ExprKind::QualifiedName { module: _, name } => self.infer_identifier(name), |
208 | | |
209 | | // Control flow and pattern matching |
210 | | ExprKind::If { condition: _, then_branch: _, else_branch: _ } => { |
211 | 0 | self.infer_control_flow_expr(expr) |
212 | | } |
213 | 0 | ExprKind::Match { expr, arms } => self.infer_match(expr, arms), |
214 | | ExprKind::IfLet { .. } | ExprKind::WhileLet { .. } => { |
215 | 0 | self.infer_control_flow_expr(expr) |
216 | | } |
217 | | |
218 | | // Functions and lambdas |
219 | | ExprKind::Function { .. } | ExprKind::Lambda { .. } => { |
220 | 0 | self.infer_function_expr(expr) |
221 | | } |
222 | | |
223 | | // Collections and data structures |
224 | | ExprKind::List(..) | ExprKind::Tuple(..) | ExprKind::ListComprehension { .. } => { |
225 | 0 | self.infer_collection_expr(expr) |
226 | | } |
227 | | |
228 | | // Operations and method calls |
229 | | ExprKind::Binary { .. } | ExprKind::Unary { .. } | ExprKind::Call { .. } | ExprKind::MethodCall { .. } => { |
230 | 0 | self.infer_operation_expr(expr) |
231 | | } |
232 | | |
233 | | // All other expressions |
234 | 0 | _ => self.infer_other_expr(expr), |
235 | | } |
236 | 0 | } |
237 | | |
238 | 0 | fn infer_literal(lit: &Literal) -> MonoType { |
239 | 0 | match lit { |
240 | 0 | Literal::Integer(_) => MonoType::Int, |
241 | 0 | Literal::Float(_) => MonoType::Float, |
242 | 0 | Literal::String(_) => MonoType::String, |
243 | 0 | Literal::Bool(_) => MonoType::Bool, |
244 | 0 | Literal::Char(_) => MonoType::Char, |
245 | 0 | Literal::Unit => MonoType::Unit, |
246 | | } |
247 | 0 | } |
248 | | |
249 | 0 | fn infer_identifier(&mut self, name: &str) -> Result<MonoType> { |
250 | 0 | match self.env.lookup(name) { |
251 | 0 | Some(scheme) => Ok(self.env.instantiate(scheme, &mut self.gen)), |
252 | 0 | None => bail!("Undefined variable: {}", name), |
253 | | } |
254 | 0 | } |
255 | | |
256 | 0 | fn infer_binary(&mut self, left: &Expr, op: BinaryOp, right: &Expr) -> Result<MonoType> { |
257 | 0 | let left_ty = self.infer_expr(left)?; |
258 | 0 | let right_ty = self.infer_expr(right)?; |
259 | | |
260 | 0 | match op { |
261 | | // Arithmetic operators |
262 | | BinaryOp::Add |
263 | | | BinaryOp::Subtract |
264 | | | BinaryOp::Multiply |
265 | | | BinaryOp::Divide |
266 | | | BinaryOp::Modulo => { |
267 | | // Both operands must be numeric and same type |
268 | 0 | self.unifier.unify(&left_ty, &right_ty)?; |
269 | | // For now, assume Int (could be Float too) |
270 | 0 | self.unifier.unify(&left_ty, &MonoType::Int)?; |
271 | 0 | Ok(MonoType::Int) |
272 | | } |
273 | | BinaryOp::Power => { |
274 | 0 | self.unifier.unify(&left_ty, &MonoType::Int)?; |
275 | 0 | self.unifier.unify(&right_ty, &MonoType::Int)?; |
276 | 0 | Ok(MonoType::Int) |
277 | | } |
278 | | // Comparison operators |
279 | | BinaryOp::Equal |
280 | | | BinaryOp::NotEqual |
281 | | | BinaryOp::Less |
282 | | | BinaryOp::LessEqual |
283 | | | BinaryOp::Greater |
284 | | | BinaryOp::GreaterEqual => { |
285 | | // Operands must have same type |
286 | 0 | self.unifier.unify(&left_ty, &right_ty)?; |
287 | 0 | Ok(MonoType::Bool) |
288 | | } |
289 | | // Boolean operators |
290 | | BinaryOp::And | BinaryOp::Or => { |
291 | 0 | self.unifier.unify(&left_ty, &MonoType::Bool)?; |
292 | 0 | self.unifier.unify(&right_ty, &MonoType::Bool)?; |
293 | 0 | Ok(MonoType::Bool) |
294 | | } |
295 | | // Null coalescing operator: return type is union of operand types |
296 | | BinaryOp::NullCoalesce => { |
297 | | // Type is the union of left and right, but return the more specific non-null type |
298 | 0 | Ok(right_ty) // For now, assume right type (could be improved with union types) |
299 | | } |
300 | | // Bitwise operators |
301 | | BinaryOp::BitwiseAnd |
302 | | | BinaryOp::BitwiseOr |
303 | | | BinaryOp::BitwiseXor |
304 | | | BinaryOp::LeftShift => { |
305 | 0 | self.unifier.unify(&left_ty, &MonoType::Int)?; |
306 | 0 | self.unifier.unify(&right_ty, &MonoType::Int)?; |
307 | 0 | Ok(MonoType::Int) |
308 | | } |
309 | | } |
310 | 0 | } |
311 | | |
312 | 0 | fn infer_unary(&mut self, op: UnaryOp, operand: &Expr) -> Result<MonoType> { |
313 | 0 | let operand_ty = self.infer_expr(operand)?; |
314 | | |
315 | 0 | match op { |
316 | | UnaryOp::Not => { |
317 | 0 | self.unifier.unify(&operand_ty, &MonoType::Bool)?; |
318 | 0 | Ok(MonoType::Bool) |
319 | | } |
320 | | UnaryOp::Negate => { |
321 | | // Can negate Int or Float |
322 | 0 | self.unifier.unify(&operand_ty, &MonoType::Int)?; |
323 | 0 | Ok(MonoType::Int) |
324 | | } |
325 | | UnaryOp::BitwiseNot => { |
326 | 0 | self.unifier.unify(&operand_ty, &MonoType::Int)?; |
327 | 0 | Ok(MonoType::Int) |
328 | | } |
329 | | UnaryOp::Reference => { |
330 | | // Reference operator &x: T -> &T |
331 | 0 | Ok(MonoType::Reference(Box::new(operand_ty))) |
332 | | } |
333 | | } |
334 | 0 | } |
335 | | |
336 | | |
337 | 0 | fn infer_throw(&mut self, expr: &Expr) -> Result<MonoType> { |
338 | | // Infer the type of the expression being thrown |
339 | 0 | let _expr_ty = self.infer_expr(expr)?; |
340 | | |
341 | | // The expression must implement Error trait |
342 | | // For now, we'll just ensure it's a valid type |
343 | | // In a more complete implementation, we'd check Error trait bounds |
344 | | |
345 | | // The throw expression itself has the Never type (!) |
346 | | // But we'll represent it as a generic type for now |
347 | 0 | Ok(MonoType::Var(self.gen.fresh())) |
348 | 0 | } |
349 | | |
350 | 0 | fn infer_await(&mut self, expr: &Expr) -> Result<MonoType> { |
351 | | // The expression must be a Future<Output = T> |
352 | 0 | let expr_ty = self.infer_expr(expr)?; |
353 | | |
354 | | // For now, we'll just return the inner type |
355 | | // In a full implementation, we'd check for Future trait |
356 | 0 | if let MonoType::Named(name) = &expr_ty { |
357 | 0 | if name.starts_with("Future") { |
358 | | // Extract the output type |
359 | 0 | return Ok(MonoType::Var(self.gen.fresh())); |
360 | 0 | } |
361 | 0 | } |
362 | | |
363 | | // For now, just return a fresh type variable |
364 | 0 | Ok(MonoType::Var(self.gen.fresh())) |
365 | 0 | } |
366 | | |
367 | 0 | fn infer_if( |
368 | 0 | &mut self, |
369 | 0 | condition: &Expr, |
370 | 0 | then_branch: &Expr, |
371 | 0 | else_branch: Option<&Expr>, |
372 | 0 | ) -> Result<MonoType> { |
373 | | // Condition must be Bool |
374 | 0 | let cond_ty = self.infer_expr(condition)?; |
375 | 0 | self.unifier.unify(&cond_ty, &MonoType::Bool)?; |
376 | | |
377 | 0 | let then_ty = self.infer_expr(then_branch)?; |
378 | | |
379 | 0 | if let Some(else_expr) = else_branch { |
380 | 0 | let else_ty = self.infer_expr(else_expr)?; |
381 | | // Both branches must have same type |
382 | 0 | self.unifier.unify(&then_ty, &else_ty)?; |
383 | 0 | Ok(self.unifier.apply(&then_ty)) |
384 | | } else { |
385 | | // No else branch means Unit type |
386 | 0 | self.unifier.unify(&then_ty, &MonoType::Unit)?; |
387 | 0 | Ok(MonoType::Unit) |
388 | | } |
389 | 0 | } |
390 | | |
391 | 0 | fn infer_let( |
392 | 0 | &mut self, |
393 | 0 | name: &str, |
394 | 0 | value: &Expr, |
395 | 0 | body: &Expr, |
396 | 0 | _is_mutable: bool, |
397 | 0 | ) -> Result<MonoType> { |
398 | | // Infer type of value |
399 | 0 | let value_ty = self.infer_expr(value)?; |
400 | | |
401 | | // Generalize the value type |
402 | 0 | let scheme = self.env.generalize(value_ty); |
403 | | |
404 | | // Extend environment and infer body |
405 | 0 | let old_env = self.env.clone(); |
406 | 0 | self.env = self.env.extend(name, scheme); |
407 | 0 | let body_ty = self.infer_expr(body)?; |
408 | 0 | self.env = old_env; |
409 | | |
410 | 0 | Ok(body_ty) |
411 | 0 | } |
412 | | |
413 | 0 | fn infer_function( |
414 | 0 | &mut self, |
415 | 0 | name: &str, |
416 | 0 | params: &[Param], |
417 | 0 | body: &Expr, |
418 | 0 | _return_type: Option<&crate::frontend::ast::Type>, |
419 | 0 | _is_async: bool, |
420 | 0 | ) -> Result<MonoType> { |
421 | | // Create fresh type variables for parameters |
422 | 0 | let mut param_types = Vec::new(); |
423 | 0 | let old_env = self.env.clone(); |
424 | | |
425 | 0 | for param in params { |
426 | 0 | let param_ty = |
427 | 0 | if param.ty.kind == crate::frontend::ast::TypeKind::Named("Any".to_string()) { |
428 | | // Untyped parameter - create fresh type variable |
429 | 0 | MonoType::Var(self.gen.fresh()) |
430 | | } else { |
431 | | // Convert AST type to MonoType |
432 | 0 | Self::ast_type_to_mono_static(¶m.ty)? |
433 | | }; |
434 | 0 | param_types.push(param_ty.clone()); |
435 | 0 | self.env = self.env.extend(param.name(), TypeScheme::mono(param_ty)); |
436 | | } |
437 | | |
438 | | // Add function itself to environment for recursion |
439 | 0 | let result_var = MonoType::Var(self.gen.fresh()); |
440 | 0 | let func_type = param_types |
441 | 0 | .iter() |
442 | 0 | .rev() |
443 | 0 | .fold(result_var.clone(), |acc, param_ty| { |
444 | 0 | MonoType::Function(Box::new(param_ty.clone()), Box::new(acc)) |
445 | 0 | }); |
446 | 0 | self.env = self.env.extend(name, TypeScheme::mono(func_type.clone())); |
447 | | |
448 | | // Infer body type |
449 | 0 | let body_ty = self.infer_expr(body)?; |
450 | 0 | self.unifier.unify(&result_var, &body_ty)?; |
451 | | |
452 | 0 | self.env = old_env; |
453 | | |
454 | 0 | let final_type = self.unifier.apply(&func_type); |
455 | | |
456 | | // Always return the function type for type inference |
457 | | // The distinction between statements and expressions should be handled at a higher level |
458 | 0 | Ok(final_type) |
459 | 0 | } |
460 | | |
461 | 0 | fn infer_lambda(&mut self, params: &[Param], body: &Expr) -> Result<MonoType> { |
462 | 0 | let old_env = self.env.clone(); |
463 | | |
464 | | // Create type variables for parameters |
465 | 0 | let mut param_types = Vec::new(); |
466 | 0 | for param in params { |
467 | 0 | let param_ty = match ¶m.ty.kind { |
468 | 0 | TypeKind::Named(name) if name == "Any" || name == "_" => { |
469 | | // Untyped parameter - create fresh type variable |
470 | 0 | MonoType::Var(self.gen.fresh()) |
471 | | } |
472 | | _ => { |
473 | | // Convert AST type to MonoType |
474 | 0 | Self::ast_type_to_mono_static(¶m.ty)? |
475 | | } |
476 | | }; |
477 | 0 | param_types.push(param_ty.clone()); |
478 | 0 | self.env = self.env.extend(param.name(), TypeScheme::mono(param_ty)); |
479 | | } |
480 | | |
481 | | // Infer body type |
482 | 0 | let body_ty = self.infer_expr(body)?; |
483 | | |
484 | | // Restore environment |
485 | 0 | self.env = old_env; |
486 | | |
487 | | // Build function type from parameters and body |
488 | 0 | let lambda_type = param_types.iter().rev().fold(body_ty, |acc, param_ty| { |
489 | 0 | MonoType::Function(Box::new(param_ty.clone()), Box::new(acc)) |
490 | 0 | }); |
491 | | |
492 | 0 | Ok(self.unifier.apply(&lambda_type)) |
493 | 0 | } |
494 | | |
495 | 0 | fn infer_call(&mut self, func: &Expr, args: &[Expr]) -> Result<MonoType> { |
496 | 0 | let func_ty = self.infer_expr(func)?; |
497 | | |
498 | | // Create type for the function we expect |
499 | 0 | let result_ty = MonoType::Var(self.gen.fresh()); |
500 | 0 | let mut expected_func_ty = result_ty.clone(); |
501 | | |
502 | 0 | for arg in args.iter().rev() { |
503 | 0 | let arg_ty = self.infer_expr(arg)?; |
504 | 0 | expected_func_ty = MonoType::Function(Box::new(arg_ty), Box::new(expected_func_ty)); |
505 | | } |
506 | | |
507 | | // Unify with actual function type |
508 | 0 | self.unifier.unify(&func_ty, &expected_func_ty)?; |
509 | | |
510 | 0 | Ok(self.unifier.apply(&result_ty)) |
511 | 0 | } |
512 | | |
513 | 0 | fn infer_macro(&mut self, name: &str, args: &[Expr]) -> Result<MonoType> { |
514 | | // Type check the arguments first |
515 | 0 | for arg in args { |
516 | 0 | self.infer_expr(arg)?; |
517 | | } |
518 | | |
519 | | // Determine the return type based on the macro name |
520 | 0 | match name { |
521 | 0 | "println" => Ok(MonoType::Unit), // println! returns unit |
522 | 0 | "vec" => { |
523 | | // vec! returns a vector of the element type |
524 | 0 | if args.is_empty() { |
525 | | // Empty vec! needs type annotation or we use a generic type |
526 | 0 | Ok(MonoType::List(Box::new(MonoType::Var(self.gen.fresh())))) |
527 | | } else { |
528 | | // Infer element type from first argument |
529 | 0 | let elem_ty = self.infer_expr(&args[0])?; |
530 | 0 | Ok(MonoType::List(Box::new(elem_ty))) |
531 | | } |
532 | | } |
533 | 0 | _ => bail!("Unknown macro: {}", name), |
534 | | } |
535 | 0 | } |
536 | | |
537 | | /// REFACTORED FOR COMPLEXITY REDUCTION |
538 | | /// Original: 41 cyclomatic complexity, Target: <20 |
539 | | /// Strategy: Extract method-category specific handlers |
540 | 0 | pub fn infer_method_call( |
541 | 0 | &mut self, |
542 | 0 | receiver: &Expr, |
543 | 0 | method: &str, |
544 | 0 | args: &[Expr], |
545 | 0 | ) -> Result<MonoType> { |
546 | 0 | let receiver_ty = self.infer_expr(receiver)?; |
547 | 0 | self.add_method_constraint(&receiver_ty, method, args)?; |
548 | | |
549 | | // Dispatch based on receiver type category (complexity: delegated) |
550 | 0 | match &receiver_ty { |
551 | 0 | MonoType::List(_) => self.infer_list_method(&receiver_ty, method, args), |
552 | 0 | MonoType::String => self.infer_string_method(&receiver_ty, method, args), |
553 | | MonoType::DataFrame(_) | MonoType::Series(_) => { |
554 | 0 | self.infer_dataframe_method(&receiver_ty, method, args) |
555 | | } |
556 | 0 | MonoType::Named(name) if name == "DataFrame" || name == "Series" => { |
557 | 0 | self.infer_dataframe_method(&receiver_ty, method, args) |
558 | | } |
559 | 0 | _ => self.infer_generic_method(&receiver_ty, method, args), |
560 | | } |
561 | 0 | } |
562 | | |
563 | | /// Extract method constraint addition (complexity ~3) |
564 | 0 | fn add_method_constraint( |
565 | 0 | &mut self, |
566 | 0 | receiver_ty: &MonoType, |
567 | 0 | method: &str, |
568 | 0 | args: &[Expr] |
569 | 0 | ) -> Result<()> { |
570 | 0 | let arg_types: Result<Vec<_>> = args.iter().map(|arg| self.infer_expr(arg)).collect(); |
571 | 0 | let arg_types = arg_types?; |
572 | | |
573 | 0 | self.type_constraints.push(TypeConstraint::MethodCall( |
574 | 0 | receiver_ty.clone(), |
575 | 0 | method.to_string(), |
576 | 0 | arg_types, |
577 | 0 | )); |
578 | 0 | Ok(()) |
579 | 0 | } |
580 | | |
581 | | /// Extract list method handling (complexity ~10) |
582 | 0 | fn infer_list_method( |
583 | 0 | &mut self, |
584 | 0 | receiver_ty: &MonoType, |
585 | 0 | method: &str, |
586 | 0 | args: &[Expr] |
587 | 0 | ) -> Result<MonoType> { |
588 | 0 | if let MonoType::List(elem_ty) = receiver_ty { |
589 | 0 | match method { |
590 | 0 | "len" | "length" => { |
591 | 0 | self.validate_no_args(method, args)?; |
592 | 0 | Ok(MonoType::Int) |
593 | | } |
594 | 0 | "push" => { |
595 | 0 | self.validate_single_arg(method, args)?; |
596 | 0 | let arg_ty = self.infer_expr(&args[0])?; |
597 | 0 | self.unifier.unify(&arg_ty, elem_ty)?; |
598 | 0 | Ok(MonoType::Unit) |
599 | | } |
600 | 0 | "pop" => { |
601 | 0 | self.validate_no_args(method, args)?; |
602 | 0 | Ok(MonoType::Optional(elem_ty.clone())) |
603 | | } |
604 | 0 | "sorted" | "reversed" | "unique" => { |
605 | 0 | self.validate_no_args(method, args)?; |
606 | 0 | Ok(MonoType::List(elem_ty.clone())) |
607 | | } |
608 | 0 | "sum" => { |
609 | 0 | self.validate_no_args(method, args)?; |
610 | 0 | Ok(*elem_ty.clone()) |
611 | | } |
612 | 0 | "min" | "max" => { |
613 | 0 | self.validate_no_args(method, args)?; |
614 | 0 | Ok(MonoType::Optional(elem_ty.clone())) |
615 | | } |
616 | 0 | _ => self.infer_generic_method(receiver_ty, method, args), |
617 | | } |
618 | | } else { |
619 | 0 | self.infer_generic_method(receiver_ty, method, args) |
620 | | } |
621 | 0 | } |
622 | | |
623 | | /// Extract string method handling (complexity ~5) |
624 | 0 | fn infer_string_method( |
625 | 0 | &mut self, |
626 | 0 | receiver_ty: &MonoType, |
627 | 0 | method: &str, |
628 | 0 | args: &[Expr] |
629 | 0 | ) -> Result<MonoType> { |
630 | 0 | match method { |
631 | 0 | "len" | "length" => { |
632 | 0 | self.validate_no_args(method, args)?; |
633 | 0 | Ok(MonoType::Int) |
634 | | } |
635 | 0 | "chars" => { |
636 | 0 | self.validate_no_args(method, args)?; |
637 | 0 | Ok(MonoType::List(Box::new(MonoType::String))) |
638 | | } |
639 | 0 | _ => self.infer_generic_method(receiver_ty, method, args), |
640 | | } |
641 | 0 | } |
642 | | |
643 | | /// Extract dataframe method handling (complexity ~8) |
644 | 0 | fn infer_dataframe_method( |
645 | 0 | &mut self, |
646 | 0 | receiver_ty: &MonoType, |
647 | 0 | method: &str, |
648 | 0 | args: &[Expr] |
649 | 0 | ) -> Result<MonoType> { |
650 | 0 | match method { |
651 | 0 | "filter" | "groupby" | "agg" | "select" => { |
652 | 0 | match receiver_ty { |
653 | 0 | MonoType::DataFrame(columns) => Ok(MonoType::DataFrame(columns.clone())), |
654 | 0 | MonoType::Named(name) if name == "DataFrame" => { |
655 | 0 | Ok(MonoType::Named("DataFrame".to_string())) |
656 | | } |
657 | 0 | _ => Ok(MonoType::Named("DataFrame".to_string())), |
658 | | } |
659 | | } |
660 | 0 | "mean" | "std" | "sum" | "count" => Ok(MonoType::Float), |
661 | 0 | "col" => self.infer_column_selection(receiver_ty, args), |
662 | 0 | _ => self.infer_generic_method(receiver_ty, method, args), |
663 | | } |
664 | 0 | } |
665 | | |
666 | | /// Extract column selection logic (complexity ~5) |
667 | 0 | fn infer_column_selection( |
668 | 0 | &mut self, |
669 | 0 | receiver_ty: &MonoType, |
670 | 0 | args: &[Expr] |
671 | 0 | ) -> Result<MonoType> { |
672 | 0 | if let MonoType::DataFrame(columns) = receiver_ty { |
673 | 0 | if let Some(arg) = args.first() { |
674 | 0 | if let ExprKind::Literal(Literal::String(col_name)) = &arg.kind { |
675 | 0 | if let Some((_, col_type)) = columns.iter().find(|(name, _)| name == col_name) { |
676 | 0 | return Ok(MonoType::Series(Box::new(col_type.clone()))); |
677 | 0 | } |
678 | 0 | } |
679 | 0 | } |
680 | 0 | Ok(MonoType::Series(Box::new(MonoType::Var(self.gen.fresh())))) |
681 | | } else { |
682 | 0 | Ok(MonoType::Series(Box::new(MonoType::Var(self.gen.fresh())))) |
683 | | } |
684 | 0 | } |
685 | | |
686 | | /// Extract generic method handling (complexity ~8) |
687 | 0 | fn infer_generic_method( |
688 | 0 | &mut self, |
689 | 0 | receiver_ty: &MonoType, |
690 | 0 | method: &str, |
691 | 0 | args: &[Expr] |
692 | 0 | ) -> Result<MonoType> { |
693 | 0 | if let Some(scheme) = self.env.lookup(method) { |
694 | 0 | let method_ty = self.env.instantiate(scheme, &mut self.gen); |
695 | 0 | let result_ty = MonoType::Var(self.gen.fresh()); |
696 | 0 | let expected_func_ty = self.build_method_function_type(receiver_ty, args, result_ty.clone())?; |
697 | | |
698 | 0 | self.unifier.unify(&method_ty, &expected_func_ty)?; |
699 | 0 | Ok(self.unifier.apply(&result_ty)) |
700 | | } else { |
701 | 0 | Ok(MonoType::Var(self.gen.fresh())) |
702 | | } |
703 | 0 | } |
704 | | |
705 | | /// Extract function type construction (complexity ~4) |
706 | 0 | fn build_method_function_type( |
707 | 0 | &mut self, |
708 | 0 | receiver_ty: &MonoType, |
709 | 0 | args: &[Expr], |
710 | 0 | result_ty: MonoType |
711 | 0 | ) -> Result<MonoType> { |
712 | 0 | let mut expected_func_ty = result_ty; |
713 | | |
714 | 0 | for arg in args.iter().rev() { |
715 | 0 | let arg_ty = self.infer_expr(arg)?; |
716 | 0 | expected_func_ty = MonoType::Function(Box::new(arg_ty), Box::new(expected_func_ty)); |
717 | | } |
718 | | |
719 | | // Add receiver as first argument |
720 | 0 | expected_func_ty = MonoType::Function(Box::new(receiver_ty.clone()), Box::new(expected_func_ty)); |
721 | 0 | Ok(expected_func_ty) |
722 | 0 | } |
723 | | |
724 | | /// Helper methods for argument validation (complexity ~3 each) |
725 | 0 | fn validate_no_args(&self, method: &str, args: &[Expr]) -> Result<()> { |
726 | 0 | if !args.is_empty() { |
727 | 0 | bail!("Method {} takes no arguments", method); |
728 | 0 | } |
729 | 0 | Ok(()) |
730 | 0 | } |
731 | | |
732 | 0 | fn validate_single_arg(&self, method: &str, args: &[Expr]) -> Result<()> { |
733 | 0 | if args.len() != 1 { |
734 | 0 | bail!("Method {} takes exactly one argument", method); |
735 | 0 | } |
736 | 0 | Ok(()) |
737 | 0 | } |
738 | | |
739 | 0 | fn infer_block(&mut self, exprs: &[Expr]) -> Result<MonoType> { |
740 | 0 | if exprs.is_empty() { |
741 | 0 | return Ok(MonoType::Unit); |
742 | 0 | } |
743 | | |
744 | 0 | let mut last_ty = MonoType::Unit; |
745 | 0 | for expr in exprs { |
746 | 0 | last_ty = self.infer_expr(expr)?; |
747 | | } |
748 | | |
749 | 0 | Ok(last_ty) |
750 | 0 | } |
751 | | |
752 | 0 | fn infer_list(&mut self, elements: &[Expr]) -> Result<MonoType> { |
753 | 0 | if elements.is_empty() { |
754 | | // Empty list with fresh type variable |
755 | 0 | let elem_ty = MonoType::Var(self.gen.fresh()); |
756 | 0 | return Ok(MonoType::List(Box::new(elem_ty))); |
757 | 0 | } |
758 | | |
759 | | // All elements must have same type |
760 | 0 | let first_ty = self.infer_expr(&elements[0])?; |
761 | 0 | for elem in &elements[1..] { |
762 | 0 | let elem_ty = self.infer_expr(elem)?; |
763 | 0 | self.unifier.unify(&first_ty, &elem_ty)?; |
764 | | } |
765 | | |
766 | 0 | Ok(MonoType::List(Box::new(self.unifier.apply(&first_ty)))) |
767 | 0 | } |
768 | | |
769 | 0 | fn infer_list_comprehension( |
770 | 0 | &mut self, |
771 | 0 | element: &Expr, |
772 | 0 | variable: &str, |
773 | 0 | iterable: &Expr, |
774 | 0 | condition: Option<&Expr>, |
775 | 0 | ) -> Result<MonoType> { |
776 | | // Type check the iterable - must be a list |
777 | 0 | let iterable_ty = self.infer_expr(iterable)?; |
778 | 0 | let elem_ty = MonoType::Var(self.gen.fresh()); |
779 | 0 | self.unifier |
780 | 0 | .unify(&iterable_ty, &MonoType::List(Box::new(elem_ty.clone())))?; |
781 | | |
782 | | // Save the old environment and add the loop variable |
783 | 0 | let old_env = self.env.clone(); |
784 | 0 | self.env = self |
785 | 0 | .env |
786 | 0 | .extend(variable, TypeScheme::mono(self.unifier.apply(&elem_ty))); |
787 | | |
788 | | // Type check the optional condition (must be bool) |
789 | 0 | if let Some(cond) = condition { |
790 | 0 | let cond_ty = self.infer_expr(cond)?; |
791 | 0 | self.unifier.unify(&cond_ty, &MonoType::Bool)?; |
792 | 0 | } |
793 | | |
794 | | // Type check the element expression |
795 | 0 | let result_elem_ty = self.infer_expr(element)?; |
796 | | |
797 | | // Restore the environment |
798 | 0 | self.env = old_env; |
799 | | |
800 | | // Return List<T> where T is the type of the element expression |
801 | 0 | Ok(MonoType::List(Box::new( |
802 | 0 | self.unifier.apply(&result_elem_ty), |
803 | 0 | ))) |
804 | 0 | } |
805 | | |
806 | 0 | fn infer_match( |
807 | 0 | &mut self, |
808 | 0 | expr: &Expr, |
809 | 0 | arms: &[crate::frontend::ast::MatchArm], |
810 | 0 | ) -> Result<MonoType> { |
811 | 0 | let expr_ty = self.infer_expr(expr)?; |
812 | | |
813 | 0 | if arms.is_empty() { |
814 | 0 | bail!("Match expression must have at least one arm"); |
815 | 0 | } |
816 | | |
817 | | // All arms must return same type |
818 | 0 | let result_ty = MonoType::Var(self.gen.fresh()); |
819 | | |
820 | 0 | for arm in arms { |
821 | | // Infer pattern and bind variables |
822 | 0 | let old_env = self.env.clone(); |
823 | 0 | self.infer_pattern(&arm.pattern, &expr_ty)?; |
824 | | |
825 | | // Guards have been removed from the grammar |
826 | | |
827 | | // Infer body type |
828 | 0 | let body_ty = self.infer_expr(&arm.body)?; |
829 | 0 | self.unifier.unify(&result_ty, &body_ty)?; |
830 | | |
831 | 0 | self.env = old_env; |
832 | | } |
833 | | |
834 | 0 | Ok(self.unifier.apply(&result_ty)) |
835 | 0 | } |
836 | | |
837 | 0 | fn infer_pattern(&mut self, pattern: &Pattern, expected_ty: &MonoType) -> Result<()> { |
838 | 0 | match pattern { |
839 | 0 | Pattern::Wildcard => Ok(()), |
840 | 0 | Pattern::Literal(lit) => { |
841 | 0 | let lit_ty = Self::infer_literal(lit); |
842 | 0 | self.unifier.unify(expected_ty, &lit_ty) |
843 | | } |
844 | 0 | Pattern::Identifier(name) => { |
845 | | // Bind the identifier to the expected type |
846 | 0 | self.env = self.env.extend(name, TypeScheme::mono(expected_ty.clone())); |
847 | 0 | Ok(()) |
848 | | } |
849 | 0 | Pattern::QualifiedName(_path) => { |
850 | | // Qualified names in patterns should match against specific enum variants |
851 | | // For now, assume it's valid |
852 | 0 | Ok(()) |
853 | | } |
854 | 0 | Pattern::List(patterns) => { |
855 | 0 | let elem_ty = MonoType::Var(self.gen.fresh()); |
856 | 0 | self.unifier |
857 | 0 | .unify(expected_ty, &MonoType::List(Box::new(elem_ty.clone())))?; |
858 | | |
859 | 0 | for pat in patterns { |
860 | 0 | self.infer_pattern(pat, &elem_ty)?; |
861 | | } |
862 | 0 | Ok(()) |
863 | | } |
864 | 0 | Pattern::Ok(inner) => { |
865 | | // Expected type should be Result<T, E>, extract T for inner pattern |
866 | 0 | if let MonoType::Result(ok_ty, _) = expected_ty { |
867 | 0 | self.infer_pattern(inner, ok_ty) |
868 | | } else { |
869 | | // Create a fresh Result type |
870 | 0 | let error_ty = MonoType::Var(self.gen.fresh()); |
871 | 0 | let inner_ty = MonoType::Var(self.gen.fresh()); |
872 | 0 | let result_ty = |
873 | 0 | MonoType::Result(Box::new(inner_ty.clone()), Box::new(error_ty)); |
874 | 0 | self.unifier.unify(expected_ty, &result_ty)?; |
875 | 0 | self.infer_pattern(inner, &inner_ty) |
876 | | } |
877 | | } |
878 | 0 | Pattern::Err(inner) => { |
879 | | // Expected type should be Result<T, E>, extract E for inner pattern |
880 | 0 | if let MonoType::Result(_, err_ty) = expected_ty { |
881 | 0 | self.infer_pattern(inner, err_ty) |
882 | | } else { |
883 | | // Create a fresh Result type |
884 | 0 | let ok_ty = MonoType::Var(self.gen.fresh()); |
885 | 0 | let inner_ty = MonoType::Var(self.gen.fresh()); |
886 | 0 | let result_ty = MonoType::Result(Box::new(ok_ty), Box::new(inner_ty.clone())); |
887 | 0 | self.unifier.unify(expected_ty, &result_ty)?; |
888 | 0 | self.infer_pattern(inner, &inner_ty) |
889 | | } |
890 | | } |
891 | 0 | Pattern::Some(inner) => { |
892 | | // Expected type should be Option<T>, extract T for inner pattern |
893 | 0 | if let MonoType::Optional(inner_ty) = expected_ty { |
894 | 0 | self.infer_pattern(inner, inner_ty) |
895 | | } else { |
896 | | // Create a fresh Option type |
897 | 0 | let inner_ty = MonoType::Var(self.gen.fresh()); |
898 | 0 | let option_ty = MonoType::Optional(Box::new(inner_ty.clone())); |
899 | 0 | self.unifier.unify(expected_ty, &option_ty)?; |
900 | 0 | self.infer_pattern(inner, &inner_ty) |
901 | | } |
902 | | } |
903 | | Pattern::None => { |
904 | | // None pattern matches Option<T> where T can be any type |
905 | 0 | let type_var = MonoType::Var(self.gen.fresh()); |
906 | 0 | let option_ty = MonoType::Optional(Box::new(type_var)); |
907 | 0 | self.unifier.unify(expected_ty, &option_ty) |
908 | | } |
909 | 0 | Pattern::Tuple(patterns) => { |
910 | | // Create tuple type with each pattern's inferred type |
911 | 0 | let mut elem_types = Vec::new(); |
912 | 0 | for pat in patterns { |
913 | 0 | let elem_ty = MonoType::Var(self.gen.fresh()); |
914 | 0 | self.infer_pattern(pat, &elem_ty)?; |
915 | 0 | elem_types.push(elem_ty); |
916 | | } |
917 | 0 | let tuple_ty = MonoType::Tuple(elem_types); |
918 | 0 | self.unifier.unify(expected_ty, &tuple_ty) |
919 | | } |
920 | 0 | Pattern::Struct { name, fields, has_rest: _ } => { |
921 | | // For now, treat struct patterns as a named type |
922 | | // In a more complete implementation, we'd look up the struct definition |
923 | 0 | let struct_ty = MonoType::Named(name.clone()); |
924 | 0 | self.unifier.unify(expected_ty, &struct_ty)?; |
925 | | |
926 | | // Infer field patterns (simplified approach) |
927 | 0 | for field in fields { |
928 | 0 | if let Some(pattern) = &field.pattern { |
929 | 0 | let field_ty = MonoType::Var(self.gen.fresh()); |
930 | 0 | self.infer_pattern(pattern, &field_ty)?; |
931 | 0 | } |
932 | | } |
933 | 0 | Ok(()) |
934 | | } |
935 | 0 | Pattern::Range { start, end, .. } => { |
936 | | // Range patterns should match numeric types |
937 | 0 | let start_ty = MonoType::Var(self.gen.fresh()); |
938 | 0 | let end_ty = MonoType::Var(self.gen.fresh()); |
939 | 0 | self.infer_pattern(start, &start_ty)?; |
940 | 0 | self.infer_pattern(end, &end_ty)?; |
941 | | |
942 | | // Unify start and end types, and with expected type |
943 | 0 | self.unifier.unify(&start_ty, &end_ty)?; |
944 | 0 | self.unifier.unify(expected_ty, &start_ty) |
945 | | } |
946 | 0 | Pattern::Or(patterns) => { |
947 | | // All patterns in an OR must have the same type |
948 | 0 | for pat in patterns { |
949 | 0 | self.infer_pattern(pat, expected_ty)?; |
950 | | } |
951 | 0 | Ok(()) |
952 | | } |
953 | | Pattern::Rest => { |
954 | | // Rest patterns don't bind to specific types |
955 | 0 | Ok(()) |
956 | | } |
957 | 0 | Pattern::RestNamed(name) => { |
958 | | // Named rest patterns bind the remaining elements to the name |
959 | | // For arrays [first, ..rest], rest should be array type |
960 | 0 | self.env = self.env.extend(name, TypeScheme::mono(expected_ty.clone())); |
961 | 0 | Ok(()) |
962 | | } |
963 | 0 | Pattern::WithDefault { pattern, .. } => { |
964 | | // For default patterns, we check the inner pattern with the expected type |
965 | | // The default value will be used if the actual value doesn't match |
966 | 0 | self.infer_pattern(pattern, expected_ty) |
967 | | } |
968 | | } |
969 | 0 | } |
970 | | |
971 | 0 | fn infer_for(&mut self, var: &str, iter: &Expr, body: &Expr) -> Result<MonoType> { |
972 | 0 | let iter_ty = self.infer_expr(iter)?; |
973 | | |
974 | | // Iterator should be a list |
975 | 0 | let elem_ty = MonoType::Var(self.gen.fresh()); |
976 | 0 | self.unifier |
977 | 0 | .unify(&iter_ty, &MonoType::List(Box::new(elem_ty.clone())))?; |
978 | | |
979 | | // Bind loop variable and infer body |
980 | 0 | let old_env = self.env.clone(); |
981 | 0 | self.env = self.env.extend(var, TypeScheme::mono(elem_ty)); |
982 | 0 | let _body_ty = self.infer_expr(body)?; |
983 | 0 | self.env = old_env; |
984 | | |
985 | | // For loops always return Unit regardless of body type |
986 | 0 | Ok(MonoType::Unit) |
987 | 0 | } |
988 | | |
989 | 0 | fn infer_while(&mut self, condition: &Expr, body: &Expr) -> Result<MonoType> { |
990 | | // Condition must be Bool |
991 | 0 | let cond_ty = self.infer_expr(condition)?; |
992 | 0 | self.unifier.unify(&cond_ty, &MonoType::Bool)?; |
993 | | |
994 | | // Type check body |
995 | 0 | let body_ty = self.infer_expr(body)?; |
996 | 0 | self.unifier.unify(&body_ty, &MonoType::Unit)?; |
997 | | |
998 | | // While loops return unit |
999 | 0 | Ok(MonoType::Unit) |
1000 | 0 | } |
1001 | | |
1002 | 0 | fn infer_loop(&mut self, body: &Expr) -> Result<MonoType> { |
1003 | | // Type check body |
1004 | 0 | let body_ty = self.infer_expr(body)?; |
1005 | 0 | self.unifier.unify(&body_ty, &MonoType::Unit)?; |
1006 | | |
1007 | | // Loop expressions return unit |
1008 | 0 | Ok(MonoType::Unit) |
1009 | 0 | } |
1010 | | |
1011 | 0 | fn infer_range(&mut self, start: &Expr, end: &Expr) -> Result<MonoType> { |
1012 | 0 | let start_ty = self.infer_expr(start)?; |
1013 | 0 | let end_ty = self.infer_expr(end)?; |
1014 | | |
1015 | | // Both must be integers |
1016 | 0 | self.unifier.unify(&start_ty, &MonoType::Int)?; |
1017 | 0 | self.unifier.unify(&end_ty, &MonoType::Int)?; |
1018 | | |
1019 | | // Range produces a list of integers |
1020 | 0 | Ok(MonoType::List(Box::new(MonoType::Int))) |
1021 | 0 | } |
1022 | | |
1023 | 0 | fn infer_pipeline( |
1024 | 0 | &mut self, |
1025 | 0 | expr: &Expr, |
1026 | 0 | stages: &[crate::frontend::ast::PipelineStage], |
1027 | 0 | ) -> Result<MonoType> { |
1028 | 0 | let mut current_ty = self.infer_expr(expr)?; |
1029 | | |
1030 | 0 | for stage in stages { |
1031 | | // Each stage is a function applied to current value |
1032 | 0 | let stage_ty = self.infer_expr(&stage.op)?; |
1033 | | |
1034 | | // Create expected function type |
1035 | 0 | let result_ty = MonoType::Var(self.gen.fresh()); |
1036 | 0 | let expected_func = |
1037 | 0 | MonoType::Function(Box::new(current_ty.clone()), Box::new(result_ty.clone())); |
1038 | | |
1039 | 0 | self.unifier.unify(&stage_ty, &expected_func)?; |
1040 | 0 | current_ty = self.unifier.apply(&result_ty); |
1041 | | } |
1042 | | |
1043 | 0 | Ok(current_ty) |
1044 | 0 | } |
1045 | | |
1046 | 0 | fn infer_assign(&mut self, target: &Expr, value: &Expr) -> Result<MonoType> { |
1047 | | // Infer the type of the value being assigned |
1048 | 0 | let value_ty = self.infer_expr(value)?; |
1049 | | |
1050 | | // Infer the type of the target (lvalue) |
1051 | 0 | let target_ty = self.infer_expr(target)?; |
1052 | | |
1053 | | // Target and value must have compatible types |
1054 | 0 | self.unifier.unify(&target_ty, &value_ty)?; |
1055 | | |
1056 | | // Assignment expressions return Unit |
1057 | 0 | Ok(MonoType::Unit) |
1058 | 0 | } |
1059 | | |
1060 | 0 | fn infer_compound_assign( |
1061 | 0 | &mut self, |
1062 | 0 | target: &Expr, |
1063 | 0 | op: BinaryOp, |
1064 | 0 | value: &Expr, |
1065 | 0 | ) -> Result<MonoType> { |
1066 | | // Infer the types of target and value |
1067 | 0 | let target_ty = self.infer_expr(target)?; |
1068 | 0 | let value_ty = self.infer_expr(value)?; |
1069 | | |
1070 | | // For compound assignment, we need to ensure the operation is valid |
1071 | | // This is equivalent to: target = target op value |
1072 | 0 | let result_ty = self.infer_binary_op_type(op, &target_ty, &value_ty)?; |
1073 | | |
1074 | | // The result type must be compatible with the target type |
1075 | 0 | self.unifier.unify(&target_ty, &result_ty)?; |
1076 | | |
1077 | | // Compound assignment expressions return Unit |
1078 | 0 | Ok(MonoType::Unit) |
1079 | 0 | } |
1080 | | |
1081 | 0 | fn infer_binary_op_type( |
1082 | 0 | &mut self, |
1083 | 0 | op: BinaryOp, |
1084 | 0 | left_ty: &MonoType, |
1085 | 0 | right_ty: &MonoType, |
1086 | 0 | ) -> Result<MonoType> { |
1087 | 0 | match op { |
1088 | | BinaryOp::Add |
1089 | | | BinaryOp::Subtract |
1090 | | | BinaryOp::Multiply |
1091 | | | BinaryOp::Divide |
1092 | | | BinaryOp::Modulo => { |
1093 | | // Arithmetic operations: both operands should be numbers, result is same type |
1094 | | // Try Int first, then Float |
1095 | 0 | if let Ok(()) = self.unifier.unify(left_ty, &MonoType::Int) { |
1096 | 0 | if let Ok(()) = self.unifier.unify(right_ty, &MonoType::Int) { |
1097 | 0 | return Ok(MonoType::Int); |
1098 | 0 | } |
1099 | 0 | } |
1100 | | // Fall back to Float |
1101 | 0 | self.unifier.unify(left_ty, &MonoType::Float)?; |
1102 | 0 | self.unifier.unify(right_ty, &MonoType::Float)?; |
1103 | 0 | Ok(MonoType::Float) |
1104 | | } |
1105 | | BinaryOp::Power => { |
1106 | | // Power operation: base and exponent are numbers, result is same as base |
1107 | 0 | self.unifier.unify(left_ty, right_ty)?; |
1108 | 0 | if let Ok(()) = self.unifier.unify(left_ty, &MonoType::Int) { |
1109 | 0 | Ok(MonoType::Int) |
1110 | | } else { |
1111 | 0 | self.unifier.unify(left_ty, &MonoType::Float)?; |
1112 | 0 | Ok(MonoType::Float) |
1113 | | } |
1114 | | } |
1115 | | BinaryOp::Equal |
1116 | | | BinaryOp::NotEqual |
1117 | | | BinaryOp::Less |
1118 | | | BinaryOp::LessEqual |
1119 | | | BinaryOp::Greater |
1120 | | | BinaryOp::GreaterEqual => { |
1121 | | // Comparison operations: operands must be same type, result is Bool |
1122 | 0 | self.unifier.unify(left_ty, right_ty)?; |
1123 | 0 | Ok(MonoType::Bool) |
1124 | | } |
1125 | | BinaryOp::And | BinaryOp::Or => { |
1126 | | // Logical operations: both operands must be Bool, result is Bool |
1127 | 0 | self.unifier.unify(left_ty, &MonoType::Bool)?; |
1128 | 0 | self.unifier.unify(right_ty, &MonoType::Bool)?; |
1129 | 0 | Ok(MonoType::Bool) |
1130 | | } |
1131 | | BinaryOp::NullCoalesce => { |
1132 | | // Null coalescing: return type should be the non-null operand type |
1133 | | // For now, return right_ty (could be improved with proper union types) |
1134 | 0 | Ok(right_ty.clone()) |
1135 | | } |
1136 | | BinaryOp::BitwiseAnd |
1137 | | | BinaryOp::BitwiseOr |
1138 | | | BinaryOp::BitwiseXor |
1139 | | | BinaryOp::LeftShift => { |
1140 | | // Bitwise operations: both operands must be Int, result is Int |
1141 | 0 | self.unifier.unify(left_ty, &MonoType::Int)?; |
1142 | 0 | self.unifier.unify(right_ty, &MonoType::Int)?; |
1143 | 0 | Ok(MonoType::Int) |
1144 | | } |
1145 | | } |
1146 | 0 | } |
1147 | | |
1148 | 0 | fn infer_increment_decrement(&mut self, target: &Expr) -> Result<MonoType> { |
1149 | | // Infer the type of the target |
1150 | 0 | let target_ty = self.infer_expr(target)?; |
1151 | | |
1152 | | // Target must be a numeric type (Int or Float) |
1153 | | // Try Int first, then Float |
1154 | 0 | if let Ok(()) = self.unifier.unify(&target_ty, &MonoType::Int) { |
1155 | 0 | Ok(MonoType::Int) |
1156 | | } else { |
1157 | 0 | self.unifier.unify(&target_ty, &MonoType::Float)?; |
1158 | 0 | Ok(MonoType::Float) |
1159 | | } |
1160 | 0 | } |
1161 | | |
1162 | 0 | fn ast_type_to_mono_static(ty: &crate::frontend::ast::Type) -> Result<MonoType> { |
1163 | | use crate::frontend::ast::TypeKind; |
1164 | | |
1165 | 0 | Ok(match &ty.kind { |
1166 | 0 | TypeKind::Named(name) => match name.as_str() { |
1167 | 0 | "i32" | "i64" => MonoType::Int, |
1168 | 0 | "f32" | "f64" => MonoType::Float, |
1169 | 0 | "bool" => MonoType::Bool, |
1170 | 0 | "String" | "str" => MonoType::String, |
1171 | 0 | "Any" => MonoType::Var(TyVarGenerator::new().fresh()), |
1172 | 0 | _ => MonoType::Named(name.clone()), |
1173 | | }, |
1174 | 0 | TypeKind::Generic { base, params } => { |
1175 | | // For now, treat generic types as their base type |
1176 | | // Full generic inference will be implemented later |
1177 | 0 | match base.as_str() { |
1178 | 0 | "Vec" | "List" => { |
1179 | 0 | if let Some(first_param) = params.first() { |
1180 | 0 | MonoType::List(Box::new(Self::ast_type_to_mono_static(first_param)?)) |
1181 | | } else { |
1182 | 0 | MonoType::List(Box::new(MonoType::Var(TyVarGenerator::new().fresh()))) |
1183 | | } |
1184 | | } |
1185 | 0 | "Option" => { |
1186 | 0 | if let Some(first_param) = params.first() { |
1187 | 0 | MonoType::Optional(Box::new(Self::ast_type_to_mono_static( |
1188 | 0 | first_param, |
1189 | 0 | )?)) |
1190 | | } else { |
1191 | 0 | MonoType::Optional(Box::new(MonoType::Var( |
1192 | 0 | TyVarGenerator::new().fresh(), |
1193 | 0 | ))) |
1194 | | } |
1195 | | } |
1196 | 0 | _ => MonoType::Named(base.clone()), |
1197 | | } |
1198 | | } |
1199 | 0 | TypeKind::Optional(inner) => { |
1200 | 0 | MonoType::Optional(Box::new(Self::ast_type_to_mono_static(inner)?)) |
1201 | | } |
1202 | 0 | TypeKind::List(inner) => { |
1203 | 0 | MonoType::List(Box::new(Self::ast_type_to_mono_static(inner)?)) |
1204 | | } |
1205 | 0 | TypeKind::Function { params, ret } => { |
1206 | 0 | let ret_ty = Self::ast_type_to_mono_static(ret)?; |
1207 | 0 | let result: Result<MonoType> = |
1208 | 0 | params.iter().rev().try_fold(ret_ty, |acc, param| { |
1209 | | Ok(MonoType::Function( |
1210 | 0 | Box::new(Self::ast_type_to_mono_static(param)?), |
1211 | 0 | Box::new(acc), |
1212 | | )) |
1213 | 0 | }); |
1214 | 0 | result? |
1215 | | } |
1216 | 0 | TypeKind::DataFrame { columns } => { |
1217 | 0 | let mut col_types = Vec::new(); |
1218 | 0 | for (name, ty) in columns { |
1219 | 0 | col_types.push((name.clone(), Self::ast_type_to_mono_static(ty)?)); |
1220 | | } |
1221 | 0 | MonoType::DataFrame(col_types) |
1222 | | } |
1223 | 0 | TypeKind::Series { dtype } => { |
1224 | 0 | MonoType::Series(Box::new(Self::ast_type_to_mono_static(dtype)?)) |
1225 | | } |
1226 | 0 | TypeKind::Tuple(types) => { |
1227 | 0 | let mono_types: Result<Vec<_>> = types |
1228 | 0 | .iter() |
1229 | 0 | .map(Self::ast_type_to_mono_static) |
1230 | 0 | .collect(); |
1231 | 0 | MonoType::Tuple(mono_types?) |
1232 | | } |
1233 | 0 | TypeKind::Reference { inner, .. } => { |
1234 | | // For type inference, treat references the same as the inner type |
1235 | 0 | Self::ast_type_to_mono_static(inner)? |
1236 | | } |
1237 | | }) |
1238 | 0 | } |
1239 | | |
1240 | | /// Get the final inferred type for a type variable |
1241 | | #[must_use] |
1242 | 0 | pub fn solve(&self, var: &crate::middleend::types::TyVar) -> MonoType { |
1243 | 0 | self.unifier.solve(var) |
1244 | 0 | } |
1245 | | |
1246 | | /// Apply current substitution to a type |
1247 | | #[must_use] |
1248 | 0 | pub fn apply(&self, ty: &MonoType) -> MonoType { |
1249 | 0 | self.unifier.apply(ty) |
1250 | 0 | } |
1251 | | |
1252 | | /// Infer types for control flow expressions (if, match, loops) |
1253 | | /// |
1254 | | /// # Example Usage |
1255 | | /// Handles type inference for control flow constructs. |
1256 | | /// For if expressions, ensures both branches have compatible types. |
1257 | | /// For match expressions, checks pattern compatibility and branch types. |
1258 | 0 | fn infer_control_flow_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1259 | 0 | match &expr.kind { |
1260 | 0 | ExprKind::If { condition, then_branch, else_branch } => { |
1261 | 0 | self.infer_if(condition, then_branch, else_branch.as_deref()) |
1262 | | } |
1263 | 0 | ExprKind::For { var, iter, body, .. } => self.infer_for(var, iter, body), |
1264 | 0 | ExprKind::While { condition, body } => self.infer_while(condition, body), |
1265 | 0 | ExprKind::Loop { body } => self.infer_loop(body), |
1266 | 0 | ExprKind::IfLet { pattern: _, expr, then_branch, else_branch } => { |
1267 | 0 | let _expr_ty = self.infer_expr(expr)?; |
1268 | 0 | let then_ty = self.infer_expr(then_branch)?; |
1269 | 0 | let else_ty = if let Some(else_expr) = else_branch { |
1270 | 0 | self.infer_expr(else_expr)? |
1271 | | } else { |
1272 | 0 | MonoType::Unit |
1273 | | }; |
1274 | 0 | self.unifier.unify(&then_ty, &else_ty)?; |
1275 | 0 | Ok(then_ty) |
1276 | | } |
1277 | 0 | ExprKind::WhileLet { pattern: _, expr, body } => { |
1278 | 0 | let _expr_ty = self.infer_expr(expr)?; |
1279 | 0 | let _body_ty = self.infer_expr(body)?; |
1280 | 0 | Ok(MonoType::Unit) |
1281 | | } |
1282 | 0 | _ => bail!("Unexpected expression type in control flow handler"), |
1283 | | } |
1284 | 0 | } |
1285 | | |
1286 | | /// Infer types for function and lambda expressions |
1287 | 0 | fn infer_function_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1288 | 0 | match &expr.kind { |
1289 | 0 | ExprKind::Function { name, params, body, return_type, is_async, .. } => { |
1290 | 0 | self.infer_function(name, params, body, return_type.as_ref(), *is_async) |
1291 | | } |
1292 | 0 | ExprKind::Lambda { params, body } => self.infer_lambda(params, body), |
1293 | 0 | _ => bail!("Unexpected expression type in function handler"), |
1294 | | } |
1295 | 0 | } |
1296 | | |
1297 | | /// Infer types for collection expressions (lists, tuples, comprehensions) |
1298 | 0 | fn infer_collection_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1299 | 0 | match &expr.kind { |
1300 | 0 | ExprKind::List(elements) => self.infer_list(elements), |
1301 | 0 | ExprKind::Tuple(elements) => { |
1302 | 0 | let element_types: Result<Vec<_>> = elements.iter().map(|e| self.infer_expr(e)).collect(); |
1303 | 0 | Ok(MonoType::Tuple(element_types?)) |
1304 | | } |
1305 | 0 | ExprKind::ListComprehension { element, variable, iterable, condition } => { |
1306 | 0 | self.infer_list_comprehension(element, variable, iterable, condition.as_deref()) |
1307 | | } |
1308 | 0 | _ => bail!("Unexpected expression type in collection handler"), |
1309 | | } |
1310 | 0 | } |
1311 | | |
1312 | | /// Infer types for operations and method calls |
1313 | 0 | fn infer_operation_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1314 | 0 | match &expr.kind { |
1315 | 0 | ExprKind::Binary { left, op, right } => self.infer_binary(left, *op, right), |
1316 | 0 | ExprKind::Unary { op, operand } => self.infer_unary(*op, operand), |
1317 | 0 | ExprKind::Call { func, args } => self.infer_call(func, args), |
1318 | 0 | ExprKind::MethodCall { receiver, method, args } => { |
1319 | 0 | self.infer_method_call(receiver, method, args) |
1320 | | } |
1321 | 0 | _ => bail!("Unexpected expression type in operation handler"), |
1322 | | } |
1323 | 0 | } |
1324 | | |
1325 | | /// REFACTORED FOR COMPLEXITY REDUCTION |
1326 | | /// Original: 38 cyclomatic complexity, Target: <20 |
1327 | | /// Strategy: Group related expression types into category handlers |
1328 | 0 | pub fn infer_other_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1329 | 0 | match &expr.kind { |
1330 | | // Special cases that need specific handling |
1331 | 0 | ExprKind::StringInterpolation { parts } => self.infer_string_interpolation(parts), |
1332 | 0 | ExprKind::Throw { expr } => self.infer_throw(expr), |
1333 | 0 | ExprKind::Ok { value } => self.infer_result_ok(value), |
1334 | 0 | ExprKind::Err { error } => self.infer_result_err(error), |
1335 | | |
1336 | | // Control flow expressions (all return Unit) |
1337 | | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => { |
1338 | 0 | self.infer_other_control_flow_expr(expr) |
1339 | | } |
1340 | | |
1341 | | // Definition expressions (all return Unit) |
1342 | | ExprKind::Struct { .. } | ExprKind::Enum { .. } | ExprKind::Trait { .. } | |
1343 | | ExprKind::Impl { .. } | ExprKind::Extension { .. } | ExprKind::Actor { .. } | |
1344 | | ExprKind::Import { .. } | ExprKind::Export { .. } => { |
1345 | 0 | self.infer_other_definition_expr(expr) |
1346 | | } |
1347 | | |
1348 | | // Literal and access expressions |
1349 | | ExprKind::StructLiteral { .. } | ExprKind::ObjectLiteral { .. } | |
1350 | | ExprKind::FieldAccess { .. } | ExprKind::IndexAccess { .. } | ExprKind::Slice { .. } => { |
1351 | 0 | self.infer_other_literal_access_expr(expr) |
1352 | | } |
1353 | | |
1354 | | // Option expressions |
1355 | 0 | ExprKind::Some { .. } | ExprKind::None => self.infer_other_option_expr(expr), |
1356 | | |
1357 | | // Async expressions |
1358 | | ExprKind::Await { .. } | ExprKind::AsyncBlock { .. } | ExprKind::Try { .. } => { |
1359 | 0 | self.infer_other_async_expr(expr) |
1360 | | } |
1361 | | |
1362 | | // Actor expressions |
1363 | | ExprKind::Send { .. } | ExprKind::ActorSend { .. } | ExprKind::Ask { .. } | |
1364 | | ExprKind::ActorQuery { .. } => { |
1365 | 0 | self.infer_other_actor_expr(expr) |
1366 | | } |
1367 | | |
1368 | | // Assignment expressions |
1369 | | ExprKind::Assign { .. } | ExprKind::CompoundAssign { .. } | |
1370 | | ExprKind::PreIncrement { .. } | ExprKind::PostIncrement { .. } | |
1371 | | ExprKind::PreDecrement { .. } | ExprKind::PostDecrement { .. } => { |
1372 | 0 | self.infer_other_assignment_expr(expr) |
1373 | | } |
1374 | | |
1375 | | // Remaining expressions |
1376 | 0 | _ => self.infer_remaining_expr(expr), |
1377 | | } |
1378 | 0 | } |
1379 | | |
1380 | | /// Extract control flow handling (complexity ~1) |
1381 | 0 | fn infer_other_control_flow_expr(&mut self, _expr: &Expr) -> Result<MonoType> { |
1382 | 0 | Ok(MonoType::Unit) // All control flow returns Unit |
1383 | 0 | } |
1384 | | |
1385 | | /// Extract definition handling (complexity ~1) |
1386 | 0 | fn infer_other_definition_expr(&mut self, _expr: &Expr) -> Result<MonoType> { |
1387 | 0 | Ok(MonoType::Unit) // All definitions return Unit |
1388 | 0 | } |
1389 | | |
1390 | | /// Extract literal/access handling (complexity ~8) |
1391 | 0 | fn infer_other_literal_access_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1392 | 0 | match &expr.kind { |
1393 | 0 | ExprKind::StructLiteral { name, .. } => Ok(MonoType::Named(name.clone())), |
1394 | 0 | ExprKind::ObjectLiteral { fields } => self.infer_object_literal(fields), |
1395 | 0 | ExprKind::FieldAccess { object, .. } => self.infer_field_access(object), |
1396 | 0 | ExprKind::IndexAccess { object, index } => self.infer_index_access(object, index), |
1397 | 0 | ExprKind::Slice { object, .. } => self.infer_slice(object), |
1398 | 0 | _ => bail!("Unexpected literal/access expression"), |
1399 | | } |
1400 | 0 | } |
1401 | | |
1402 | | /// Extract option handling (complexity ~5) |
1403 | 0 | fn infer_other_option_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1404 | 0 | match &expr.kind { |
1405 | 0 | ExprKind::Some { value } => { |
1406 | 0 | let inner_type = self.infer_expr(value)?; |
1407 | 0 | Ok(MonoType::Optional(Box::new(inner_type))) |
1408 | | } |
1409 | | ExprKind::None => { |
1410 | 0 | let type_var = MonoType::Var(self.gen.fresh()); |
1411 | 0 | Ok(MonoType::Optional(Box::new(type_var))) |
1412 | | } |
1413 | 0 | _ => bail!("Unexpected option expression"), |
1414 | | } |
1415 | 0 | } |
1416 | | |
1417 | | /// Extract async handling (complexity ~5) |
1418 | 0 | fn infer_other_async_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1419 | 0 | match &expr.kind { |
1420 | 0 | ExprKind::Await { expr } => self.infer_await(expr), |
1421 | 0 | ExprKind::AsyncBlock { body } => self.infer_async_block(body), |
1422 | 0 | ExprKind::Try { expr } => { |
1423 | 0 | let expr_type = self.infer(expr)?; |
1424 | 0 | Ok(expr_type) |
1425 | | } |
1426 | 0 | _ => bail!("Unexpected async expression"), |
1427 | | } |
1428 | 0 | } |
1429 | | |
1430 | | /// Extract actor handling (complexity ~6) |
1431 | 0 | fn infer_other_actor_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1432 | 0 | match &expr.kind { |
1433 | 0 | ExprKind::Send { actor, message } | ExprKind::ActorSend { actor, message } => { |
1434 | 0 | self.infer_send(actor, message) |
1435 | | } |
1436 | 0 | ExprKind::Ask { actor, message, timeout } => { |
1437 | 0 | self.infer_ask(actor, message, timeout.as_deref()) |
1438 | | } |
1439 | 0 | ExprKind::ActorQuery { actor, message } => self.infer_ask(actor, message, None), |
1440 | 0 | _ => bail!("Unexpected actor expression"), |
1441 | | } |
1442 | 0 | } |
1443 | | |
1444 | | /// Extract assignment handling (complexity ~6) |
1445 | 0 | fn infer_other_assignment_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1446 | 0 | match &expr.kind { |
1447 | 0 | ExprKind::Assign { target, value } => self.infer_assign(target, value), |
1448 | 0 | ExprKind::CompoundAssign { target, op, value } => { |
1449 | 0 | self.infer_compound_assign(target, *op, value) |
1450 | | } |
1451 | 0 | ExprKind::PreIncrement { target } | ExprKind::PostIncrement { target } | |
1452 | 0 | ExprKind::PreDecrement { target } | ExprKind::PostDecrement { target } => { |
1453 | 0 | self.infer_increment_decrement(target) |
1454 | | } |
1455 | 0 | _ => bail!("Unexpected assignment expression"), |
1456 | | } |
1457 | 0 | } |
1458 | | |
1459 | | /// Extract remaining expressions (complexity ~8) |
1460 | 0 | fn infer_remaining_expr(&mut self, expr: &Expr) -> Result<MonoType> { |
1461 | 0 | match &expr.kind { |
1462 | 0 | ExprKind::Let { name, value, body, is_mutable, .. } => { |
1463 | 0 | self.infer_let(name, value, body, *is_mutable) |
1464 | | } |
1465 | 0 | ExprKind::Block(exprs) => self.infer_block(exprs), |
1466 | 0 | ExprKind::Range { start, end, .. } => self.infer_range(start, end), |
1467 | 0 | ExprKind::Pipeline { expr, stages } => self.infer_pipeline(expr, stages), |
1468 | 0 | ExprKind::Module { body, .. } => self.infer_expr(body), |
1469 | 0 | ExprKind::DataFrame { columns } => self.infer_dataframe(columns), |
1470 | 0 | ExprKind::Command { .. } => Ok(MonoType::String), |
1471 | 0 | ExprKind::Macro { name, args } => self.infer_macro(name, args), |
1472 | 0 | ExprKind::DataFrameOperation { source, operation } => { |
1473 | 0 | self.infer_dataframe_operation(source, operation) |
1474 | | } |
1475 | 0 | _ => bail!("Unknown expression type in inference"), |
1476 | | } |
1477 | 0 | } |
1478 | | |
1479 | | /// Helper methods for complex expression groups |
1480 | 0 | fn infer_string_interpolation( |
1481 | 0 | &mut self, |
1482 | 0 | parts: &[crate::frontend::ast::StringPart], |
1483 | 0 | ) -> Result<MonoType> { |
1484 | 0 | for part in parts { |
1485 | 0 | if let crate::frontend::ast::StringPart::Expr(expr) = part { |
1486 | 0 | let _ = self.infer_expr(expr)?; |
1487 | 0 | } |
1488 | | } |
1489 | 0 | Ok(MonoType::Named("String".to_string())) |
1490 | 0 | } |
1491 | | |
1492 | 0 | fn infer_result_ok(&mut self, value: &Expr) -> Result<MonoType> { |
1493 | 0 | let value_type = self.infer_expr(value)?; |
1494 | 0 | let error_type = MonoType::Var(self.gen.fresh()); |
1495 | 0 | Ok(MonoType::Result(Box::new(value_type), Box::new(error_type))) |
1496 | 0 | } |
1497 | | |
1498 | 0 | fn infer_result_err(&mut self, error: &Expr) -> Result<MonoType> { |
1499 | 0 | let error_type = self.infer_expr(error)?; |
1500 | 0 | let value_type = MonoType::Var(self.gen.fresh()); |
1501 | 0 | Ok(MonoType::Result(Box::new(value_type), Box::new(error_type))) |
1502 | 0 | } |
1503 | | |
1504 | 0 | fn infer_object_literal( |
1505 | 0 | &mut self, |
1506 | 0 | fields: &[crate::frontend::ast::ObjectField], |
1507 | 0 | ) -> Result<MonoType> { |
1508 | 0 | for field in fields { |
1509 | 0 | match field { |
1510 | 0 | crate::frontend::ast::ObjectField::KeyValue { value, .. } => { |
1511 | 0 | let _ = self.infer_expr(value)?; |
1512 | | } |
1513 | 0 | crate::frontend::ast::ObjectField::Spread { expr } => { |
1514 | 0 | let _ = self.infer_expr(expr)?; |
1515 | | } |
1516 | | } |
1517 | | } |
1518 | 0 | Ok(MonoType::Named("Object".to_string())) |
1519 | 0 | } |
1520 | | |
1521 | 0 | fn infer_field_access(&mut self, object: &Expr) -> Result<MonoType> { |
1522 | 0 | let _object_ty = self.infer_expr(object)?; |
1523 | 0 | Ok(MonoType::Var(self.gen.fresh())) |
1524 | 0 | } |
1525 | | |
1526 | 0 | fn infer_index_access(&mut self, object: &Expr, index: &Expr) -> Result<MonoType> { |
1527 | 0 | let object_ty = self.infer_expr(object)?; |
1528 | 0 | let index_ty = self.infer_expr(index)?; |
1529 | | |
1530 | | // Check if the index is a range (which results in slicing) |
1531 | 0 | if let MonoType::List(inner_ty) = &index_ty { |
1532 | 0 | if matches!(**inner_ty, MonoType::Int) { |
1533 | | // This is a range (List of integers), so return the same collection type |
1534 | 0 | return Ok(object_ty); |
1535 | 0 | } |
1536 | 0 | } |
1537 | | |
1538 | | // Regular integer indexing - return the element type |
1539 | 0 | match object_ty { |
1540 | 0 | MonoType::List(element_ty) => { |
1541 | | // Ensure index is an integer |
1542 | 0 | self.unifier.unify(&index_ty, &MonoType::Int)?; |
1543 | 0 | Ok(*element_ty) |
1544 | | } |
1545 | | MonoType::String => { |
1546 | | // Ensure index is an integer |
1547 | 0 | self.unifier.unify(&index_ty, &MonoType::Int)?; |
1548 | 0 | Ok(MonoType::String) |
1549 | | } |
1550 | 0 | _ => Ok(MonoType::Var(self.gen.fresh())), |
1551 | | } |
1552 | 0 | } |
1553 | | |
1554 | 0 | fn infer_slice(&mut self, object: &Expr) -> Result<MonoType> { |
1555 | 0 | let object_ty = self.infer_expr(object)?; |
1556 | | // Slicing returns the same type as the original collection |
1557 | | // (a slice of a list is still a list, a slice of a string is still a string) |
1558 | 0 | Ok(object_ty) |
1559 | 0 | } |
1560 | | |
1561 | 0 | fn infer_send(&mut self, actor: &Expr, message: &Expr) -> Result<MonoType> { |
1562 | 0 | let _actor_ty = self.infer_expr(actor)?; |
1563 | 0 | let _message_ty = self.infer_expr(message)?; |
1564 | 0 | Ok(MonoType::Unit) |
1565 | 0 | } |
1566 | | |
1567 | 0 | fn infer_ask( |
1568 | 0 | &mut self, |
1569 | 0 | actor: &Expr, |
1570 | 0 | message: &Expr, |
1571 | 0 | timeout: Option<&Expr>, |
1572 | 0 | ) -> Result<MonoType> { |
1573 | 0 | let _actor_ty = self.infer_expr(actor)?; |
1574 | 0 | let _message_ty = self.infer_expr(message)?; |
1575 | 0 | if let Some(t) = timeout { |
1576 | 0 | let timeout_ty = self.infer_expr(t)?; |
1577 | 0 | self.unifier.unify(&timeout_ty, &MonoType::Int)?; |
1578 | 0 | } |
1579 | 0 | Ok(MonoType::Var(self.gen.fresh())) |
1580 | 0 | } |
1581 | | |
1582 | 0 | fn infer_dataframe( |
1583 | 0 | &mut self, |
1584 | 0 | columns: &[crate::frontend::ast::DataFrameColumn], |
1585 | 0 | ) -> Result<MonoType> { |
1586 | 0 | let mut column_types = Vec::new(); |
1587 | | |
1588 | 0 | for col in columns { |
1589 | | // Infer the type of the first value to determine column type |
1590 | 0 | let col_type = if col.values.is_empty() { |
1591 | 0 | MonoType::Var(self.gen.fresh()) |
1592 | | } else { |
1593 | 0 | let first_ty = self.infer_expr(&col.values[0])?; |
1594 | | // Verify all values in the column have the same type |
1595 | 0 | for value in &col.values[1..] { |
1596 | 0 | let value_ty = self.infer_expr(value)?; |
1597 | 0 | self.unifier.unify(&first_ty, &value_ty)?; |
1598 | | } |
1599 | 0 | first_ty |
1600 | | }; |
1601 | 0 | column_types.push((col.name.clone(), col_type)); |
1602 | | } |
1603 | | |
1604 | 0 | Ok(MonoType::DataFrame(column_types)) |
1605 | 0 | } |
1606 | | |
1607 | 0 | fn infer_dataframe_operation( |
1608 | 0 | &mut self, |
1609 | 0 | source: &Expr, |
1610 | 0 | operation: &crate::frontend::ast::DataFrameOp, |
1611 | 0 | ) -> Result<MonoType> { |
1612 | | use crate::frontend::ast::DataFrameOp; |
1613 | | |
1614 | 0 | let source_ty = self.infer_expr(source)?; |
1615 | | |
1616 | | // Ensure source is a DataFrame |
1617 | 0 | match &source_ty { |
1618 | 0 | MonoType::DataFrame(columns) => { |
1619 | 0 | match operation { |
1620 | | DataFrameOp::Filter(_) => { |
1621 | | // Filter preserves the DataFrame structure |
1622 | 0 | Ok(source_ty.clone()) |
1623 | | } |
1624 | 0 | DataFrameOp::Select(selected_cols) => { |
1625 | | // Select creates a new DataFrame with only the selected columns |
1626 | 0 | let mut new_columns = Vec::new(); |
1627 | 0 | for col_name in selected_cols { |
1628 | 0 | if let Some((_, ty)) = columns.iter().find(|(name, _)| name == col_name) |
1629 | 0 | { |
1630 | 0 | new_columns.push((col_name.clone(), ty.clone())); |
1631 | 0 | } |
1632 | | } |
1633 | 0 | Ok(MonoType::DataFrame(new_columns)) |
1634 | | } |
1635 | | DataFrameOp::GroupBy(_) => { |
1636 | | // GroupBy returns a grouped DataFrame (for now, same type) |
1637 | 0 | Ok(source_ty.clone()) |
1638 | | } |
1639 | | DataFrameOp::Aggregate(_) => { |
1640 | | // Aggregation returns a DataFrame with aggregated values |
1641 | 0 | Ok(source_ty.clone()) |
1642 | | } |
1643 | | DataFrameOp::Join { .. } => { |
1644 | | // Join returns a DataFrame (simplified for now) |
1645 | 0 | Ok(source_ty.clone()) |
1646 | | } |
1647 | | DataFrameOp::Sort { .. } => { |
1648 | | // Sort preserves the DataFrame structure |
1649 | 0 | Ok(source_ty.clone()) |
1650 | | } |
1651 | | DataFrameOp::Limit(_) | DataFrameOp::Head(_) | DataFrameOp::Tail(_) => { |
1652 | | // These operations preserve the DataFrame structure |
1653 | 0 | Ok(source_ty.clone()) |
1654 | | } |
1655 | | } |
1656 | | } |
1657 | 0 | MonoType::Named(name) if name == "DataFrame" => { |
1658 | | // Fallback for untyped DataFrames |
1659 | 0 | Ok(MonoType::Named("DataFrame".to_string())) |
1660 | | } |
1661 | 0 | _ => bail!("DataFrame operation on non-DataFrame type: {}", source_ty), |
1662 | | } |
1663 | 0 | } |
1664 | | |
1665 | 0 | fn infer_async_block(&mut self, body: &Expr) -> Result<MonoType> { |
1666 | | // Infer the body type |
1667 | 0 | let body_ty = self.infer_expr(body)?; |
1668 | | |
1669 | | // Async blocks return Future<Output = body_type> |
1670 | 0 | Ok(MonoType::Named(format!("Future<{body_ty}>"))) |
1671 | 0 | } |
1672 | | } |
1673 | | |
1674 | | impl Default for InferenceContext { |
1675 | 0 | fn default() -> Self { |
1676 | 0 | Self::new() |
1677 | 0 | } |
1678 | | } |
1679 | | |
1680 | | #[cfg(test)] |
1681 | | #[allow(clippy::unwrap_used)] |
1682 | | #[allow(clippy::panic)] |
1683 | | mod tests { |
1684 | | use super::*; |
1685 | | use crate::frontend::parser::Parser; |
1686 | | |
1687 | | fn infer_str(input: &str) -> Result<MonoType> { |
1688 | | let mut parser = Parser::new(input); |
1689 | | let expr = parser.parse()?; |
1690 | | let mut ctx = InferenceContext::new(); |
1691 | | ctx.infer(&expr) |
1692 | | } |
1693 | | |
1694 | | #[test] |
1695 | | fn test_infer_literals() { |
1696 | | assert_eq!(infer_str("42").unwrap(), MonoType::Int); |
1697 | | assert_eq!(infer_str("3.14").unwrap(), MonoType::Float); |
1698 | | assert_eq!(infer_str("true").unwrap(), MonoType::Bool); |
1699 | | assert_eq!(infer_str("\"hello\"").unwrap(), MonoType::String); |
1700 | | } |
1701 | | |
1702 | | #[test] |
1703 | | fn test_infer_arithmetic() { |
1704 | | assert_eq!(infer_str("1 + 2").unwrap(), MonoType::Int); |
1705 | | assert_eq!(infer_str("3 * 4").unwrap(), MonoType::Int); |
1706 | | assert_eq!(infer_str("5 - 2").unwrap(), MonoType::Int); |
1707 | | } |
1708 | | |
1709 | | #[test] |
1710 | | fn test_infer_comparison() { |
1711 | | assert_eq!(infer_str("1 < 2").unwrap(), MonoType::Bool); |
1712 | | assert_eq!(infer_str("3 == 3").unwrap(), MonoType::Bool); |
1713 | | assert_eq!(infer_str("true != false").unwrap(), MonoType::Bool); |
1714 | | } |
1715 | | |
1716 | | #[test] |
1717 | | fn test_infer_if() { |
1718 | | assert_eq!( |
1719 | | infer_str("if true { 1 } else { 2 }").unwrap(), |
1720 | | MonoType::Int |
1721 | | ); |
1722 | | assert_eq!( |
1723 | | infer_str("if false { \"yes\" } else { \"no\" }").unwrap(), |
1724 | | MonoType::String |
1725 | | ); |
1726 | | } |
1727 | | |
1728 | | #[test] |
1729 | | fn test_infer_let() { |
1730 | | assert_eq!(infer_str("let x = 42 in x + 1").unwrap(), MonoType::Int); |
1731 | | assert_eq!( |
1732 | | infer_str("let f = 3.14 in let g = 2.71 in f").unwrap(), |
1733 | | MonoType::Float |
1734 | | ); |
1735 | | } |
1736 | | |
1737 | | #[test] |
1738 | | fn test_infer_list() { |
1739 | | assert_eq!( |
1740 | | infer_str("[1, 2, 3]").unwrap(), |
1741 | | MonoType::List(Box::new(MonoType::Int)) |
1742 | | ); |
1743 | | assert_eq!( |
1744 | | infer_str("[true, false]").unwrap(), |
1745 | | MonoType::List(Box::new(MonoType::Bool)) |
1746 | | ); |
1747 | | } |
1748 | | |
1749 | | #[test] |
1750 | | #[ignore = "DataFrame syntax changed - needs update"] |
1751 | | fn test_infer_dataframe() { |
1752 | | let df_str = r#"DataFrame::new() |
1753 | | .column("age", [25, 30, 35]) |
1754 | | .column("name", ["Alice", "Bob", "Charlie"]) |
1755 | | .build()"#; |
1756 | | |
1757 | | let result = infer_str(df_str).unwrap_or(MonoType::DataFrame(vec![])); |
1758 | | match result { |
1759 | | MonoType::DataFrame(columns) => { |
1760 | | assert_eq!(columns.len(), 2); |
1761 | | assert_eq!(columns[0].0, "age"); |
1762 | | assert!(matches!(columns[0].1, MonoType::Int)); |
1763 | | assert_eq!(columns[1].0, "name"); |
1764 | | assert!(matches!(columns[1].1, MonoType::String)); |
1765 | | } |
1766 | | _ => panic!("Expected DataFrame type, got {result:?}"), |
1767 | | } |
1768 | | } |
1769 | | |
1770 | | #[test] |
1771 | | #[ignore = "DataFrame syntax changed - needs update"] |
1772 | | fn test_infer_dataframe_operations() { |
1773 | | // Test filter operation with simpler pattern |
1774 | | let filter_str = r"let df = DataFrame::new(); df.filter(|x| x > 25)"; |
1775 | | let result = infer_str(filter_str).unwrap_or(MonoType::DataFrame(vec![])); |
1776 | | assert!(matches!(result, MonoType::DataFrame(_))); |
1777 | | |
1778 | | // Test select operation |
1779 | | let select_str = r#"let df = DataFrame::new(); df.select(["age"])"#; |
1780 | | let result = infer_str(select_str).unwrap_or(MonoType::DataFrame(vec![])); |
1781 | | match result { |
1782 | | MonoType::DataFrame(columns) => { |
1783 | | assert_eq!(columns.len(), 1); |
1784 | | assert_eq!(columns[0].0, "age"); |
1785 | | } |
1786 | | _ => panic!("Expected DataFrame type, got {result:?}"), |
1787 | | } |
1788 | | } |
1789 | | |
1790 | | #[test] |
1791 | | #[ignore = "DataFrame syntax changed - needs update"] |
1792 | | fn test_infer_series() { |
1793 | | // Test column selection returns Series |
1794 | | let col_str = r#"let df = DataFrame::new(); df.col("age")"#; |
1795 | | let result = infer_str(col_str).unwrap_or(MonoType::DataFrame(vec![])); |
1796 | | assert!(matches!(result, MonoType::Series(_)) || matches!(result, MonoType::DataFrame(_))); |
1797 | | |
1798 | | // Test aggregation on Series |
1799 | | let mean_str = r#"let df = DataFrame::new(); df.col("age").mean()"#; |
1800 | | let result = infer_str(mean_str).unwrap_or(MonoType::Float); |
1801 | | assert_eq!(result, MonoType::Float); |
1802 | | } |
1803 | | |
1804 | | #[test] |
1805 | | fn test_infer_function() { |
1806 | | let result = infer_str("fun add(x: i32, y: i32) -> i32 { x + y }").unwrap(); |
1807 | | match result { |
1808 | | MonoType::Function(first_arg, remaining) => { |
1809 | | assert!(matches!(first_arg.as_ref(), MonoType::Int)); |
1810 | | match remaining.as_ref() { |
1811 | | MonoType::Function(second_arg, return_type) => { |
1812 | | assert!(matches!(second_arg.as_ref(), MonoType::Int)); |
1813 | | assert!(matches!(return_type.as_ref(), MonoType::Int)); |
1814 | | } |
1815 | | _ => panic!("Expected function type"), |
1816 | | } |
1817 | | } |
1818 | | _ => panic!("Expected function type"), |
1819 | | } |
1820 | | } |
1821 | | |
1822 | | #[test] |
1823 | | fn test_type_errors() { |
1824 | | assert!(infer_str("1 + true").is_err()); |
1825 | | assert!(infer_str("if 42 { 1 } else { 2 }").is_err()); |
1826 | | assert!(infer_str("[1, true, 3]").is_err()); |
1827 | | } |
1828 | | |
1829 | | #[test] |
1830 | | fn test_infer_lambda() { |
1831 | | // Simple lambda: |x| x + 1 |
1832 | | let result = infer_str("|x| x + 1").unwrap(); |
1833 | | match result { |
1834 | | MonoType::Function(arg, ret) => { |
1835 | | assert!(matches!(arg.as_ref(), MonoType::Int)); |
1836 | | assert!(matches!(ret.as_ref(), MonoType::Int)); |
1837 | | } |
1838 | | _ => panic!("Expected function type for lambda"), |
1839 | | } |
1840 | | |
1841 | | // Lambda with multiple params: |x, y| x * y |
1842 | | let result = infer_str("|x, y| x * y").unwrap(); |
1843 | | match result { |
1844 | | MonoType::Function(first_arg, remaining) => { |
1845 | | assert!(matches!(first_arg.as_ref(), MonoType::Int)); |
1846 | | match remaining.as_ref() { |
1847 | | MonoType::Function(second_arg, return_type) => { |
1848 | | assert!(matches!(second_arg.as_ref(), MonoType::Int)); |
1849 | | assert!(matches!(return_type.as_ref(), MonoType::Int)); |
1850 | | } |
1851 | | _ => panic!("Expected function type"), |
1852 | | } |
1853 | | } |
1854 | | _ => panic!("Expected function type for lambda"), |
1855 | | } |
1856 | | |
1857 | | // Lambda with no params: || 42 |
1858 | | let result = infer_str("|| 42").unwrap(); |
1859 | | assert_eq!(result, MonoType::Int); |
1860 | | |
1861 | | // Lambda used in let binding |
1862 | | let result = infer_str("let f = |x| x + 1 in f(5)").unwrap(); |
1863 | | assert_eq!(result, MonoType::Int); |
1864 | | } |
1865 | | |
1866 | | #[test] |
1867 | | fn test_self_hosting_patterns() { |
1868 | | // Test fat arrow lambda syntax inference |
1869 | | let result = infer_str("x => x * 2").unwrap(); |
1870 | | match result { |
1871 | | MonoType::Function(arg, ret) => { |
1872 | | assert!(matches!(arg.as_ref(), MonoType::Int)); |
1873 | | assert!(matches!(ret.as_ref(), MonoType::Int)); |
1874 | | } |
1875 | | _ => panic!("Expected function type for fat arrow lambda"), |
1876 | | } |
1877 | | |
1878 | | // Test higher-order function patterns (compiler combinators) |
1879 | | let result = infer_str("let map = |f, xs| xs in let double = |x| x * 2 in map(double, [1, 2, 3])").unwrap(); |
1880 | | assert!(matches!(result, MonoType::List(_))); |
1881 | | |
1882 | | // Test recursive function inference (needed for recursive descent parser) |
1883 | | let result = infer_str("fun factorial(n: i32) -> i32 { if n <= 1 { 1 } else { n * factorial(n - 1) } }").unwrap(); |
1884 | | match result { |
1885 | | MonoType::Function(arg, ret) => { |
1886 | | assert!(matches!(arg.as_ref(), MonoType::Int)); |
1887 | | assert!(matches!(ret.as_ref(), MonoType::Int)); |
1888 | | } |
1889 | | _ => panic!("Expected function type for recursive function"), |
1890 | | } |
1891 | | } |
1892 | | |
1893 | | #[test] |
1894 | | fn test_compiler_data_structures() { |
1895 | | // Test struct type inference for compiler data structures |
1896 | | let result = infer_str("struct Token { kind: String, value: String }").unwrap(); |
1897 | | assert_eq!(result, MonoType::Unit); |
1898 | | |
1899 | | // Test enum for AST nodes |
1900 | | let result = infer_str("enum Expr { Literal, Binary, Function }").unwrap(); |
1901 | | assert_eq!(result, MonoType::Unit); |
1902 | | |
1903 | | // Test Vec operations for token streams - basic list inference |
1904 | | let result = infer_str("[1, 2, 3]").unwrap(); |
1905 | | assert!(matches!(result, MonoType::List(_))); |
1906 | | |
1907 | | // Test list length method |
1908 | | let result = infer_str("[1, 2, 3].len()").unwrap(); |
1909 | | assert_eq!(result, MonoType::Int); |
1910 | | } |
1911 | | |
1912 | | #[test] |
1913 | | fn test_constraint_solving() { |
1914 | | // Test basic list operations |
1915 | | let result = infer_str("[1, 2, 3].len()").unwrap(); |
1916 | | assert_eq!(result, MonoType::Int); |
1917 | | |
1918 | | // Test polymorphic function inference |
1919 | | let result = infer_str("let id = |x| x in let n = id(42) in let s = id(\"hello\") in n").unwrap(); |
1920 | | assert_eq!(result, MonoType::Int); |
1921 | | |
1922 | | // Test simple constraint solving |
1923 | | let result = infer_str("let f = |x| x + 1 in f").unwrap(); |
1924 | | assert!(matches!(result, MonoType::Function(_, _))); |
1925 | | |
1926 | | // Test function composition |
1927 | | let result = infer_str("let compose = |f, g, x| f(g(x)) in compose").unwrap(); |
1928 | | assert!(matches!(result, MonoType::Function(_, _))); |
1929 | | } |
1930 | | } |