1use super::*;
2impl TypeChecker {
3 pub fn check_literal(&self, lit: &Literal) -> Result<Type> {
4 let span = Self::dummy_span();
5 Ok(match lit {
6 Literal::Integer(_) => Type::new(TypeKind::Int, span),
7 Literal::Float(_) => Type::new(TypeKind::Float, span),
8 Literal::String(_) => Type::new(TypeKind::String, span),
9 Literal::Bool(_) => Type::new(TypeKind::Bool, span),
10 })
11 }
12
13 pub fn check_binary_expr(&mut self, left: &Expr, op: &BinaryOp, right: &Expr) -> Result<Type> {
14 let span = Self::dummy_span();
15 if matches!(op, BinaryOp::And) {
16 let mut pattern_bindings = Vec::new();
17 pattern_bindings.extend(self.extract_all_pattern_bindings_from_expr(left));
18 pattern_bindings.extend(self.extract_all_pattern_bindings_from_expr(right));
19 if !pattern_bindings.is_empty() {
20 let left_type = self.check_expr(left)?;
21 self.unify(&Type::new(TypeKind::Bool, span), &left_type)?;
22 self.env.push_scope();
23 for (scrutinee, pattern) in pattern_bindings {
24 if let Ok(scrutinee_type) = self.check_expr(scrutinee) {
25 let _ = self.bind_pattern(&pattern, &scrutinee_type);
26 }
27 }
28
29 let right_narrowings = self.extract_type_narrowings_from_expr(right);
30 for (var_name, narrowed_type) in right_narrowings {
31 self.env.refine_variable_type(var_name, narrowed_type);
32 }
33
34 let right_type = self.check_expr(right)?;
35 self.unify(&Type::new(TypeKind::Bool, span), &right_type)?;
36 self.env.pop_scope();
37 return Ok(Type::new(TypeKind::Bool, span));
38 }
39 }
40
41 let left_type = self.check_expr(left)?;
42 let right_type = self.check_expr(right)?;
43 match op {
44 BinaryOp::Add
45 | BinaryOp::Sub
46 | BinaryOp::Mul
47 | BinaryOp::Div
48 | BinaryOp::Mod
49 | BinaryOp::Pow => {
50 if matches!(left_type.kind, TypeKind::Int | TypeKind::Float)
51 && matches!(right_type.kind, TypeKind::Int | TypeKind::Float)
52 {
53 if matches!(left_type.kind, TypeKind::Float)
54 || matches!(right_type.kind, TypeKind::Float)
55 {
56 Ok(Type::new(TypeKind::Float, span))
57 } else {
58 Ok(Type::new(TypeKind::Int, span))
59 }
60 } else {
61 Err(self.type_error_at(
62 format!(
63 "Arithmetic operator {} requires numeric types, got '{}' and '{}'",
64 op, left_type, right_type
65 ),
66 left.span,
67 ))
68 }
69 }
70
71 BinaryOp::Eq
72 | BinaryOp::Ne
73 | BinaryOp::Lt
74 | BinaryOp::Le
75 | BinaryOp::Gt
76 | BinaryOp::Ge => {
77 if matches!(left_type.kind, TypeKind::Unknown)
78 || matches!(right_type.kind, TypeKind::Unknown)
79 {
80 return Ok(Type::new(TypeKind::Bool, span));
81 }
82
83 if !self.types_equal(&left_type, &right_type) {
84 return Err(self.type_error(format!(
85 "Comparison requires compatible types, got '{}' and '{}'",
86 left_type, right_type
87 )));
88 }
89
90 Ok(Type::new(TypeKind::Bool, span))
91 }
92
93 BinaryOp::And | BinaryOp::Or => {
94 self.unify(&Type::new(TypeKind::Bool, span), &left_type)?;
95 self.unify(&Type::new(TypeKind::Bool, span), &right_type)?;
96 Ok(Type::new(TypeKind::Bool, span))
97 }
98
99 BinaryOp::Concat => {
100 if !self.env.type_implements_trait(&left_type, "ToString") {
101 return Err(self.type_error_at(
102 format!(
103 "Left operand of `..` must implement ToString trait, got '{}'",
104 left_type
105 ),
106 left.span,
107 ));
108 }
109
110 if !self.env.type_implements_trait(&right_type, "ToString") {
111 return Err(self.type_error_at(
112 format!(
113 "Right operand of `..` must implement ToString trait, got '{}'",
114 right_type
115 ),
116 right.span,
117 ));
118 }
119
120 Ok(Type::new(TypeKind::String, span))
121 }
122
123 BinaryOp::Range => {
124 return Err(self.type_error(
125 "Range operator is not supported; use numeric for-loops".to_string(),
126 ));
127 }
128 }
129 }
130
131 pub fn check_unary_expr(&mut self, op: &UnaryOp, operand: &Expr) -> Result<Type> {
132 let operand_type = self.check_expr(operand)?;
133 let span = Self::dummy_span();
134 match op {
135 UnaryOp::Neg => {
136 if matches!(operand_type.kind, TypeKind::Int | TypeKind::Float) {
137 Ok(operand_type)
138 } else {
139 Err(self.type_error(format!(
140 "Negation requires numeric type, got '{}'",
141 operand_type
142 )))
143 }
144 }
145
146 UnaryOp::Not => {
147 self.unify(&Type::new(TypeKind::Bool, span), &operand_type)?;
148 Ok(Type::new(TypeKind::Bool, span))
149 }
150 }
151 }
152
153 pub fn check_call_expr(&mut self, span: Span, callee: &Expr, args: &[Expr]) -> Result<Type> {
154 if let ExprKind::FieldAccess { object, field } = &callee.kind {
155 if let ExprKind::Identifier(type_name) = &object.kind {
156 let mut candidate_names: Vec<String> = Vec::new();
157 if let Some(real_mod) = self.resolve_module_alias(type_name) {
158 candidate_names.push(format!("{}.{}", real_mod, field));
159 }
160
161 candidate_names.push(format!("{}.{}", type_name, field));
162 let resolved_type = self.resolve_type_key(type_name);
163 if resolved_type != *type_name {
164 candidate_names.push(format!("{}.{}", resolved_type, field));
165 }
166
167 let mut static_candidate: Option<(String, type_env::FunctionSignature)> = None;
168 for name in candidate_names {
169 if let Some(sig) = self.env.lookup_function(&name) {
170 static_candidate = Some((name, sig.clone()));
171 break;
172 }
173 }
174
175 if let Some((resolved_name, sig)) = static_candidate {
176 if args.len() != sig.params.len() {
177 return Err(self.type_error_at(
178 format!(
179 "Static method '{}' expects {} arguments, got {}",
180 resolved_name,
181 sig.params.len(),
182 args.len()
183 ),
184 span,
185 ));
186 }
187
188 for (i, (arg, expected_type)) in args.iter().zip(sig.params.iter()).enumerate()
189 {
190 let arg_type = self.check_expr(arg)?;
191 self.unify(expected_type, &arg_type).map_err(|_| {
192 self.type_error_at(
193 format!(
194 "Argument {} to static method '{}': expected '{}', got '{}'",
195 i + 1,
196 resolved_name,
197 expected_type,
198 arg_type
199 ),
200 arg.span,
201 )
202 })?;
203 }
204
205 return Ok(sig.return_type);
206 }
207
208 let enum_lookup = {
209 let key = self.resolve_type_key(type_name);
210 self.env
211 .lookup_enum(&key)
212 .or_else(|| self.env.lookup_enum(type_name))
213 };
214 if let Some(enum_def) = enum_lookup {
215 let enum_def = enum_def.clone();
216 let variant = field;
217 let variant_def = enum_def
218 .variants
219 .iter()
220 .find(|v| &v.name == variant)
221 .ok_or_else(|| {
222 self.type_error_at(
223 format!("Enum '{}' has no variant '{}'", type_name, variant),
224 span,
225 )
226 })?;
227 if let Some(expected_fields) = &variant_def.fields {
228 if args.len() != expected_fields.len() {
229 return Err(self.type_error_at(
230 format!(
231 "Variant '{}::{}' expects {} arguments, got {}",
232 type_name,
233 variant,
234 expected_fields.len(),
235 args.len()
236 ),
237 span,
238 ));
239 }
240
241 let mut type_params = std::collections::HashMap::new();
242 for (arg, expected_type) in args.iter().zip(expected_fields.iter()) {
243 let arg_type = self.check_expr(arg)?;
244 if let TypeKind::Generic(type_param) = &expected_type.kind {
245 type_params.insert(type_param.clone(), arg_type.clone());
246 } else {
247 self.unify(expected_type, &arg_type)?;
248 }
249 }
250
251 if !type_params.is_empty() {
252 self.pending_generic_instances = Some(type_params.clone());
253 }
254
255 if type_name == "Option" {
256 if let Some(inner_type) = type_params.get("T") {
257 return Ok(Type::new(
258 TypeKind::Option(Box::new(inner_type.clone())),
259 Self::dummy_span(),
260 ));
261 }
262 } else if type_name == "Result" {
263 if let (Some(ok_type), Some(err_type)) =
264 (type_params.get("T"), type_params.get("E"))
265 {
266 return Ok(Type::new(
267 TypeKind::Result(
268 Box::new(ok_type.clone()),
269 Box::new(err_type.clone()),
270 ),
271 Self::dummy_span(),
272 ));
273 }
274 }
275
276 let enum_type_name = {
277 let key = self.resolve_type_key(type_name);
278 if self.env.lookup_enum(&key).is_some() {
279 key
280 } else {
281 type_name.clone()
282 }
283 };
284 return Ok(Type::new(
285 TypeKind::Named(enum_type_name),
286 Self::dummy_span(),
287 ));
288 } else {
289 if !args.is_empty() {
290 return Err(self.type_error(format!(
291 "Variant '{}::{}' is a unit variant and takes no arguments",
292 type_name, variant
293 )));
294 }
295
296 let enum_type_name = {
297 let key = self.resolve_type_key(type_name);
298 if self.env.lookup_enum(&key).is_some() {
299 key
300 } else {
301 type_name.clone()
302 }
303 };
304 return Ok(Type::new(
305 TypeKind::Named(enum_type_name),
306 Self::dummy_span(),
307 ));
308 }
309 }
310 }
311 }
312
313 if let ExprKind::Identifier(name) = &callee.kind {
314 if let Some(var_type) = self.env.lookup_variable(name) {
315 if let TypeKind::Function {
316 params: param_types,
317 return_type,
318 } = &var_type.kind
319 {
320 if args.len() != param_types.len() {
321 return Err(self.type_error_at(
322 format!(
323 "Lambda '{}' expects {} arguments, got {}",
324 name,
325 param_types.len(),
326 args.len()
327 ),
328 span,
329 ));
330 }
331
332 for (i, (arg, expected_type)) in args.iter().zip(param_types.iter()).enumerate()
333 {
334 let arg_type = self.check_expr(arg)?;
335 self.unify(expected_type, &arg_type).map_err(|_| {
336 self.type_error_at(
337 format!(
338 "Argument {} to lambda '{}': expected '{}', got '{}'",
339 i + 1,
340 name,
341 expected_type,
342 arg_type
343 ),
344 arg.span,
345 )
346 })?;
347 }
348
349 return Ok((**return_type).clone());
350 }
351 }
352
353 let resolved = self.resolve_function_key(name);
354 let sig = self
355 .env
356 .lookup_function(&resolved)
357 .ok_or_else(|| {
358 self.type_error_at(format!("Undefined function '{}'", name), callee.span)
359 })?
360 .clone();
361 if args.len() != sig.params.len() {
362 return Err(self.type_error_at(
363 format!(
364 "Function '{}' expects {} arguments, got {}",
365 name,
366 sig.params.len(),
367 args.len()
368 ),
369 callee.span,
370 ));
371 }
372
373 for (i, (arg, expected_type)) in args.iter().zip(sig.params.iter()).enumerate() {
374 let arg_type = self.check_expr(arg)?;
375 self.unify_with_bounds(expected_type, &arg_type)
376 .map_err(|_| {
377 self.type_error_at(
378 format!(
379 "Argument {} to function '{}': expected '{}', got '{}'",
380 i + 1,
381 name,
382 expected_type,
383 arg_type
384 ),
385 arg.span,
386 )
387 })?;
388 }
389
390 Ok(sig.return_type)
391 } else {
392 Err(self.type_error_at(
393 "Only direct function/lambda calls are supported".to_string(),
394 span,
395 ))
396 }
397 }
398
399 pub fn check_method_call(
400 &mut self,
401 receiver: &Expr,
402 method: &str,
403 args: &[Expr],
404 ) -> Result<Type> {
405 let receiver_type = self.check_expr(receiver)?;
406 let span = Self::dummy_span();
407 match &receiver_type.kind {
408 TypeKind::String => match method {
409 "len" => {
410 if !args.is_empty() {
411 return Err(self.type_error("len() takes no arguments".to_string()));
412 }
413
414 return Ok(Type::new(TypeKind::Int, span));
415 }
416
417 "substring" => {
418 if args.len() != 2 {
419 return Err(self.type_error("substring() requires 2 arguments".to_string()));
420 }
421
422 self.check_expr(&args[0])?;
423 self.check_expr(&args[1])?;
424 return Ok(Type::new(TypeKind::String, span));
425 }
426
427 "find" => {
428 if args.len() != 1 {
429 return Err(self.type_error("find() requires 1 argument".to_string()));
430 }
431
432 self.check_expr(&args[0])?;
433 return Ok(Type::new(TypeKind::Named("Option".to_string()), span));
434 }
435
436 "starts_with" | "ends_with" | "contains" => {
437 if args.len() != 1 {
438 return Err(self.type_error(format!("{}() requires 1 argument", method)));
439 }
440
441 self.check_expr(&args[0])?;
442 return Ok(Type::new(TypeKind::Bool, span));
443 }
444
445 "split" => {
446 if args.len() != 1 {
447 return Err(self.type_error("split() requires 1 argument".to_string()));
448 }
449
450 self.check_expr(&args[0])?;
451 return Ok(Type::new(
452 TypeKind::Array(Box::new(Type::new(TypeKind::String, span))),
453 span,
454 ));
455 }
456
457 "trim" | "trim_start" | "trim_end" | "to_upper" | "to_lower" => {
458 if !args.is_empty() {
459 return Err(self.type_error(format!("{}() takes no arguments", method)));
460 }
461
462 return Ok(Type::new(TypeKind::String, span));
463 }
464
465 "replace" => {
466 if args.len() != 2 {
467 return Err(self.type_error("replace() requires 2 arguments".to_string()));
468 }
469
470 self.check_expr(&args[0])?;
471 self.check_expr(&args[1])?;
472 return Ok(Type::new(TypeKind::String, span));
473 }
474
475 "is_empty" => {
476 if !args.is_empty() {
477 return Err(self.type_error("is_empty() takes no arguments".to_string()));
478 }
479
480 return Ok(Type::new(TypeKind::Bool, span));
481 }
482
483 "chars" | "lines" => {
484 if !args.is_empty() {
485 return Err(self.type_error(format!("{}() takes no arguments", method)));
486 }
487
488 return Ok(Type::new(
489 TypeKind::Array(Box::new(Type::new(TypeKind::String, span))),
490 span,
491 ));
492 }
493
494 _ => {}
495 },
496 TypeKind::Array(elem_type) => match method {
497 "len" => {
498 if !args.is_empty() {
499 return Err(self.type_error("len() takes no arguments".to_string()));
500 }
501
502 return Ok(Type::new(TypeKind::Int, span));
503 }
504
505 "get" => {
506 if args.len() != 1 {
507 return Err(self.type_error("get() requires 1 argument".to_string()));
508 }
509
510 self.check_expr(&args[0])?;
511 return Ok(Type::new(TypeKind::Option(elem_type.clone()), span));
512 }
513
514 "first" | "last" => {
515 if !args.is_empty() {
516 return Err(self.type_error(format!("{}() takes no arguments", method)));
517 }
518
519 return Ok(Type::new(TypeKind::Option(elem_type.clone()), span));
520 }
521
522 "push" => {
523 if args.len() != 1 {
524 return Err(self.type_error("push() requires 1 argument".to_string()));
525 }
526
527 self.check_expr(&args[0])?;
528 return Ok(Type::new(TypeKind::Unit, span));
529 }
530
531 "pop" => {
532 if !args.is_empty() {
533 return Err(self.type_error("pop() takes no arguments".to_string()));
534 }
535
536 return Ok(Type::new(TypeKind::Option(elem_type.clone()), span));
537 }
538
539 "slice" => {
540 if args.len() != 2 {
541 return Err(self.type_error("slice() requires 2 arguments".to_string()));
542 }
543
544 self.check_expr(&args[0])?;
545 self.check_expr(&args[1])?;
546 return Ok(Type::new(TypeKind::Array(elem_type.clone()), span));
547 }
548
549 "clear" => {
550 if !args.is_empty() {
551 return Err(self.type_error("clear() takes no arguments".to_string()));
552 }
553
554 return Ok(Type::new(TypeKind::Unit, span));
555 }
556
557 "is_empty" => {
558 if !args.is_empty() {
559 return Err(self.type_error("is_empty() takes no arguments".to_string()));
560 }
561
562 return Ok(Type::new(TypeKind::Bool, span));
563 }
564
565 "map" => {
566 if args.len() != 1 {
567 return Err(
568 self.type_error("map() requires 1 argument (function)".to_string())
569 );
570 }
571
572 self.expected_lambda_signature = Some((vec![(**elem_type).clone()], None));
573 let func_type = self.check_expr(&args[0])?;
574 match &func_type.kind {
575 TypeKind::Function {
576 params: _,
577 return_type,
578 } => {
579 return Ok(Type::new(TypeKind::Array(return_type.clone()), span));
580 }
581
582 _ => {
583 return Err(
584 self.type_error("map() requires a function argument".to_string())
585 );
586 }
587 }
588 }
589
590 "filter" => {
591 if args.len() != 1 {
592 return Err(
593 self.type_error("filter() requires 1 argument (function)".to_string())
594 );
595 }
596
597 self.expected_lambda_signature = Some((
598 vec![(**elem_type).clone()],
599 Some(Type::new(TypeKind::Bool, span)),
600 ));
601 let func_type = self.check_expr(&args[0])?;
602 match &func_type.kind {
603 TypeKind::Function {
604 params: _,
605 return_type,
606 } => {
607 self.unify(&Type::new(TypeKind::Bool, span), return_type)?;
608 return Ok(Type::new(TypeKind::Array(elem_type.clone()), span));
609 }
610
611 _ => {
612 return Err(self
613 .type_error("filter() requires a function argument".to_string()));
614 }
615 }
616 }
617
618 "reduce" => {
619 if args.len() != 2 {
620 return Err(self.type_error(
621 "reduce() requires 2 arguments (initial value and function)"
622 .to_string(),
623 ));
624 }
625
626 let init_type = self.check_expr(&args[0])?;
627 self.expected_lambda_signature = Some((
628 vec![init_type.clone(), (**elem_type).clone()],
629 Some(init_type.clone()),
630 ));
631 let func_type = self.check_expr(&args[1])?;
632 match &func_type.kind {
633 TypeKind::Function {
634 params: _,
635 return_type,
636 } => {
637 self.unify(&init_type, return_type)?;
638 return Ok(init_type);
639 }
640
641 _ => {
642 return Err(self.type_error(
643 "reduce() requires a function as second argument".to_string(),
644 ));
645 }
646 }
647 }
648
649 _ => {}
650 },
651 TypeKind::Map(key_type, value_type) => match method {
652 "iter" => {
653 if !args.is_empty() {
654 return Err(self.type_error("iter() takes no arguments".to_string()));
655 }
656
657 return Ok(Type::new(TypeKind::Named("Iterator".to_string()), span));
658 }
659
660 "len" => {
661 if !args.is_empty() {
662 return Err(self.type_error("len() takes no arguments".to_string()));
663 }
664
665 return Ok(Type::new(TypeKind::Int, span));
666 }
667
668 "get" => {
669 if args.len() != 1 {
670 return Err(self.type_error("get() requires 1 argument (key)".to_string()));
671 }
672
673 let arg_type = self.check_expr(&args[0])?;
674 self.unify(key_type, &arg_type)?;
675 return Ok(Type::new(TypeKind::Option(value_type.clone()), span));
676 }
677
678 "set" => {
679 if args.len() != 2 {
680 return Err(
681 self.type_error("set() requires 2 arguments (key, value)".to_string())
682 );
683 }
684
685 let key_arg_type = self.check_expr(&args[0])?;
686 let value_arg_type = self.check_expr(&args[1])?;
687 self.unify(key_type, &key_arg_type)?;
688 self.unify(value_type, &value_arg_type)?;
689 return Ok(Type::new(TypeKind::Unit, span));
690 }
691
692 "has" => {
693 if args.len() != 1 {
694 return Err(self.type_error("has() requires 1 argument (key)".to_string()));
695 }
696
697 let arg_type = self.check_expr(&args[0])?;
698 self.unify(key_type, &arg_type)?;
699 return Ok(Type::new(TypeKind::Bool, span));
700 }
701
702 "delete" => {
703 if args.len() != 1 {
704 return Err(
705 self.type_error("delete() requires 1 argument (key)".to_string())
706 );
707 }
708
709 let arg_type = self.check_expr(&args[0])?;
710 self.unify(key_type, &arg_type)?;
711 return Ok(Type::new(TypeKind::Option(value_type.clone()), span));
712 }
713
714 "keys" => {
715 if !args.is_empty() {
716 return Err(self.type_error("keys() takes no arguments".to_string()));
717 }
718
719 return Ok(Type::new(TypeKind::Array(key_type.clone()), span));
720 }
721
722 "values" => {
723 if !args.is_empty() {
724 return Err(self.type_error("values() takes no arguments".to_string()));
725 }
726
727 return Ok(Type::new(TypeKind::Array(value_type.clone()), span));
728 }
729
730 _ => {}
731 },
732 TypeKind::Table => match method {
733 "iter" => {
734 if !args.is_empty() {
735 return Err(self.type_error("iter() takes no arguments".to_string()));
736 }
737
738 return Ok(Type::new(TypeKind::Named("Iterator".to_string()), span));
739 }
740
741 "len" => {
742 if !args.is_empty() {
743 return Err(self.type_error("len() takes no arguments".to_string()));
744 }
745
746 return Ok(Type::new(TypeKind::Int, span));
747 }
748
749 "get" => {
750 if args.len() != 1 {
751 return Err(self.type_error("get() requires 1 argument (key)".to_string()));
752 }
753
754 self.check_expr(&args[0])?;
755 return Ok(Type::new(
756 TypeKind::Option(Box::new(Type::new(TypeKind::Unknown, span))),
757 span,
758 ));
759 }
760
761 "set" => {
762 if args.len() != 2 {
763 return Err(
764 self.type_error("set() requires 2 arguments (key, value)".to_string())
765 );
766 }
767
768 self.check_expr(&args[0])?;
769 self.check_expr(&args[1])?;
770 return Ok(Type::new(TypeKind::Unit, span));
771 }
772
773 "has" => {
774 if args.len() != 1 {
775 return Err(self.type_error("has() requires 1 argument (key)".to_string()));
776 }
777
778 self.check_expr(&args[0])?;
779 return Ok(Type::new(TypeKind::Bool, span));
780 }
781
782 "delete" => {
783 if args.len() != 1 {
784 return Err(
785 self.type_error("delete() requires 1 argument (key)".to_string())
786 );
787 }
788
789 self.check_expr(&args[0])?;
790 return Ok(Type::new(
791 TypeKind::Option(Box::new(Type::new(TypeKind::Unknown, span))),
792 span,
793 ));
794 }
795
796 "keys" => {
797 if !args.is_empty() {
798 return Err(self.type_error("keys() takes no arguments".to_string()));
799 }
800
801 return Ok(Type::new(
802 TypeKind::Array(Box::new(Type::new(TypeKind::Unknown, span))),
803 span,
804 ));
805 }
806
807 "values" => {
808 if !args.is_empty() {
809 return Err(self.type_error("values() takes no arguments".to_string()));
810 }
811
812 return Ok(Type::new(
813 TypeKind::Array(Box::new(Type::new(TypeKind::Unknown, span))),
814 span,
815 ));
816 }
817
818 _ => {}
819 },
820 TypeKind::Named(type_name) if type_name == "Array" => match method {
821 "len" => {
822 if !args.is_empty() {
823 return Err(self.type_error("len() takes no arguments".to_string()));
824 }
825
826 return Ok(Type::new(TypeKind::Int, span));
827 }
828
829 "get" => {
830 if args.len() != 1 {
831 return Err(self.type_error("get() requires 1 argument".to_string()));
832 }
833
834 self.check_expr(&args[0])?;
835 return Ok(Type::new(TypeKind::Named("Option".to_string()), span));
836 }
837
838 "first" | "last" => {
839 if !args.is_empty() {
840 return Err(self.type_error(format!("{}() takes no arguments", method)));
841 }
842
843 return Ok(Type::new(TypeKind::Named("Option".to_string()), span));
844 }
845
846 "push" => {
847 if args.len() != 1 {
848 return Err(self.type_error("push() requires 1 argument".to_string()));
849 }
850
851 self.check_expr(&args[0])?;
852 return Ok(Type::new(TypeKind::Unit, span));
853 }
854
855 "pop" => {
856 if !args.is_empty() {
857 return Err(self.type_error("pop() takes no arguments".to_string()));
858 }
859
860 return Ok(Type::new(TypeKind::Named("Option".to_string()), span));
861 }
862
863 "slice" => {
864 if args.len() != 2 {
865 return Err(self.type_error("slice() requires 2 arguments".to_string()));
866 }
867
868 self.check_expr(&args[0])?;
869 self.check_expr(&args[1])?;
870 return Ok(receiver_type.clone());
871 }
872
873 "clear" => {
874 if !args.is_empty() {
875 return Err(self.type_error("clear() takes no arguments".to_string()));
876 }
877
878 return Ok(Type::new(TypeKind::Unit, span));
879 }
880
881 "is_empty" => {
882 if !args.is_empty() {
883 return Err(self.type_error("is_empty() takes no arguments".to_string()));
884 }
885
886 return Ok(Type::new(TypeKind::Bool, span));
887 }
888
889 _ => {}
890 },
891 TypeKind::Option(inner_type) => match method {
892 "is_some" | "is_none" => {
893 if !args.is_empty() {
894 return Err(self.type_error(format!("{}() takes no arguments", method)));
895 }
896
897 return Ok(Type::new(TypeKind::Bool, span));
898 }
899
900 "unwrap" => {
901 if !args.is_empty() {
902 return Err(self.type_error("unwrap() takes no arguments".to_string()));
903 }
904
905 return Ok((**inner_type).clone());
906 }
907
908 "unwrap_or" => {
909 if args.len() != 1 {
910 return Err(self.type_error("unwrap_or() requires 1 argument".to_string()));
911 }
912
913 let default_type = self.check_expr(&args[0])?;
914 return Ok(default_type);
915 }
916
917 _ => {}
918 },
919 TypeKind::Result(ok_type, _err_type) => match method {
920 "is_ok" | "is_err" => {
921 if !args.is_empty() {
922 return Err(self.type_error(format!("{}() takes no arguments", method)));
923 }
924
925 return Ok(Type::new(TypeKind::Bool, span));
926 }
927
928 "unwrap" => {
929 if !args.is_empty() {
930 return Err(self.type_error("unwrap() takes no arguments".to_string()));
931 }
932
933 return Ok((**ok_type).clone());
934 }
935
936 "unwrap_or" => {
937 if args.len() != 1 {
938 return Err(self.type_error("unwrap_or() requires 1 argument".to_string()));
939 }
940
941 let default_type = self.check_expr(&args[0])?;
942 return Ok(default_type);
943 }
944
945 _ => {}
946 },
947 TypeKind::Named(type_name) if type_name == "Option" || type_name == "Result" => {
948 match method {
949 "is_some" | "is_none" | "is_ok" | "is_err" => {
950 if !args.is_empty() {
951 return Err(self.type_error(format!("{}() takes no arguments", method)));
952 }
953
954 return Ok(Type::new(TypeKind::Bool, span));
955 }
956
957 "unwrap" => {
958 if !args.is_empty() {
959 return Err(self.type_error("unwrap() takes no arguments".to_string()));
960 }
961
962 if let ExprKind::Identifier(var_name) = &receiver.kind {
963 if let Some(concrete_type) =
964 self.env.lookup_generic_param(var_name, "T")
965 {
966 return Ok(concrete_type);
967 }
968 }
969
970 return Ok(Type::new(TypeKind::Unknown, span));
971 }
972
973 "unwrap_or" => {
974 if args.len() != 1 {
975 return Err(
976 self.type_error("unwrap_or() requires 1 argument".to_string())
977 );
978 }
979
980 let default_type = self.check_expr(&args[0])?;
981 return Ok(default_type);
982 }
983
984 _ => {}
985 }
986 }
987
988 TypeKind::Float => match method {
989 "to_int" => {
990 if !args.is_empty() {
991 return Err(self.type_error("to_int() takes no arguments".to_string()));
992 }
993
994 return Ok(Type::new(TypeKind::Int, span));
995 }
996
997 "floor" | "ceil" | "round" | "sqrt" | "abs" => {
998 if !args.is_empty() {
999 return Err(self.type_error(format!("{}() takes no arguments", method)));
1000 }
1001
1002 return Ok(Type::new(TypeKind::Float, span));
1003 }
1004
1005 "clamp" => {
1006 if args.len() != 2 {
1007 return Err(
1008 self.type_error("clamp() requires 2 arguments (min, max)".to_string())
1009 );
1010 }
1011
1012 let min_type = self.check_expr(&args[0])?;
1013 let max_type = self.check_expr(&args[1])?;
1014 self.unify(&Type::new(TypeKind::Float, span), &min_type)?;
1015 self.unify(&Type::new(TypeKind::Float, span), &max_type)?;
1016 return Ok(Type::new(TypeKind::Float, span));
1017 }
1018
1019 _ => {}
1020 },
1021 TypeKind::Int => match method {
1022 "to_float" => {
1023 if !args.is_empty() {
1024 return Err(self.type_error("to_float() takes no arguments".to_string()));
1025 }
1026
1027 return Ok(Type::new(TypeKind::Float, span));
1028 }
1029
1030 "abs" => {
1031 if !args.is_empty() {
1032 return Err(self.type_error("abs() takes no arguments".to_string()));
1033 }
1034
1035 return Ok(Type::new(TypeKind::Int, span));
1036 }
1037
1038 "clamp" => {
1039 if args.len() != 2 {
1040 return Err(
1041 self.type_error("clamp() requires 2 arguments (min, max)".to_string())
1042 );
1043 }
1044
1045 let min_type = self.check_expr(&args[0])?;
1046 let max_type = self.check_expr(&args[1])?;
1047 self.unify(&Type::new(TypeKind::Int, span), &min_type)?;
1048 self.unify(&Type::new(TypeKind::Int, span), &max_type)?;
1049 return Ok(Type::new(TypeKind::Int, span));
1050 }
1051
1052 _ => {}
1053 },
1054 TypeKind::Named(type_name) => {
1055 if let Some(method_def) = self.env.lookup_method(type_name, method) {
1056 let method_def = method_def.clone();
1057 let expected_args = method_def.params.len().saturating_sub(1);
1058 if args.len() != expected_args {
1059 return Err(self.type_error(format!(
1060 "Method '{}' expects {} arguments, got {}",
1061 method,
1062 expected_args,
1063 args.len()
1064 )));
1065 }
1066
1067 for (i, (arg, param)) in args
1068 .iter()
1069 .zip(method_def.params.iter().skip(1))
1070 .enumerate()
1071 {
1072 let arg_type = self.check_expr(arg)?;
1073 if !self.types_equal(&arg_type, ¶m.ty) {
1074 return Err(self.type_error(format!(
1075 "Argument {} to method '{}': expected '{}', got '{}'",
1076 i + 1,
1077 method,
1078 param.ty,
1079 arg_type
1080 )));
1081 }
1082 }
1083
1084 return Ok(method_def
1085 .return_type
1086 .clone()
1087 .unwrap_or(Type::new(TypeKind::Unit, span)));
1088 }
1089 }
1090
1091 TypeKind::Generic(type_param) => {
1092 if let Some(trait_names) = self.current_trait_bounds.get(type_param) {
1093 for trait_name in trait_names {
1094 if let Some(trait_def) = {
1095 let key = self.resolve_type_key(trait_name);
1096 self.env
1097 .lookup_trait(&key)
1098 .or_else(|| self.env.lookup_trait(trait_name))
1099 } {
1100 if let Some(trait_method) =
1101 trait_def.methods.iter().find(|m| m.name == method)
1102 {
1103 let expected_args =
1104 trait_method.params.iter().filter(|p| !p.is_self).count();
1105 if args.len() != expected_args {
1106 return Err(self.type_error(format!(
1107 "Method '{}' expects {} arguments, got {}",
1108 method,
1109 expected_args,
1110 args.len()
1111 )));
1112 }
1113
1114 return Ok(trait_method
1115 .return_type
1116 .clone()
1117 .unwrap_or(Type::new(TypeKind::Unit, span)));
1118 }
1119 }
1120 }
1121 }
1122 }
1123
1124 TypeKind::Trait(trait_name) => {
1125 if let Some(trait_def) = {
1126 let key = self.resolve_type_key(trait_name);
1127 self.env
1128 .lookup_trait(&key)
1129 .or_else(|| self.env.lookup_trait(trait_name))
1130 } {
1131 if let Some(trait_method) = trait_def.methods.iter().find(|m| m.name == method)
1132 {
1133 let expected_args =
1134 trait_method.params.iter().filter(|p| !p.is_self).count();
1135 if args.len() != expected_args {
1136 return Err(self.type_error(format!(
1137 "Method '{}' expects {} arguments, got {}",
1138 method,
1139 expected_args,
1140 args.len()
1141 )));
1142 }
1143
1144 return Ok(trait_method
1145 .return_type
1146 .clone()
1147 .unwrap_or(Type::new(TypeKind::Unit, span)));
1148 }
1149 }
1150 }
1151
1152 _ => {}
1153 }
1154
1155 Err(self.type_error(format!(
1156 "Type '{}' has no method '{}'",
1157 receiver_type, method
1158 )))
1159 }
1160
1161 pub fn check_field_access_with_hint(
1162 &mut self,
1163 span: Span,
1164 object: &Expr,
1165 field: &str,
1166 expected_type: Option<&Type>,
1167 ) -> Result<Type> {
1168 if let ExprKind::Identifier(enum_name) = &object.kind {
1169 if let Some(enum_def) = {
1170 let key = self.resolve_type_key(enum_name);
1171 self.env
1172 .lookup_enum(&key)
1173 .or_else(|| self.env.lookup_enum(enum_name))
1174 } {
1175 let enum_def = enum_def.clone();
1176 let variant_def = enum_def
1177 .variants
1178 .iter()
1179 .find(|v| &v.name == field)
1180 .ok_or_else(|| {
1181 self.type_error_at(
1182 format!("Enum '{}' has no variant '{}'", enum_name, field),
1183 span,
1184 )
1185 })?;
1186 if variant_def.fields.is_some() {
1187 return Err(self.type_error_at(
1188 format!(
1189 "Variant '{}::{}' has fields and must be called with arguments",
1190 enum_name, field
1191 ),
1192 span,
1193 ));
1194 }
1195
1196 if let Some(expected) = expected_type {
1197 match &expected.kind {
1198 TypeKind::Option(_) if enum_name == "Option" => {
1199 return Ok(expected.clone());
1200 }
1201
1202 TypeKind::Result(_, _) if enum_name == "Result" => {
1203 return Ok(expected.clone());
1204 }
1205
1206 _ => {}
1207 }
1208 }
1209
1210 return Ok(Type::new(TypeKind::Named(enum_name.clone()), span));
1211 }
1212 }
1213
1214 let object_type = self.check_expr(object)?;
1215 let type_name = match &object_type.kind {
1216 TypeKind::Named(name) => name.clone(),
1217 _ => {
1218 return Err(self.type_error_at(
1219 format!("Cannot access field on type '{}'", object_type),
1220 object.span,
1221 ))
1222 }
1223 };
1224 self.env
1225 .lookup_struct_field(&type_name, field)
1226 .ok_or_else(|| {
1227 self.type_error_at(
1228 format!("Type '{}' has no field '{}'", type_name, field),
1229 span,
1230 )
1231 })
1232 }
1233
1234 pub fn check_index_expr(&mut self, object: &Expr, index: &Expr) -> Result<Type> {
1235 let object_type = self.check_expr(object)?;
1236 let index_type = self.check_expr(index)?;
1237 match &object_type.kind {
1238 TypeKind::Array(elem_type) => {
1239 self.unify(&Type::new(TypeKind::Int, Self::dummy_span()), &index_type)?;
1240 Ok((**elem_type).clone())
1241 }
1242
1243 TypeKind::Map(key_type, value_type) => {
1244 self.unify(key_type, &index_type)?;
1245 Ok(Type::new(
1246 TypeKind::Option(Box::new((**value_type).clone())),
1247 Self::dummy_span(),
1248 ))
1249 }
1250
1251 TypeKind::Table => {
1252 self.check_expr(index)?;
1253 Ok(Type::new(TypeKind::Unknown, Self::dummy_span()))
1254 }
1255
1256 _ => Err(self.type_error(format!("Cannot index type '{}'", object_type))),
1257 }
1258 }
1259}