lust/typechecker/expr_checker/
operations.rs

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, &param.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}