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