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}