lust/typechecker/
mod.rs

1mod expr_checker;
2mod item_checker;
3mod stmt_checker;
4mod type_env;
5use crate::modules::{LoadedModule, ModuleImports};
6use crate::{
7    ast::*,
8    config::LustConfig,
9    error::{LustError, Result},
10};
11pub use type_env::FunctionSignature;
12pub use type_env::TypeEnv;
13pub struct TypeChecker {
14    env: TypeEnv,
15    current_function_return_type: Option<Type>,
16    in_loop: bool,
17    pending_generic_instances: Option<std::collections::HashMap<String, Type>>,
18    expected_lambda_signature: Option<(Vec<Type>, Option<Type>)>,
19    current_trait_bounds: std::collections::HashMap<String, Vec<String>>,
20    current_module: Option<String>,
21    imports_by_module: std::collections::HashMap<String, ModuleImports>,
22    expr_types_by_module: std::collections::HashMap<String, std::collections::HashMap<Span, Type>>,
23    variable_types_by_module:
24        std::collections::HashMap<String, std::collections::HashMap<Span, Type>>,
25}
26
27pub struct TypeCollection {
28    pub expr_types: std::collections::HashMap<String, std::collections::HashMap<Span, Type>>,
29    pub variable_types: std::collections::HashMap<String, std::collections::HashMap<Span, Type>>,
30}
31
32impl TypeChecker {
33    pub fn new() -> Self {
34        Self::with_config(&LustConfig::default())
35    }
36
37    pub fn with_config(config: &LustConfig) -> Self {
38        Self {
39            env: TypeEnv::with_config(config),
40            current_function_return_type: None,
41            in_loop: false,
42            pending_generic_instances: None,
43            expected_lambda_signature: None,
44            current_trait_bounds: std::collections::HashMap::new(),
45            current_module: None,
46            imports_by_module: std::collections::HashMap::new(),
47            expr_types_by_module: std::collections::HashMap::new(),
48            variable_types_by_module: std::collections::HashMap::new(),
49        }
50    }
51
52    fn dummy_span() -> Span {
53        Span::new(0, 0, 0, 0)
54    }
55
56    pub fn check_module(&mut self, items: &[Item]) -> Result<()> {
57        for item in items {
58            self.register_type_definition(item)?;
59        }
60
61        self.validate_struct_cycles()?;
62        self.env.push_scope();
63        self.register_module_init_locals(items)?;
64        for item in items {
65            self.check_item(item)?;
66        }
67
68        self.env.pop_scope();
69        Ok(())
70    }
71
72    pub fn check_program(&mut self, modules: &[LoadedModule]) -> Result<()> {
73        for m in modules {
74            self.current_module = Some(m.path.clone());
75            for item in &m.items {
76                self.register_type_definition(item)?;
77            }
78        }
79
80        self.validate_struct_cycles()?;
81        for m in modules {
82            self.current_module = Some(m.path.clone());
83            self.env.push_scope();
84            self.register_module_init_locals(&m.items)?;
85            for item in &m.items {
86                self.check_item(item)?;
87            }
88
89            self.env.pop_scope();
90        }
91
92        self.current_module = None;
93        Ok(())
94    }
95
96    fn validate_struct_cycles(&self) -> Result<()> {
97        use std::collections::{HashMap, HashSet};
98        let struct_defs = self.env.struct_definitions();
99        if struct_defs.is_empty() {
100            return Ok(());
101        }
102
103        let mut simple_to_full: HashMap<String, Vec<String>> = HashMap::new();
104        for name in struct_defs.keys() {
105            let simple = name.rsplit('.').next().unwrap_or(name).to_string();
106            simple_to_full.entry(simple).or_default().push(name.clone());
107        }
108
109        let mut struct_has_weak: HashMap<String, bool> = HashMap::new();
110        for (name, def) in &struct_defs {
111            let has_weak = def
112                .fields
113                .iter()
114                .any(|field| matches!(field.ownership, FieldOwnership::Weak));
115            struct_has_weak.insert(name.clone(), has_weak);
116        }
117
118        let mut graph: HashMap<String, Vec<String>> = HashMap::new();
119        for (name, def) in &struct_defs {
120            let module_prefix = name.rsplit_once('.').map(|(module, _)| module.to_string());
121            let mut edges: HashSet<String> = HashSet::new();
122            for field in &def.fields {
123                if matches!(field.ownership, FieldOwnership::Weak) {
124                    let target = field.weak_target.as_ref().ok_or_else(|| {
125                        self.type_error(format!(
126                            "Field '{}.{}' is marked as 'ref' but has no target type",
127                            name, field.name
128                        ))
129                    })?;
130                    let target_name = if let TypeKind::Named(inner) = &target.kind {
131                        inner
132                    } else {
133                        return Err(self.type_error(format!(
134                            "Field '{}.{}' uses 'ref' but only struct types are supported",
135                            name, field.name
136                        )));
137                    };
138                    let resolved = self.resolve_struct_name_for_cycle(
139                        target_name,
140                        module_prefix.as_deref(),
141                        &struct_defs,
142                        &simple_to_full,
143                    );
144                    if resolved.is_none() {
145                        return Err(self.type_error(format!(
146                            "Field '{}.{}' uses 'ref' but '{}' is not a known struct type",
147                            name, field.name, target_name
148                        )));
149                    }
150
151                    continue;
152                }
153
154                self.collect_strong_struct_targets(
155                    &field.ty,
156                    module_prefix.as_deref(),
157                    &struct_defs,
158                    &simple_to_full,
159                    &mut edges,
160                );
161            }
162
163            graph.insert(name.clone(), edges.into_iter().collect());
164        }
165
166        fn dfs(
167            node: &str,
168            graph: &HashMap<String, Vec<String>>,
169            visited: &mut HashSet<String>,
170            on_stack: &mut HashSet<String>,
171            stack: &mut Vec<String>,
172        ) -> Option<Vec<String>> {
173            visited.insert(node.to_string());
174            on_stack.insert(node.to_string());
175            stack.push(node.to_string());
176            if let Some(neighbors) = graph.get(node) {
177                for neighbor in neighbors {
178                    if !visited.contains(neighbor) {
179                        if let Some(cycle) = dfs(neighbor, graph, visited, on_stack, stack) {
180                            return Some(cycle);
181                        }
182                    } else if on_stack.contains(neighbor) {
183                        if let Some(pos) = stack.iter().position(|n| n == neighbor) {
184                            let mut cycle = stack[pos..].to_vec();
185                            cycle.push(neighbor.clone());
186                            return Some(cycle);
187                        }
188                    }
189                }
190            }
191
192            stack.pop();
193            on_stack.remove(node);
194            None
195        }
196
197        let mut visited: HashSet<String> = HashSet::new();
198        let mut on_stack: HashSet<String> = HashSet::new();
199        let mut stack: Vec<String> = Vec::new();
200        for name in struct_defs.keys() {
201            if !visited.contains(name) {
202                if let Some(cycle) = dfs(name, &graph, &mut visited, &mut on_stack, &mut stack) {
203                    let contains_weak = cycle
204                        .iter()
205                        .any(|node| struct_has_weak.get(node).copied().unwrap_or(false));
206                    if contains_weak {
207                        continue;
208                    }
209
210                    let description = cycle.join(" -> ");
211                    return Err(self.type_error(format!(
212                        "Strong ownership cycle detected: {}. Mark at least one field as 'ref' to break the cycle.",
213                        description
214                    )));
215                }
216            }
217        }
218
219        Ok(())
220    }
221
222    fn collect_strong_struct_targets(
223        &self,
224        ty: &Type,
225        parent_module: Option<&str>,
226        struct_defs: &std::collections::HashMap<String, StructDef>,
227        simple_to_full: &std::collections::HashMap<String, Vec<String>>,
228        out: &mut std::collections::HashSet<String>,
229    ) {
230        match &ty.kind {
231            TypeKind::Named(name) => {
232                if let Some(resolved) = self.resolve_struct_name_for_cycle(
233                    name,
234                    parent_module,
235                    struct_defs,
236                    simple_to_full,
237                ) {
238                    out.insert(resolved);
239                }
240            }
241
242            TypeKind::Array(inner)
243            | TypeKind::Ref(inner)
244            | TypeKind::MutRef(inner)
245            | TypeKind::Option(inner) => {
246                self.collect_strong_struct_targets(
247                    inner,
248                    parent_module,
249                    struct_defs,
250                    simple_to_full,
251                    out,
252                );
253            }
254
255            TypeKind::Map(key, value) => {
256                self.collect_strong_struct_targets(
257                    key,
258                    parent_module,
259                    struct_defs,
260                    simple_to_full,
261                    out,
262                );
263                self.collect_strong_struct_targets(
264                    value,
265                    parent_module,
266                    struct_defs,
267                    simple_to_full,
268                    out,
269                );
270            }
271
272            TypeKind::Tuple(elements) | TypeKind::Union(elements) => {
273                for element in elements {
274                    self.collect_strong_struct_targets(
275                        element,
276                        parent_module,
277                        struct_defs,
278                        simple_to_full,
279                        out,
280                    );
281                }
282            }
283
284            TypeKind::Result(ok, err) => {
285                self.collect_strong_struct_targets(
286                    ok,
287                    parent_module,
288                    struct_defs,
289                    simple_to_full,
290                    out,
291                );
292                self.collect_strong_struct_targets(
293                    err,
294                    parent_module,
295                    struct_defs,
296                    simple_to_full,
297                    out,
298                );
299            }
300
301            TypeKind::GenericInstance { type_args, .. } => {
302                for arg in type_args {
303                    self.collect_strong_struct_targets(
304                        arg,
305                        parent_module,
306                        struct_defs,
307                        simple_to_full,
308                        out,
309                    );
310                }
311            }
312
313            _ => {}
314        }
315    }
316
317    fn resolve_struct_name_for_cycle(
318        &self,
319        name: &str,
320        parent_module: Option<&str>,
321        struct_defs: &std::collections::HashMap<String, StructDef>,
322        simple_to_full: &std::collections::HashMap<String, Vec<String>>,
323    ) -> Option<String> {
324        if struct_defs.contains_key(name) {
325            return Some(name.to_string());
326        }
327
328        if name.contains('.') {
329            return None;
330        }
331
332        if let Some(candidates) = simple_to_full.get(name) {
333            if candidates.len() == 1 {
334                return Some(candidates[0].clone());
335            }
336
337            if let Some(module) = parent_module {
338                for candidate in candidates {
339                    if let Some((candidate_module, _)) = candidate.rsplit_once('.') {
340                        if candidate_module == module {
341                            return Some(candidate.clone());
342                        }
343                    }
344                }
345            }
346        }
347
348        None
349    }
350
351    pub fn set_imports_by_module(&mut self, map: std::collections::HashMap<String, ModuleImports>) {
352        self.imports_by_module = map;
353    }
354
355    pub fn take_type_info(&mut self) -> TypeCollection {
356        TypeCollection {
357            expr_types: std::mem::take(&mut self.expr_types_by_module),
358            variable_types: std::mem::take(&mut self.variable_types_by_module),
359        }
360    }
361
362    pub fn function_signatures(
363        &self,
364    ) -> std::collections::HashMap<String, type_env::FunctionSignature> {
365        self.env.function_signatures()
366    }
367
368    pub fn struct_definitions(&self) -> std::collections::HashMap<String, StructDef> {
369        self.env.struct_definitions()
370    }
371
372    pub fn enum_definitions(&self) -> std::collections::HashMap<String, EnumDef> {
373        self.env.enum_definitions()
374    }
375
376    fn register_module_init_locals(&mut self, items: &[Item]) -> Result<()> {
377        let module = match &self.current_module {
378            Some(m) => m.clone(),
379            None => return Ok(()),
380        };
381        let init_name = format!("__init@{}", module);
382        for item in items {
383            if let ItemKind::Function(func) = &item.kind {
384                if func.name == init_name {
385                    for stmt in &func.body {
386                        if let StmtKind::Local {
387                            bindings,
388                            mutable,
389                            initializer,
390                        } = &stmt.kind
391                        {
392                            self.check_local_stmt(
393                                bindings.as_slice(),
394                                *mutable,
395                                initializer.as_ref().map(|values| values.as_slice()),
396                            )?;
397                        }
398                    }
399                }
400            }
401        }
402
403        Ok(())
404    }
405
406    pub fn resolve_function_key(&self, name: &str) -> String {
407        if name.contains('.') || name.contains(':') {
408            return name.to_string();
409        }
410
411        if let Some(module) = &self.current_module {
412            if let Some(imports) = self.imports_by_module.get(module) {
413                if let Some(fq) = imports.function_aliases.get(name) {
414                    return fq.clone();
415                }
416            }
417
418            let qualified = format!("{}.{}", module, name);
419            if self.env.lookup_function(&qualified).is_some() {
420                return qualified;
421            }
422
423            if self.env.lookup_function(name).is_some() {
424                return name.to_string();
425            }
426
427            return qualified;
428        }
429
430        name.to_string()
431    }
432
433    pub fn resolve_module_alias(&self, alias: &str) -> Option<String> {
434        if let Some(module) = &self.current_module {
435            if let Some(imports) = self.imports_by_module.get(module) {
436                if let Some(m) = imports.module_aliases.get(alias) {
437                    return Some(m.clone());
438                }
439            }
440        }
441
442        None
443    }
444
445    pub fn resolve_type_key(&self, name: &str) -> String {
446        if let Some((head, tail)) = name.split_once('.') {
447            if let Some(module) = &self.current_module {
448                if let Some(imports) = self.imports_by_module.get(module) {
449                    if let Some(real_module) = imports.module_aliases.get(head) {
450                        if tail.is_empty() {
451                            return real_module.clone();
452                        } else {
453                            return format!("{}.{}", real_module, tail);
454                        }
455                    }
456                }
457            }
458
459            return name.to_string();
460        }
461
462        if self.env.lookup_struct(name).is_some()
463            || self.env.lookup_enum(name).is_some()
464            || self.env.lookup_trait(name).is_some()
465        {
466            return name.to_string();
467        }
468
469        if self.env.is_builtin_type(name) {
470            return name.to_string();
471        }
472
473        if let Some(module) = &self.current_module {
474            if let Some(imports) = self.imports_by_module.get(module) {
475                if let Some(fq) = imports.type_aliases.get(name) {
476                    return fq.clone();
477                }
478            }
479
480            return format!("{}.{}", module, name);
481        }
482
483        name.to_string()
484    }
485
486    fn register_type_definition(&mut self, item: &Item) -> Result<()> {
487        match &item.kind {
488            ItemKind::Struct(s) => {
489                let mut s2 = s.clone();
490                if let Some(module) = &self.current_module {
491                    if !s2.name.contains('.') {
492                        s2.name = format!("{}.{}", module, s2.name);
493                    }
494                }
495
496                self.env.register_struct(&s2)?;
497            }
498
499            ItemKind::Enum(e) => {
500                let mut e2 = e.clone();
501                if let Some(module) = &self.current_module {
502                    if !e2.name.contains('.') {
503                        e2.name = format!("{}.{}", module, e2.name);
504                    }
505                }
506
507                self.env.register_enum(&e2)?;
508            }
509
510            ItemKind::Trait(t) => {
511                let mut t2 = t.clone();
512                if let Some(module) = &self.current_module {
513                    if !t2.name.contains('.') {
514                        t2.name = format!("{}.{}", module, t2.name);
515                    }
516                }
517
518                self.env.register_trait(&t2)?;
519            }
520
521            ItemKind::TypeAlias {
522                name,
523                type_params,
524                target,
525            } => {
526                let qname = if let Some(module) = &self.current_module {
527                    if name.contains('.') {
528                        name.clone()
529                    } else {
530                        format!("{}.{}", module, name)
531                    }
532                } else {
533                    name.clone()
534                };
535                self.env
536                    .register_type_alias(qname, type_params.clone(), target.clone())?;
537            }
538
539            _ => {}
540        }
541
542        Ok(())
543    }
544
545    fn type_error(&self, message: String) -> LustError {
546        LustError::TypeError { message }
547    }
548
549    fn type_error_at(&self, message: String, span: Span) -> LustError {
550        if span.start_line > 0 {
551            LustError::TypeErrorWithSpan {
552                message,
553                line: span.start_line,
554                column: span.start_col,
555                module: self.current_module.clone(),
556            }
557        } else {
558            LustError::TypeError { message }
559        }
560    }
561
562    fn types_equal(&self, t1: &Type, t2: &Type) -> bool {
563        t1.kind == t2.kind
564    }
565
566    pub fn canonicalize_type(&self, ty: &Type) -> Type {
567        use crate::ast::TypeKind as TK;
568        match &ty.kind {
569            TK::Named(name) => Type::new(TK::Named(self.resolve_type_key(name)), ty.span),
570            TK::Array(inner) => {
571                Type::new(TK::Array(Box::new(self.canonicalize_type(inner))), ty.span)
572            }
573
574            TK::Tuple(elements) => Type::new(
575                TK::Tuple(elements.iter().map(|t| self.canonicalize_type(t)).collect()),
576                ty.span,
577            ),
578            TK::Option(inner) => {
579                Type::new(TK::Option(Box::new(self.canonicalize_type(inner))), ty.span)
580            }
581
582            TK::Result(ok, err) => Type::new(
583                TK::Result(
584                    Box::new(self.canonicalize_type(ok)),
585                    Box::new(self.canonicalize_type(err)),
586                ),
587                ty.span,
588            ),
589            TK::Map(k, v) => Type::new(
590                TK::Map(
591                    Box::new(self.canonicalize_type(k)),
592                    Box::new(self.canonicalize_type(v)),
593                ),
594                ty.span,
595            ),
596            TK::Ref(inner) => Type::new(TK::Ref(Box::new(self.canonicalize_type(inner))), ty.span),
597            TK::MutRef(inner) => {
598                Type::new(TK::MutRef(Box::new(self.canonicalize_type(inner))), ty.span)
599            }
600
601            TK::Pointer { mutable, pointee } => Type::new(
602                TK::Pointer {
603                    mutable: *mutable,
604                    pointee: Box::new(self.canonicalize_type(pointee)),
605                },
606                ty.span,
607            ),
608            _ => ty.clone(),
609        }
610    }
611
612    fn unify(&self, expected: &Type, actual: &Type) -> Result<()> {
613        let span = if actual.span.start_line > 0 {
614            Some(actual.span)
615        } else if expected.span.start_line > 0 {
616            Some(expected.span)
617        } else {
618            None
619        };
620        self.unify_at(expected, actual, span)
621    }
622
623    fn unify_at(&self, expected: &Type, actual: &Type, span: Option<Span>) -> Result<()> {
624        if matches!(expected.kind, TypeKind::Unknown) || matches!(actual.kind, TypeKind::Unknown) {
625            return Ok(());
626        }
627
628        if matches!(expected.kind, TypeKind::Infer) || matches!(actual.kind, TypeKind::Infer) {
629            return Ok(());
630        }
631
632        match (&expected.kind, &actual.kind) {
633            (TypeKind::Union(expected_types), TypeKind::Union(actual_types)) => {
634                if expected_types.len() != actual_types.len() {
635                    return Err(self.type_error(format!(
636                        "Union types have different number of members: expected {}, got {}",
637                        expected_types.len(),
638                        actual_types.len()
639                    )));
640                }
641
642                for exp_type in expected_types {
643                    let mut found = false;
644                    for act_type in actual_types {
645                        if self.types_equal(exp_type, act_type) {
646                            found = true;
647                            break;
648                        }
649                    }
650
651                    if !found {
652                        return Err(match span {
653                            Some(s) => self.type_error_at(
654                                format!(
655                                    "Union type member '{}' not found in actual union",
656                                    exp_type
657                                ),
658                                s,
659                            ),
660                            None => self.type_error(format!(
661                                "Union type member '{}' not found in actual union",
662                                exp_type
663                            )),
664                        });
665                    }
666                }
667
668                return Ok(());
669            }
670
671            (TypeKind::Union(expected_types), _) => {
672                for union_member in expected_types {
673                    if self.unify(union_member, actual).is_ok() {
674                        return Ok(());
675                    }
676                }
677
678                return Err(match span {
679                    Some(s) => self.type_error_at(
680                        format!("Type '{}' is not compatible with union type", actual),
681                        s,
682                    ),
683                    None => self.type_error(format!(
684                        "Type '{}' is not compatible with union type",
685                        actual
686                    )),
687                });
688            }
689
690            (_, TypeKind::Union(actual_types)) => {
691                for union_member in actual_types {
692                    self.unify(expected, union_member)?;
693                }
694
695                return Ok(());
696            }
697
698            _ => {}
699        }
700
701        match (&expected.kind, &actual.kind) {
702            (TypeKind::Tuple(expected_elems), TypeKind::Tuple(actual_elems)) => {
703                if expected_elems.len() != actual_elems.len() {
704                    return Err(match span {
705                        Some(s) => self.type_error_at(
706                            format!(
707                                "Tuple length mismatch: expected {} element(s), got {}",
708                                expected_elems.len(),
709                                actual_elems.len()
710                            ),
711                            s,
712                        ),
713                        None => self.type_error(format!(
714                            "Tuple length mismatch: expected {} element(s), got {}",
715                            expected_elems.len(),
716                            actual_elems.len()
717                        )),
718                    });
719                }
720
721                for (exp_elem, act_elem) in expected_elems.iter().zip(actual_elems.iter()) {
722                    self.unify(exp_elem, act_elem)?;
723                }
724
725                return Ok(());
726            }
727
728            (TypeKind::Tuple(_), _) | (_, TypeKind::Tuple(_)) => {
729                return Err(match span {
730                    Some(s) => self.type_error_at(
731                        format!("Tuple type is not compatible with type '{}'", actual),
732                        s,
733                    ),
734                    None => self.type_error(format!(
735                        "Tuple type is not compatible with type '{}'",
736                        actual
737                    )),
738                })
739            }
740
741            (TypeKind::Named(name), TypeKind::Array(_))
742            | (TypeKind::Array(_), TypeKind::Named(name))
743                if name == "Array" =>
744            {
745                return Ok(());
746            }
747
748            (TypeKind::Array(exp_el), TypeKind::Array(act_el)) => {
749                if matches!(exp_el.kind, TypeKind::Unknown | TypeKind::Infer)
750                    || matches!(act_el.kind, TypeKind::Unknown | TypeKind::Infer)
751                {
752                    return Ok(());
753                } else {
754                    return self.unify(exp_el, act_el);
755                }
756            }
757
758            (TypeKind::Named(name), TypeKind::Option(_))
759            | (TypeKind::Option(_), TypeKind::Named(name))
760                if name == "Option" =>
761            {
762                return Ok(());
763            }
764
765            (TypeKind::Option(exp_inner), TypeKind::Option(act_inner)) => {
766                if matches!(exp_inner.kind, TypeKind::Unknown | TypeKind::Infer)
767                    || matches!(act_inner.kind, TypeKind::Unknown | TypeKind::Infer)
768                {
769                    return Ok(());
770                } else {
771                    return self.unify(exp_inner, act_inner);
772                }
773            }
774
775            (TypeKind::Named(name), TypeKind::Result(_, _))
776            | (TypeKind::Result(_, _), TypeKind::Named(name))
777                if name == "Result" =>
778            {
779                return Ok(());
780            }
781
782            (TypeKind::Result(exp_ok, exp_err), TypeKind::Result(act_ok, act_err)) => {
783                if matches!(exp_ok.kind, TypeKind::Unknown | TypeKind::Infer)
784                    || matches!(act_ok.kind, TypeKind::Unknown | TypeKind::Infer)
785                {
786                    if matches!(exp_err.kind, TypeKind::Unknown | TypeKind::Infer)
787                        || matches!(act_err.kind, TypeKind::Unknown | TypeKind::Infer)
788                    {
789                        return Ok(());
790                    } else {
791                        return self.unify(exp_err, act_err);
792                    }
793                } else {
794                    self.unify(exp_ok, act_ok)?;
795                    return self.unify(exp_err, act_err);
796                }
797            }
798
799            _ => {}
800        }
801
802        match (&expected.kind, &actual.kind) {
803            (TypeKind::Table, TypeKind::Map(key, val)) => {
804                if matches!(key.kind, TypeKind::Unknown) && matches!(val.kind, TypeKind::Unknown) {
805                    return Ok(());
806                }
807            }
808
809            (TypeKind::Map(key, val), TypeKind::Table) => {
810                if matches!(key.kind, TypeKind::Unknown) && matches!(val.kind, TypeKind::Unknown) {
811                    return Ok(());
812                }
813            }
814
815            _ => {}
816        }
817
818        if self.types_equal(expected, actual) {
819            Ok(())
820        } else {
821            Err(match span {
822                Some(s) => self.type_error_at(
823                    format!("Type mismatch: expected '{}', got '{}'", expected, actual),
824                    s,
825                ),
826                None => self.type_error(format!(
827                    "Type mismatch: expected '{}', got '{}'",
828                    expected, actual
829                )),
830            })
831        }
832    }
833
834    fn types_compatible(&self, expected: &Type, actual: &Type) -> bool {
835        if matches!(expected.kind, TypeKind::Unknown) || matches!(actual.kind, TypeKind::Unknown) {
836            return true;
837        }
838
839        if matches!(expected.kind, TypeKind::Infer) || matches!(actual.kind, TypeKind::Infer) {
840            return true;
841        }
842
843        match (&expected.kind, &actual.kind) {
844            (TypeKind::Generic(_), TypeKind::Generic(_)) => return true,
845            (TypeKind::Generic(_), _) | (_, TypeKind::Generic(_)) => return true,
846            _ => {}
847        }
848
849        match (&expected.kind, &actual.kind) {
850            (TypeKind::Array(e1), TypeKind::Array(e2)) => {
851                return self.types_compatible(e1, e2);
852            }
853
854            (TypeKind::Named(name), TypeKind::Array(_))
855            | (TypeKind::Array(_), TypeKind::Named(name))
856                if name == "Array" =>
857            {
858                return true;
859            }
860
861            _ => {}
862        }
863
864        match (&expected.kind, &actual.kind) {
865            (TypeKind::Map(k1, v1), TypeKind::Map(k2, v2)) => {
866                return self.types_compatible(k1, k2) && self.types_compatible(v1, v2);
867            }
868
869            _ => {}
870        }
871
872        match (&expected.kind, &actual.kind) {
873            (TypeKind::Option(t1), TypeKind::Option(t2)) => {
874                return self.types_compatible(t1, t2);
875            }
876
877            (TypeKind::Named(name), TypeKind::Option(_))
878            | (TypeKind::Option(_), TypeKind::Named(name))
879                if name == "Option" =>
880            {
881                return true;
882            }
883
884            _ => {}
885        }
886
887        match (&expected.kind, &actual.kind) {
888            (TypeKind::Result(ok1, err1), TypeKind::Result(ok2, err2)) => {
889                return self.types_compatible(ok1, ok2) && self.types_compatible(err1, err2);
890            }
891
892            (TypeKind::Named(name), TypeKind::Result(_, _))
893            | (TypeKind::Result(_, _), TypeKind::Named(name))
894                if name == "Result" =>
895            {
896                return true;
897            }
898
899            _ => {}
900        }
901
902        match (&expected.kind, &actual.kind) {
903            (
904                TypeKind::Function {
905                    params: p1,
906                    return_type: r1,
907                },
908                TypeKind::Function {
909                    params: p2,
910                    return_type: r2,
911                },
912            ) => {
913                if p1.len() != p2.len() {
914                    return false;
915                }
916
917                for (t1, t2) in p1.iter().zip(p2.iter()) {
918                    if !self.types_compatible(t1, t2) {
919                        return false;
920                    }
921                }
922
923                return self.types_compatible(r1, r2);
924            }
925
926            _ => {}
927        }
928
929        self.types_equal(expected, actual)
930    }
931
932    fn unify_with_bounds(&self, expected: &Type, actual: &Type) -> Result<()> {
933        if let TypeKind::Generic(type_param) = &expected.kind {
934            if let Some(trait_names) = self.current_trait_bounds.get(type_param) {
935                for trait_name in trait_names {
936                    if !self.env.type_implements_trait(actual, trait_name) {
937                        return Err(self.type_error(format!(
938                            "Type '{}' does not implement required trait '{}'",
939                            actual, trait_name
940                        )));
941                    }
942                }
943
944                return Ok(());
945            }
946
947            return Ok(());
948        }
949
950        self.unify(expected, actual)
951    }
952}