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