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(&self) -> HashMap<String, type_env::FunctionSignature> {
370        self.env.function_signatures()
371    }
372
373    pub fn struct_definitions(&self) -> HashMap<String, StructDef> {
374        self.env.struct_definitions()
375    }
376
377    pub fn enum_definitions(&self) -> HashMap<String, EnumDef> {
378        self.env.enum_definitions()
379    }
380
381    fn register_module_init_locals(&mut self, items: &[Item]) -> Result<()> {
382        let module = match &self.current_module {
383            Some(m) => m.clone(),
384            None => return Ok(()),
385        };
386        let init_name = format!("__init@{}", module);
387        for item in items {
388            if let ItemKind::Function(func) = &item.kind {
389                if func.name == init_name {
390                    for stmt in &func.body {
391                        if let StmtKind::Local {
392                            bindings,
393                            ref mutable,
394                            initializer,
395                        } = &stmt.kind
396                        {
397                            self.check_local_stmt(
398                                bindings.as_slice(),
399                                *mutable,
400                                initializer.as_ref().map(|values| values.as_slice()),
401                            )?;
402                        }
403                    }
404                }
405            }
406        }
407
408        Ok(())
409    }
410
411    pub fn resolve_function_key(&self, name: &str) -> String {
412        if name.contains('.') || name.contains(':') {
413            return name.to_string();
414        }
415
416        if let Some(module) = &self.current_module {
417            if let Some(imports) = self.imports_by_module.get(module) {
418                if let Some(fq) = imports.function_aliases.get(name) {
419                    return fq.clone();
420                }
421            }
422
423            let qualified = format!("{}.{}", module, name);
424            if self.env.lookup_function(&qualified).is_some() {
425                return qualified;
426            }
427
428            if self.env.lookup_function(name).is_some() {
429                return name.to_string();
430            }
431
432            return qualified;
433        }
434
435        name.to_string()
436    }
437
438    pub fn resolve_module_alias(&self, alias: &str) -> Option<String> {
439        if let Some(module) = &self.current_module {
440            if let Some(imports) = self.imports_by_module.get(module) {
441                if let Some(m) = imports.module_aliases.get(alias) {
442                    return Some(m.clone());
443                }
444            }
445        }
446
447        None
448    }
449
450    pub fn resolve_type_key(&self, name: &str) -> String {
451        if let Some((head, tail)) = name.split_once('.') {
452            if let Some(module) = &self.current_module {
453                if let Some(imports) = self.imports_by_module.get(module) {
454                    if let Some(real_module) = imports.module_aliases.get(head) {
455                        if tail.is_empty() {
456                            return real_module.clone();
457                        } else {
458                            return format!("{}.{}", real_module, tail);
459                        }
460                    }
461                }
462            }
463
464            return name.to_string();
465        }
466
467        if self.env.lookup_struct(name).is_some()
468            || self.env.lookup_enum(name).is_some()
469            || self.env.lookup_trait(name).is_some()
470        {
471            return name.to_string();
472        }
473
474        if self.env.is_builtin_type(name) {
475            return name.to_string();
476        }
477
478        if let Some(module) = &self.current_module {
479            if let Some(imports) = self.imports_by_module.get(module) {
480                if let Some(fq) = imports.type_aliases.get(name) {
481                    return fq.clone();
482                }
483            }
484
485            return format!("{}.{}", module, name);
486        }
487
488        name.to_string()
489    }
490
491    fn register_type_definition(&mut self, item: &Item) -> Result<()> {
492        match &item.kind {
493            ItemKind::Struct(s) => {
494                let mut s2 = s.clone();
495                if let Some(module) = &self.current_module {
496                    if !s2.name.contains('.') {
497                        s2.name = format!("{}.{}", module, s2.name);
498                    }
499                }
500
501                self.env.register_struct(&s2)?;
502            }
503
504            ItemKind::Enum(e) => {
505                let mut e2 = e.clone();
506                if let Some(module) = &self.current_module {
507                    if !e2.name.contains('.') {
508                        e2.name = format!("{}.{}", module, e2.name);
509                    }
510                }
511
512                self.env.register_enum(&e2)?;
513            }
514
515            ItemKind::Trait(t) => {
516                let mut t2 = t.clone();
517                if let Some(module) = &self.current_module {
518                    if !t2.name.contains('.') {
519                        t2.name = format!("{}.{}", module, t2.name);
520                    }
521                }
522
523                self.env.register_trait(&t2)?;
524            }
525
526            ItemKind::TypeAlias {
527                name,
528                type_params,
529                target,
530            } => {
531                let qname = if let Some(module) = &self.current_module {
532                    if name.contains('.') {
533                        name.clone()
534                    } else {
535                        format!("{}.{}", module, name)
536                    }
537                } else {
538                    name.clone()
539                };
540                self.env
541                    .register_type_alias(qname, type_params.clone(), target.clone())?;
542            }
543
544            _ => {}
545        }
546
547        Ok(())
548    }
549
550    fn type_error(&self, message: String) -> LustError {
551        LustError::TypeError { message }
552    }
553
554    fn type_error_at(&self, message: String, span: Span) -> LustError {
555        if span.start_line > 0 {
556            LustError::TypeErrorWithSpan {
557                message,
558                line: span.start_line,
559                column: span.start_col,
560                module: self.current_module.clone(),
561            }
562        } else {
563            LustError::TypeError { message }
564        }
565    }
566
567    fn types_equal(&self, t1: &Type, t2: &Type) -> bool {
568        t1.kind == t2.kind
569    }
570
571    pub fn canonicalize_type(&self, ty: &Type) -> Type {
572        use crate::ast::TypeKind as TK;
573        match &ty.kind {
574            TK::Named(name) => Type::new(TK::Named(self.resolve_type_key(name)), ty.span),
575            TK::Array(inner) => {
576                Type::new(TK::Array(Box::new(self.canonicalize_type(inner))), ty.span)
577            }
578
579            TK::Tuple(elements) => Type::new(
580                TK::Tuple(elements.iter().map(|t| self.canonicalize_type(t)).collect()),
581                ty.span,
582            ),
583            TK::Option(inner) => {
584                Type::new(TK::Option(Box::new(self.canonicalize_type(inner))), ty.span)
585            }
586
587            TK::Result(ok, err) => Type::new(
588                TK::Result(
589                    Box::new(self.canonicalize_type(ok)),
590                    Box::new(self.canonicalize_type(err)),
591                ),
592                ty.span,
593            ),
594            TK::Map(k, v) => Type::new(
595                TK::Map(
596                    Box::new(self.canonicalize_type(k)),
597                    Box::new(self.canonicalize_type(v)),
598                ),
599                ty.span,
600            ),
601            TK::Ref(inner) => Type::new(TK::Ref(Box::new(self.canonicalize_type(inner))), ty.span),
602            TK::MutRef(inner) => {
603                Type::new(TK::MutRef(Box::new(self.canonicalize_type(inner))), ty.span)
604            }
605
606            TK::Pointer { mutable, pointee } => Type::new(
607                TK::Pointer {
608                    mutable: *mutable,
609                    pointee: Box::new(self.canonicalize_type(pointee)),
610                },
611                ty.span,
612            ),
613            _ => ty.clone(),
614        }
615    }
616
617    fn unify(&self, expected: &Type, actual: &Type) -> Result<()> {
618        let span = if actual.span.start_line > 0 {
619            Some(actual.span)
620        } else if expected.span.start_line > 0 {
621            Some(expected.span)
622        } else {
623            None
624        };
625        self.unify_at(expected, actual, span)
626    }
627
628    fn unify_at(&self, expected: &Type, actual: &Type, span: Option<Span>) -> Result<()> {
629        if matches!(expected.kind, TypeKind::Unknown) || matches!(actual.kind, TypeKind::Unknown) {
630            return Ok(());
631        }
632
633        if matches!(expected.kind, TypeKind::Infer) || matches!(actual.kind, TypeKind::Infer) {
634            return Ok(());
635        }
636
637        match (&expected.kind, &actual.kind) {
638            (TypeKind::Union(expected_types), TypeKind::Union(actual_types)) => {
639                if expected_types.len() != actual_types.len() {
640                    return Err(self.type_error(format!(
641                        "Union types have different number of members: expected {}, got {}",
642                        expected_types.len(),
643                        actual_types.len()
644                    )));
645                }
646
647                for exp_type in expected_types {
648                    let mut found = false;
649                    for act_type in actual_types {
650                        if self.types_equal(exp_type, act_type) {
651                            found = true;
652                            break;
653                        }
654                    }
655
656                    if !found {
657                        return Err(match span {
658                            Some(s) => self.type_error_at(
659                                format!(
660                                    "Union type member '{}' not found in actual union",
661                                    exp_type
662                                ),
663                                s,
664                            ),
665                            None => self.type_error(format!(
666                                "Union type member '{}' not found in actual union",
667                                exp_type
668                            )),
669                        });
670                    }
671                }
672
673                return Ok(());
674            }
675
676            (TypeKind::Union(expected_types), _) => {
677                for union_member in expected_types {
678                    if self.unify(union_member, actual).is_ok() {
679                        return Ok(());
680                    }
681                }
682
683                return Err(match span {
684                    Some(s) => self.type_error_at(
685                        format!("Type '{}' is not compatible with union type", actual),
686                        s,
687                    ),
688                    None => self.type_error(format!(
689                        "Type '{}' is not compatible with union type",
690                        actual
691                    )),
692                });
693            }
694
695            (_, TypeKind::Union(actual_types)) => {
696                for union_member in actual_types {
697                    self.unify(expected, union_member)?;
698                }
699
700                return Ok(());
701            }
702
703            _ => {}
704        }
705
706        match (&expected.kind, &actual.kind) {
707            (TypeKind::Tuple(expected_elems), TypeKind::Tuple(actual_elems)) => {
708                if expected_elems.len() != actual_elems.len() {
709                    return Err(match span {
710                        Some(s) => self.type_error_at(
711                            format!(
712                                "Tuple length mismatch: expected {} element(s), got {}",
713                                expected_elems.len(),
714                                actual_elems.len()
715                            ),
716                            s,
717                        ),
718                        None => self.type_error(format!(
719                            "Tuple length mismatch: expected {} element(s), got {}",
720                            expected_elems.len(),
721                            actual_elems.len()
722                        )),
723                    });
724                }
725
726                for (exp_elem, act_elem) in expected_elems.iter().zip(actual_elems.iter()) {
727                    self.unify(exp_elem, act_elem)?;
728                }
729
730                return Ok(());
731            }
732
733            (TypeKind::Tuple(_), _) | (_, TypeKind::Tuple(_)) => {
734                return Err(match span {
735                    Some(s) => self.type_error_at(
736                        format!("Tuple type is not compatible with type '{}'", actual),
737                        s,
738                    ),
739                    None => self.type_error(format!(
740                        "Tuple type is not compatible with type '{}'",
741                        actual
742                    )),
743                })
744            }
745
746            (TypeKind::Named(name), TypeKind::Array(_))
747            | (TypeKind::Array(_), TypeKind::Named(name))
748                if name == "Array" =>
749            {
750                return Ok(());
751            }
752
753            (TypeKind::Array(exp_el), TypeKind::Array(act_el)) => {
754                if matches!(exp_el.kind, TypeKind::Unknown | TypeKind::Infer)
755                    || matches!(act_el.kind, TypeKind::Unknown | TypeKind::Infer)
756                {
757                    return Ok(());
758                } else {
759                    return self.unify(exp_el, act_el);
760                }
761            }
762
763            (TypeKind::Named(name), TypeKind::Option(_))
764            | (TypeKind::Option(_), TypeKind::Named(name))
765                if name == "Option" =>
766            {
767                return Ok(());
768            }
769
770            (TypeKind::Option(exp_inner), TypeKind::Option(act_inner)) => {
771                if matches!(exp_inner.kind, TypeKind::Unknown | TypeKind::Infer)
772                    || matches!(act_inner.kind, TypeKind::Unknown | TypeKind::Infer)
773                {
774                    return Ok(());
775                } else {
776                    return self.unify(exp_inner, act_inner);
777                }
778            }
779
780            (TypeKind::Named(name), TypeKind::Result(_, _))
781            | (TypeKind::Result(_, _), TypeKind::Named(name))
782                if name == "Result" =>
783            {
784                return Ok(());
785            }
786
787            (TypeKind::Result(exp_ok, exp_err), TypeKind::Result(act_ok, act_err)) => {
788                if matches!(exp_ok.kind, TypeKind::Unknown | TypeKind::Infer)
789                    || matches!(act_ok.kind, TypeKind::Unknown | TypeKind::Infer)
790                {
791                    if matches!(exp_err.kind, TypeKind::Unknown | TypeKind::Infer)
792                        || matches!(act_err.kind, TypeKind::Unknown | TypeKind::Infer)
793                    {
794                        return Ok(());
795                    } else {
796                        return self.unify(exp_err, act_err);
797                    }
798                } else {
799                    self.unify(exp_ok, act_ok)?;
800                    return self.unify(exp_err, act_err);
801                }
802            }
803
804            _ => {}
805        }
806
807        match (&expected.kind, &actual.kind) {
808            (TypeKind::Table, TypeKind::Map(key, val)) => {
809                if matches!(key.kind, TypeKind::Unknown) && matches!(val.kind, TypeKind::Unknown) {
810                    return Ok(());
811                }
812            }
813
814            (TypeKind::Map(key, val), TypeKind::Table) => {
815                if matches!(key.kind, TypeKind::Unknown) && matches!(val.kind, TypeKind::Unknown) {
816                    return Ok(());
817                }
818            }
819
820            _ => {}
821        }
822
823        if self.types_equal(expected, actual) {
824            Ok(())
825        } else {
826            Err(match span {
827                Some(s) => self.type_error_at(
828                    format!("Type mismatch: expected '{}', got '{}'", expected, actual),
829                    s,
830                ),
831                None => self.type_error(format!(
832                    "Type mismatch: expected '{}', got '{}'",
833                    expected, actual
834                )),
835            })
836        }
837    }
838
839    fn types_compatible(&self, expected: &Type, actual: &Type) -> bool {
840        if matches!(expected.kind, TypeKind::Unknown) || matches!(actual.kind, TypeKind::Unknown) {
841            return true;
842        }
843
844        if matches!(expected.kind, TypeKind::Infer) || matches!(actual.kind, TypeKind::Infer) {
845            return true;
846        }
847
848        match (&expected.kind, &actual.kind) {
849            (TypeKind::Generic(_), TypeKind::Generic(_)) => return true,
850            (TypeKind::Generic(_), _) | (_, TypeKind::Generic(_)) => return true,
851            _ => {}
852        }
853
854        match (&expected.kind, &actual.kind) {
855            (TypeKind::Array(e1), TypeKind::Array(e2)) => {
856                return self.types_compatible(e1, e2);
857            }
858
859            (TypeKind::Named(name), TypeKind::Array(_))
860            | (TypeKind::Array(_), TypeKind::Named(name))
861                if name == "Array" =>
862            {
863                return true;
864            }
865
866            _ => {}
867        }
868
869        match (&expected.kind, &actual.kind) {
870            (TypeKind::Map(k1, v1), TypeKind::Map(k2, v2)) => {
871                return self.types_compatible(k1, k2) && self.types_compatible(v1, v2);
872            }
873
874            _ => {}
875        }
876
877        match (&expected.kind, &actual.kind) {
878            (TypeKind::Option(t1), TypeKind::Option(t2)) => {
879                return self.types_compatible(t1, t2);
880            }
881
882            (TypeKind::Named(name), TypeKind::Option(_))
883            | (TypeKind::Option(_), TypeKind::Named(name))
884                if name == "Option" =>
885            {
886                return true;
887            }
888
889            _ => {}
890        }
891
892        match (&expected.kind, &actual.kind) {
893            (TypeKind::Result(ok1, err1), TypeKind::Result(ok2, err2)) => {
894                return self.types_compatible(ok1, ok2) && self.types_compatible(err1, err2);
895            }
896
897            (TypeKind::Named(name), TypeKind::Result(_, _))
898            | (TypeKind::Result(_, _), TypeKind::Named(name))
899                if name == "Result" =>
900            {
901                return true;
902            }
903
904            _ => {}
905        }
906
907        match (&expected.kind, &actual.kind) {
908            (
909                TypeKind::Function {
910                    params: p1,
911                    return_type: r1,
912                },
913                TypeKind::Function {
914                    params: p2,
915                    return_type: r2,
916                },
917            ) => {
918                if p1.len() != p2.len() {
919                    return false;
920                }
921
922                for (t1, t2) in p1.iter().zip(p2.iter()) {
923                    if !self.types_compatible(t1, t2) {
924                        return false;
925                    }
926                }
927
928                return self.types_compatible(r1, r2);
929            }
930
931            _ => {}
932        }
933
934        self.types_equal(expected, actual)
935    }
936
937    fn unify_with_bounds(&self, expected: &Type, actual: &Type) -> Result<()> {
938        if let TypeKind::Generic(type_param) = &expected.kind {
939            if let Some(trait_names) = self.current_trait_bounds.get(type_param) {
940                for trait_name in trait_names {
941                    if !self.env.type_implements_trait(actual, trait_name) {
942                        return Err(self.type_error(format!(
943                            "Type '{}' does not implement required trait '{}'",
944                            actual, trait_name
945                        )));
946                    }
947                }
948
949                return Ok(());
950            }
951
952            return Ok(());
953        }
954
955        self.unify(expected, actual)
956    }
957}