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