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