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