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