lust/typechecker/expr_checker/
operations.rs

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