lust/typechecker/expr_checker/
operations.rs

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