1use crate::ast::*;
8use crate::span::Span;
9use std::cell::RefCell;
10use std::collections::HashMap;
11use std::fmt;
12use std::rc::Rc;
13
14#[derive(Debug, Clone, PartialEq)]
16pub enum Type {
17 Unit,
19 Bool,
20 Int(IntSize),
21 Float(FloatSize),
22 Char,
23 Str,
24
25 Array {
27 element: Box<Type>,
28 size: Option<usize>,
29 },
30 Slice(Box<Type>),
31 Tuple(Vec<Type>),
32
33 Named {
35 name: String,
36 generics: Vec<Type>,
37 },
38
39 Function {
41 params: Vec<Type>,
42 return_type: Box<Type>,
43 is_async: bool,
44 },
45
46 Ref {
48 lifetime: Option<String>,
49 mutable: bool,
50 inner: Box<Type>,
51 },
52 Ptr {
53 mutable: bool,
54 inner: Box<Type>,
55 },
56
57 Evidential {
59 inner: Box<Type>,
60 evidence: EvidenceLevel,
61 },
62
63 Cycle {
65 modulus: usize,
66 },
67
68 Simd {
70 element: Box<Type>,
71 lanes: u8,
72 },
73
74 Atomic(Box<Type>),
76
77 Var(TypeVar),
79
80 Error,
82
83 Never,
85
86 Lifetime(String),
88
89 TraitObject(Vec<Type>),
91
92 Hrtb {
94 lifetimes: Vec<String>,
95 bound: Box<Type>,
96 },
97 InlineStruct {
99 fields: Vec<(String, Type)>,
100 },
101 ImplTrait(Vec<Type>),
103 InlineEnum(Vec<String>),
105 AssocTypeBinding {
107 name: String,
108 ty: Box<Type>,
109 },
110}
111
112#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub enum IntSize {
115 I8,
116 I16,
117 I32,
118 I64,
119 I128,
120 U8,
121 U16,
122 U32,
123 U64,
124 U128,
125 ISize,
126 USize,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub enum FloatSize {
132 F32,
133 F64,
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
144pub enum EvidenceLevel {
145 Known, Uncertain, Reported, Paradox, }
154
155impl EvidenceLevel {
156 pub fn join(self, other: Self) -> Self {
158 std::cmp::max(self, other)
159 }
160
161 pub fn meet(self, other: Self) -> Self {
163 std::cmp::min(self, other)
164 }
165
166 pub fn from_ast(e: Evidentiality) -> Self {
168 match e {
169 Evidentiality::Known => EvidenceLevel::Known,
170 Evidentiality::Uncertain | Evidentiality::Predicted => EvidenceLevel::Uncertain,
171 Evidentiality::Reported => EvidenceLevel::Reported,
172 Evidentiality::Paradox => EvidenceLevel::Paradox,
173 }
174 }
175
176 pub fn symbol(&self) -> &'static str {
178 match self {
179 EvidenceLevel::Known => "!",
180 EvidenceLevel::Uncertain => "?",
181 EvidenceLevel::Reported => "~",
182 EvidenceLevel::Paradox => "‽",
183 }
184 }
185
186 pub fn name(&self) -> &'static str {
188 match self {
189 EvidenceLevel::Known => "known",
190 EvidenceLevel::Uncertain => "uncertain",
191 EvidenceLevel::Reported => "reported",
192 EvidenceLevel::Paradox => "paradox",
193 }
194 }
195
196 pub fn satisfies(self, required: Self) -> bool {
204 self <= required
207 }
208}
209
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
212pub struct TypeVar(pub u32);
213
214#[derive(Debug, Clone)]
216pub struct TypeError {
217 pub message: String,
218 pub span: Option<Span>,
219 pub notes: Vec<String>,
220}
221
222impl TypeError {
223 pub fn new(message: impl Into<String>) -> Self {
224 Self {
225 message: message.into(),
226 span: None,
227 notes: Vec::new(),
228 }
229 }
230
231 pub fn with_span(mut self, span: Span) -> Self {
232 self.span = Some(span);
233 self
234 }
235
236 pub fn with_note(mut self, note: impl Into<String>) -> Self {
237 self.notes.push(note.into());
238 self
239 }
240}
241
242impl fmt::Display for TypeError {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 write!(f, "{}", self.message)?;
245 if let Some(span) = self.span {
246 write!(f, " at {}", span)?;
247 }
248 for note in &self.notes {
249 write!(f, "\n note: {}", note)?;
250 }
251 Ok(())
252 }
253}
254
255#[derive(Debug, Clone)]
257pub struct TypeEnv {
258 bindings: HashMap<String, (Type, EvidenceLevel)>,
260 parent: Option<Rc<RefCell<TypeEnv>>>,
262}
263
264impl TypeEnv {
265 pub fn new() -> Self {
266 Self {
267 bindings: HashMap::new(),
268 parent: None,
269 }
270 }
271
272 pub fn with_parent(parent: Rc<RefCell<TypeEnv>>) -> Self {
273 Self {
274 bindings: HashMap::new(),
275 parent: Some(parent),
276 }
277 }
278
279 pub fn define(&mut self, name: String, ty: Type, evidence: EvidenceLevel) {
281 self.bindings.insert(name, (ty, evidence));
282 }
283
284 pub fn lookup(&self, name: &str) -> Option<(Type, EvidenceLevel)> {
286 if let Some(binding) = self.bindings.get(name) {
287 Some(binding.clone())
288 } else if let Some(ref parent) = self.parent {
289 parent.borrow().lookup(name)
290 } else {
291 None
292 }
293 }
294}
295
296impl Default for TypeEnv {
297 fn default() -> Self {
298 Self::new()
299 }
300}
301
302#[derive(Debug, Clone)]
304pub enum TypeDef {
305 Struct {
306 generics: Vec<String>,
307 fields: Vec<(String, Type)>,
308 },
309 Enum {
310 generics: Vec<String>,
311 variants: Vec<(String, Option<Vec<Type>>)>,
312 },
313 Alias {
314 generics: Vec<String>,
315 target: Type,
316 },
317}
318
319pub struct TypeChecker {
321 env: Rc<RefCell<TypeEnv>>,
323 types: HashMap<String, TypeDef>,
325 functions: HashMap<String, Type>,
327 impl_methods: HashMap<String, HashMap<String, Type>>,
329 current_self_type: Option<String>,
331 current_generics: HashMap<String, Type>,
333 expected_return_type: Option<Type>,
335 next_var: u32,
337 substitutions: HashMap<TypeVar, Type>,
339 errors: Vec<TypeError>,
341}
342
343impl TypeChecker {
344 pub fn new() -> Self {
345 let mut checker = Self {
346 env: Rc::new(RefCell::new(TypeEnv::new())),
347 types: HashMap::new(),
348 functions: HashMap::new(),
349 impl_methods: HashMap::new(),
350 current_self_type: None,
351 current_generics: HashMap::new(),
352 expected_return_type: None,
353 next_var: 0,
354 substitutions: HashMap::new(),
355 errors: Vec::new(),
356 };
357
358 checker.register_builtins();
360 checker
361 }
362
363 fn register_builtins(&mut self) {
364 let func = |params: Vec<Type>, ret: Type| Type::Function {
366 params,
367 return_type: Box::new(ret),
368 is_async: false,
369 };
370
371 let any = Type::Var(TypeVar(9999)); self.functions
379 .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
380 self.functions
381 .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
382 self.functions
383 .insert("input".to_string(), func(vec![], Type::Str));
384 self.functions
385 .insert("input_line".to_string(), func(vec![], Type::Str));
386
387 self.functions
391 .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
392 self.functions.insert(
393 "len".to_string(),
394 func(vec![any.clone()], Type::Int(IntSize::USize)),
395 );
396
397 self.functions
401 .insert("str".to_string(), func(vec![any.clone()], Type::Str));
402 self.functions
403 .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
404 self.functions
405 .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
406 self.functions
407 .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
408 self.functions.insert(
409 "split".to_string(),
410 func(
411 vec![Type::Str, Type::Str],
412 Type::Array {
413 element: Box::new(Type::Str),
414 size: None,
415 },
416 ),
417 );
418 self.functions.insert(
419 "join".to_string(),
420 func(
421 vec![
422 Type::Array {
423 element: Box::new(Type::Str),
424 size: None,
425 },
426 Type::Str,
427 ],
428 Type::Str,
429 ),
430 );
431 self.functions.insert(
432 "contains".to_string(),
433 func(vec![Type::Str, Type::Str], Type::Bool),
434 );
435 self.functions.insert(
436 "starts_with".to_string(),
437 func(vec![Type::Str, Type::Str], Type::Bool),
438 );
439 self.functions.insert(
440 "ends_with".to_string(),
441 func(vec![Type::Str, Type::Str], Type::Bool),
442 );
443 self.functions.insert(
444 "replace".to_string(),
445 func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
446 );
447 self.functions.insert(
448 "char_at".to_string(),
449 func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
450 );
451 self.functions.insert(
452 "substring".to_string(),
453 func(
454 vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
455 Type::Str,
456 ),
457 );
458
459 let f64_ty = Type::Float(FloatSize::F64);
463 let i64_ty = Type::Int(IntSize::I64);
464
465 self.functions.insert(
466 "abs".to_string(),
467 func(vec![f64_ty.clone()], f64_ty.clone()),
468 );
469 self.functions.insert(
470 "sqrt".to_string(),
471 func(vec![f64_ty.clone()], f64_ty.clone()),
472 );
473 self.functions.insert(
474 "sin".to_string(),
475 func(vec![f64_ty.clone()], f64_ty.clone()),
476 );
477 self.functions.insert(
478 "cos".to_string(),
479 func(vec![f64_ty.clone()], f64_ty.clone()),
480 );
481 self.functions.insert(
482 "tan".to_string(),
483 func(vec![f64_ty.clone()], f64_ty.clone()),
484 );
485 self.functions.insert(
486 "floor".to_string(),
487 func(vec![f64_ty.clone()], f64_ty.clone()),
488 );
489 self.functions.insert(
490 "ceil".to_string(),
491 func(vec![f64_ty.clone()], f64_ty.clone()),
492 );
493 self.functions.insert(
494 "round".to_string(),
495 func(vec![f64_ty.clone()], f64_ty.clone()),
496 );
497 self.functions.insert(
498 "pow".to_string(),
499 func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
500 );
501 self.functions.insert(
502 "log".to_string(),
503 func(vec![f64_ty.clone()], f64_ty.clone()),
504 );
505 self.functions.insert(
506 "exp".to_string(),
507 func(vec![f64_ty.clone()], f64_ty.clone()),
508 );
509 self.functions.insert(
510 "min".to_string(),
511 func(vec![any.clone(), any.clone()], any.clone()),
512 );
513 self.functions.insert(
514 "max".to_string(),
515 func(vec![any.clone(), any.clone()], any.clone()),
516 );
517
518 self.functions
522 .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
523 self.functions
524 .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
525 self.functions.insert(
526 "push".to_string(),
527 func(vec![any.clone(), any.clone()], Type::Unit),
528 );
529 self.functions
530 .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
531 self.functions
532 .insert("first".to_string(), func(vec![any.clone()], any.clone()));
533 self.functions
534 .insert("last".to_string(), func(vec![any.clone()], any.clone()));
535 self.functions
536 .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
537 self.functions
538 .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
539 self.functions.insert(
540 "range".to_string(),
541 func(
542 vec![i64_ty.clone(), i64_ty.clone()],
543 Type::Array {
544 element: Box::new(i64_ty.clone()),
545 size: None,
546 },
547 ),
548 );
549
550 self.functions
554 .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
555 self.functions.insert(
556 "assert_eq".to_string(),
557 func(vec![any.clone(), any.clone()], Type::Unit),
558 );
559 self.functions.insert(
560 "assert_ne".to_string(),
561 func(vec![any.clone(), any.clone()], Type::Unit),
562 );
563 self.functions.insert(
564 "assert_lt".to_string(),
565 func(vec![any.clone(), any.clone()], Type::Unit),
566 );
567 self.functions.insert(
568 "assert_le".to_string(),
569 func(vec![any.clone(), any.clone()], Type::Unit),
570 );
571 self.functions.insert(
572 "assert_gt".to_string(),
573 func(vec![any.clone(), any.clone()], Type::Unit),
574 );
575 self.functions.insert(
576 "assert_ge".to_string(),
577 func(vec![any.clone(), any.clone()], Type::Unit),
578 );
579 self.functions.insert(
580 "assert_true".to_string(),
581 func(vec![Type::Bool], Type::Unit),
582 );
583 self.functions.insert(
584 "assert_false".to_string(),
585 func(vec![Type::Bool], Type::Unit),
586 );
587 self.functions.insert(
588 "assert_null".to_string(),
589 func(vec![any.clone()], Type::Unit),
590 );
591 self.functions.insert(
592 "assert_not_null".to_string(),
593 func(vec![any.clone()], Type::Unit),
594 );
595 self.functions.insert(
596 "assert_contains".to_string(),
597 func(vec![any.clone(), any.clone()], Type::Unit),
598 );
599 self.functions.insert(
600 "assert_len".to_string(),
601 func(vec![any.clone(), i64_ty.clone()], Type::Unit),
602 );
603
604 self.functions
608 .insert("random".to_string(), func(vec![], f64_ty.clone()));
609 self.functions.insert(
610 "random_int".to_string(),
611 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
612 );
613 self.functions
614 .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
615
616 self.functions
620 .insert("now".to_string(), func(vec![], f64_ty.clone()));
621 self.functions
622 .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
623
624 self.functions
628 .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
629 self.functions
630 .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
631 self.functions
632 .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
633
634 self.functions
638 .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
639 self.functions
640 .insert("todo".to_string(), func(vec![], Type::Never));
641 self.functions
642 .insert("unreachable".to_string(), func(vec![], Type::Never));
643
644 self.functions.insert(
649 "known".to_string(),
650 func(
651 vec![any.clone()],
652 Type::Evidential {
653 inner: Box::new(any.clone()),
654 evidence: EvidenceLevel::Known,
655 },
656 ),
657 );
658 self.functions.insert(
660 "uncertain".to_string(),
661 func(
662 vec![any.clone()],
663 Type::Evidential {
664 inner: Box::new(any.clone()),
665 evidence: EvidenceLevel::Uncertain,
666 },
667 ),
668 );
669 self.functions.insert(
671 "reported".to_string(),
672 func(
673 vec![any.clone()],
674 Type::Evidential {
675 inner: Box::new(any.clone()),
676 evidence: EvidenceLevel::Reported,
677 },
678 ),
679 );
680 self.functions.insert(
682 "evidence_of".to_string(),
683 func(vec![any.clone()], Type::Str),
684 );
685 self.functions.insert(
687 "validate".to_string(),
688 func(
689 vec![any.clone()],
690 Type::Evidential {
691 inner: Box::new(any.clone()),
692 evidence: EvidenceLevel::Uncertain,
693 },
694 ),
695 );
696 self.functions.insert(
698 "verify".to_string(),
699 func(
700 vec![any.clone()],
701 Type::Evidential {
702 inner: Box::new(any.clone()),
703 evidence: EvidenceLevel::Known,
704 },
705 ),
706 );
707
708 self.functions.insert(
713 "freq".to_string(),
714 func(vec![i64_ty.clone()], f64_ty.clone()),
715 );
716 self.functions.insert(
718 "octave".to_string(),
719 func(vec![i64_ty.clone()], i64_ty.clone()),
720 );
721 self.functions.insert(
723 "pitch_class".to_string(),
724 func(vec![i64_ty.clone()], i64_ty.clone()),
725 );
726 self.functions.insert(
728 "mod_cycle".to_string(),
729 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
730 );
731 }
732
733 fn fresh_var(&mut self) -> Type {
735 let var = TypeVar(self.next_var);
736 self.next_var += 1;
737 Type::Var(var)
738 }
739
740 fn type_contains_var(&self, ty: &Type) -> bool {
742 match ty {
743 Type::Var(v) => !self.substitutions.contains_key(v),
744 Type::Array { element, .. } => self.type_contains_var(element.as_ref()),
745 Type::Slice(inner) => self.type_contains_var(inner.as_ref()),
746 Type::Tuple(elems) => elems.iter().any(|e| self.type_contains_var(e)),
747 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => {
748 self.type_contains_var(inner.as_ref())
749 }
750 Type::Function {
751 params,
752 return_type,
753 ..
754 } => {
755 params.iter().any(|p| self.type_contains_var(p))
756 || self.type_contains_var(return_type.as_ref())
757 }
758 Type::Named { generics, .. } => generics.iter().any(|g| self.type_contains_var(g)),
759 Type::Evidential { inner, .. } => self.type_contains_var(inner.as_ref()),
760 Type::Atomic(inner) => self.type_contains_var(inner.as_ref()),
761 Type::Simd { element, .. } => self.type_contains_var(element.as_ref()),
762 _ => false,
763 }
764 }
765
766 fn occurs_in(&self, v: &TypeVar, t: &Type) -> bool {
769 match t {
770 Type::Var(w) => {
771 if v == w {
772 return true;
773 }
774 if let Some(resolved) = self.substitutions.get(w) {
775 self.occurs_in(v, resolved)
776 } else {
777 false
778 }
779 }
780 Type::Array { element, .. } => self.occurs_in(v, element),
781 Type::Slice(inner) => self.occurs_in(v, inner),
782 Type::Tuple(elems) => elems.iter().any(|e| self.occurs_in(v, e)),
783 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.occurs_in(v, inner),
784 Type::Function {
785 params,
786 return_type,
787 ..
788 } => params.iter().any(|p| self.occurs_in(v, p)) || self.occurs_in(v, return_type),
789 Type::Named { generics, .. } => generics.iter().any(|g| self.occurs_in(v, g)),
790 Type::Evidential { inner, .. } => self.occurs_in(v, inner),
791 Type::Atomic(inner) => self.occurs_in(v, inner),
792 Type::Simd { element, .. } => self.occurs_in(v, element),
793 _ => false,
794 }
795 }
796
797 fn freshen(&mut self, ty: &Type) -> Type {
800 let mut mapping = std::collections::HashMap::new();
801 self.freshen_inner(ty, &mut mapping)
802 }
803
804 fn freshen_inner(
805 &mut self,
806 ty: &Type,
807 mapping: &mut std::collections::HashMap<u32, Type>,
808 ) -> Type {
809 match ty {
810 Type::Var(TypeVar(id)) => {
811 if let Some(fresh) = mapping.get(id) {
812 fresh.clone()
813 } else {
814 let fresh = self.fresh_var();
815 mapping.insert(*id, fresh.clone());
816 fresh
817 }
818 }
819 Type::Array { element, size } => Type::Array {
820 element: Box::new(self.freshen_inner(element, mapping)),
821 size: *size,
822 },
823 Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
824 Type::Ref {
825 lifetime,
826 mutable,
827 inner,
828 } => Type::Ref {
829 lifetime: lifetime.clone(),
830 mutable: *mutable,
831 inner: Box::new(self.freshen_inner(inner, mapping)),
832 },
833 Type::Tuple(elems) => Type::Tuple(
834 elems
835 .iter()
836 .map(|e| self.freshen_inner(e, mapping))
837 .collect(),
838 ),
839 Type::Function {
840 params,
841 return_type,
842 is_async,
843 } => Type::Function {
844 params: params
845 .iter()
846 .map(|p| self.freshen_inner(p, mapping))
847 .collect(),
848 return_type: Box::new(self.freshen_inner(return_type, mapping)),
849 is_async: *is_async,
850 },
851 Type::Evidential { inner, evidence } => Type::Evidential {
852 inner: Box::new(self.freshen_inner(inner, mapping)),
853 evidence: *evidence,
854 },
855 Type::Named { name, generics } => Type::Named {
856 name: name.clone(),
857 generics: generics
858 .iter()
859 .map(|g| self.freshen_inner(g, mapping))
860 .collect(),
861 },
862 _ => ty.clone(),
864 }
865 }
866
867 fn push_scope(&mut self) {
869 let new_env = TypeEnv::with_parent(self.env.clone());
870 self.env = Rc::new(RefCell::new(new_env));
871 }
872
873 fn pop_scope(&mut self) {
875 let parent = self.env.borrow().parent.clone();
876 if let Some(p) = parent {
877 self.env = p;
878 }
879 }
880
881 fn error(&mut self, err: TypeError) {
883 self.errors.push(err);
884 }
885
886 fn check_evidence(
889 &mut self,
890 expected: EvidenceLevel,
891 actual: EvidenceLevel,
892 context: &str,
893 ) -> bool {
894 if actual.satisfies(expected) {
895 true
896 } else {
897 let mut err = TypeError::new(format!(
898 "evidence mismatch {}: expected {} ({}), found {} ({})",
899 context,
900 expected.name(),
901 expected.symbol(),
902 actual.name(),
903 actual.symbol(),
904 ));
905
906 match (expected, actual) {
908 (EvidenceLevel::Known, EvidenceLevel::Reported) => {
909 err = err.with_note(
910 "reported data (~) cannot be used where known data (!) is required",
911 );
912 err = err.with_note(
913 "help: use |validate!{...} to verify and promote evidence level",
914 );
915 }
916 (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
917 err = err.with_note(
918 "uncertain data (?) cannot be used where known data (!) is required",
919 );
920 err = err.with_note(
921 "help: use pattern matching or unwrap to handle the uncertainty",
922 );
923 }
924 (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
925 err = err.with_note(
926 "reported data (~) cannot be used where uncertain data (?) is required",
927 );
928 err = err.with_note("help: use |validate?{...} to verify external data");
929 }
930 _ => {
931 err = err.with_note(format!(
932 "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
933 ));
934 }
935 }
936
937 self.error(err);
938 false
939 }
940 }
941
942 fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
944 match ty {
945 Type::Evidential { evidence, .. } => *evidence,
946 _ => EvidenceLevel::Known,
947 }
948 }
949
950 pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
952 for item in &file.items {
954 self.collect_type_def(&item.node);
955 }
956
957 for item in &file.items {
959 self.collect_fn_sig(&item.node);
960 }
961
962 for item in &file.items {
964 self.check_item(&item.node);
965 }
966
967 if self.errors.is_empty() {
968 Ok(())
969 } else {
970 Err(std::mem::take(&mut self.errors))
971 }
972 }
973
974 fn collect_type_def(&mut self, item: &Item) {
976 match item {
977 Item::Struct(s) => {
978 let generics = s
979 .generics
980 .as_ref()
981 .map(|g| {
982 g.params
983 .iter()
984 .filter_map(|p| {
985 if let GenericParam::Type { name, .. } = p {
986 Some(name.name.clone())
987 } else {
988 None
989 }
990 })
991 .collect()
992 })
993 .unwrap_or_default();
994
995 let fields = match &s.fields {
996 StructFields::Named(fs) => fs
997 .iter()
998 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
999 .collect(),
1000 StructFields::Tuple(ts) => ts
1001 .iter()
1002 .enumerate()
1003 .map(|(i, t)| (i.to_string(), self.convert_type(t)))
1004 .collect(),
1005 StructFields::Unit => vec![],
1006 };
1007
1008 if self.types.contains_key(&s.name.name) {
1010 self.error(TypeError::new(format!(
1011 "duplicate type definition: '{}'",
1012 s.name.name
1013 )));
1014 }
1015 self.types
1016 .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
1017 }
1018 Item::Enum(e) => {
1019 let generics = e
1020 .generics
1021 .as_ref()
1022 .map(|g| {
1023 g.params
1024 .iter()
1025 .filter_map(|p| {
1026 if let GenericParam::Type { name, .. } = p {
1027 Some(name.name.clone())
1028 } else {
1029 None
1030 }
1031 })
1032 .collect()
1033 })
1034 .unwrap_or_default();
1035
1036 let variants = e
1037 .variants
1038 .iter()
1039 .map(|v| {
1040 let fields = match &v.fields {
1041 StructFields::Tuple(ts) => {
1042 Some(ts.iter().map(|t| self.convert_type(t)).collect())
1043 }
1044 StructFields::Named(fs) => {
1045 Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
1046 }
1047 StructFields::Unit => None,
1048 };
1049 (v.name.name.clone(), fields)
1050 })
1051 .collect();
1052
1053 self.types
1054 .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
1055 }
1056 Item::TypeAlias(t) => {
1057 let generics = t
1058 .generics
1059 .as_ref()
1060 .map(|g| {
1061 g.params
1062 .iter()
1063 .filter_map(|p| {
1064 if let GenericParam::Type { name, .. } = p {
1065 Some(name.name.clone())
1066 } else {
1067 None
1068 }
1069 })
1070 .collect()
1071 })
1072 .unwrap_or_default();
1073
1074 let target = self.convert_type(&t.ty);
1075 self.types
1076 .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
1077 }
1078 _ => {}
1079 }
1080 }
1081
1082 fn collect_fn_sig(&mut self, item: &Item) {
1084 match item {
1085 Item::Function(f) => {
1086 let params: Vec<Type> = f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1087
1088 let return_type = f
1089 .return_type
1090 .as_ref()
1091 .map(|t| self.convert_type(t))
1092 .unwrap_or(Type::Unit);
1093
1094 let fn_type = Type::Function {
1095 params,
1096 return_type: Box::new(return_type),
1097 is_async: f.is_async,
1098 };
1099
1100 if self.functions.contains_key(&f.name.name) {
1102 self.error(TypeError::new(format!(
1103 "duplicate function definition: '{}'",
1104 f.name.name
1105 )));
1106 }
1107 self.functions.insert(f.name.name.clone(), fn_type);
1108 }
1109 Item::Impl(impl_block) => {
1110 let type_name = self.type_path_to_name(&impl_block.self_ty);
1112
1113 self.current_self_type = Some(type_name.clone());
1115
1116 if let Some(ref generics) = impl_block.generics {
1118 for param in &generics.params {
1119 if let crate::ast::GenericParam::Type { name, .. } = param {
1120 let type_var = self.fresh_var();
1121 self.current_generics.insert(name.name.clone(), type_var);
1122 }
1123 }
1124 }
1125
1126 for impl_item in &impl_block.items {
1128 if let crate::ast::ImplItem::Function(f) = impl_item {
1129 let params: Vec<Type> =
1130 f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1131
1132 let return_type = f
1133 .return_type
1134 .as_ref()
1135 .map(|t| self.convert_type(t))
1136 .unwrap_or(Type::Unit);
1137
1138 let fn_type = Type::Function {
1139 params,
1140 return_type: Box::new(return_type),
1141 is_async: f.is_async,
1142 };
1143
1144 self.impl_methods
1146 .entry(type_name.clone())
1147 .or_insert_with(HashMap::new)
1148 .insert(f.name.name.clone(), fn_type);
1149 }
1150 }
1151
1152 self.current_self_type = None;
1154 self.current_generics.clear();
1155 }
1156 _ => {}
1157 }
1158 }
1159
1160 fn type_path_to_name(&self, ty: &crate::ast::TypeExpr) -> String {
1162 match ty {
1163 crate::ast::TypeExpr::Path(path) => path
1164 .segments
1165 .iter()
1166 .map(|s| s.ident.name.clone())
1167 .collect::<Vec<_>>()
1168 .join("::"),
1169 _ => "Unknown".to_string(),
1170 }
1171 }
1172
1173 fn check_item(&mut self, item: &Item) {
1175 match item {
1176 Item::Function(f) => self.check_function(f),
1177 Item::Const(c) => {
1178 let declared = self.convert_type(&c.ty);
1179 let inferred = self.infer_expr(&c.value);
1180 if !self.unify(&declared, &inferred) {
1181 self.error(
1182 TypeError::new(format!(
1183 "type mismatch in const '{}': expected {:?}, found {:?}",
1184 c.name.name, declared, inferred
1185 ))
1186 .with_span(c.name.span),
1187 );
1188 }
1189 }
1190 Item::Static(s) => {
1191 let declared = self.convert_type(&s.ty);
1192 let inferred = self.infer_expr(&s.value);
1193 if !self.unify(&declared, &inferred) {
1194 self.error(
1195 TypeError::new(format!(
1196 "type mismatch in static '{}': expected {:?}, found {:?}",
1197 s.name.name, declared, inferred
1198 ))
1199 .with_span(s.name.span),
1200 );
1201 }
1202 }
1203 Item::Impl(impl_block) => {
1204 let type_name = self.type_path_to_name(&impl_block.self_ty);
1206 self.current_self_type = Some(type_name);
1207
1208 if let Some(ref generics) = impl_block.generics {
1210 for param in &generics.params {
1211 if let crate::ast::GenericParam::Type { name, .. } = param {
1212 let type_var = self.fresh_var();
1213 self.current_generics.insert(name.name.clone(), type_var);
1214 }
1215 }
1216 }
1217
1218 for impl_item in &impl_block.items {
1220 if let crate::ast::ImplItem::Function(f) = impl_item {
1221 self.check_function(f);
1222 }
1223 }
1224
1225 self.current_self_type = None;
1227 self.current_generics.clear();
1228 }
1229 _ => {}
1230 }
1231 }
1232
1233 fn check_function(&mut self, func: &Function) {
1235 self.push_scope();
1236
1237 for param in &func.params {
1239 let ty = self.convert_type(¶m.ty);
1240 let type_evidence = self.get_evidence(&ty);
1243 let evidence = param
1244 .pattern
1245 .evidentiality()
1246 .map(EvidenceLevel::from_ast)
1247 .unwrap_or(type_evidence);
1248
1249 if let Some(name) = param.pattern.binding_name() {
1250 self.env.borrow_mut().define(name, ty, evidence);
1251 }
1252 }
1253
1254 let expected_return = func
1256 .return_type
1257 .as_ref()
1258 .map(|t| self.convert_type(t))
1259 .unwrap_or(Type::Unit);
1260 let old_return_type = self.expected_return_type.clone();
1261 self.expected_return_type = Some(expected_return.clone());
1262
1263 if let Some(ref body) = func.body {
1265 let body_type = self.check_block(body);
1266
1267 self.expected_return_type = old_return_type;
1269
1270 let expected_return = func
1272 .return_type
1273 .as_ref()
1274 .map(|t| self.convert_type(t))
1275 .unwrap_or(Type::Unit);
1276
1277 let _ = self.unify(&expected_return, &body_type);
1281
1282 let type_has_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1288 let name_evidence = func
1290 .name
1291 .evidentiality
1292 .as_ref()
1293 .map(|e| EvidenceLevel::from_ast(*e));
1294 let has_explicit_evidence = type_has_evidence || name_evidence.is_some();
1295 let actual_evidence = self.get_evidence(&body_type);
1296
1297 if has_explicit_evidence {
1298 if name_evidence.is_none() {
1302 let expected_evidence = self.get_evidence(&expected_return);
1303 self.check_evidence(
1304 expected_evidence,
1305 actual_evidence,
1306 &format!("in return type of '{}'", func.name.name),
1307 );
1308 }
1309 } else {
1311 if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1314 self.error(
1315 TypeError::new(format!(
1316 "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1317 func.name.name,
1318 actual_evidence.name(),
1319 actual_evidence.symbol(),
1320 ))
1321 .with_span(func.name.span)
1322 .with_note("help: add explicit evidence annotation to the return type")
1323 .with_note(format!(
1324 "example: fn {}(...) -> {}{} {{ ... }}",
1325 func.name.name,
1326 expected_return,
1327 actual_evidence.symbol()
1328 )),
1329 );
1330 }
1331 }
1333 }
1334
1335 self.pop_scope();
1336 }
1337
1338 fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1340 match ty {
1341 Some(TypeExpr::Evidential { .. }) => true,
1342 Some(TypeExpr::Reference { inner, .. })
1343 | Some(TypeExpr::Pointer { inner, .. })
1344 | Some(TypeExpr::Slice(inner))
1345 | Some(TypeExpr::Array { element: inner, .. }) => {
1346 self.type_has_explicit_evidence(Some(inner.as_ref()))
1347 }
1348 Some(TypeExpr::Tuple(elements)) => elements
1349 .iter()
1350 .any(|e| self.type_has_explicit_evidence(Some(e))),
1351 _ => false,
1352 }
1353 }
1354
1355 fn check_block(&mut self, block: &Block) -> Type {
1357 self.push_scope();
1358
1359 let mut diverges = false;
1360 for stmt in &block.stmts {
1361 let stmt_ty = self.check_stmt(stmt);
1362 if matches!(stmt_ty, Type::Never) {
1363 diverges = true;
1364 }
1365 }
1366
1367 let result = if let Some(ref expr) = block.expr {
1368 self.infer_expr(expr)
1369 } else if diverges {
1370 Type::Never
1371 } else {
1372 Type::Unit
1373 };
1374
1375 self.pop_scope();
1376 result
1377 }
1378
1379 fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1381 match stmt {
1382 Stmt::Let { pattern, ty, init } => {
1383 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1384 let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1385
1386 let final_ty = match (&declared_ty, &init_ty) {
1387 (Some(d), Some(i)) => {
1388 if !self.unify(d, i) {
1389 let binding_name = pattern
1391 .binding_name()
1392 .unwrap_or_else(|| "<pattern>".to_string());
1393 let mut err = TypeError::new(format!(
1394 "type mismatch in let binding '{}': expected {:?}, found {:?}",
1395 binding_name, d, i
1396 ));
1397 if let Some(span) = pattern.binding_span() {
1398 err = err.with_span(span);
1399 }
1400 self.error(err);
1401 }
1402 d.clone()
1403 }
1404 (Some(d), None) => d.clone(),
1405 (None, Some(i)) => i.clone(),
1406 (None, None) => self.fresh_var(),
1407 };
1408
1409 let evidence = pattern
1415 .evidentiality()
1416 .map(EvidenceLevel::from_ast)
1417 .unwrap_or_else(|| {
1418 init_ty
1420 .as_ref()
1421 .map(|ty| self.get_evidence(ty))
1422 .unwrap_or(EvidenceLevel::Known)
1423 });
1424
1425 if let Some(name) = pattern.binding_name() {
1426 self.env.borrow_mut().define(name, final_ty, evidence);
1427 }
1428 Type::Unit
1429 }
1430 Stmt::LetElse {
1431 pattern,
1432 ty,
1433 init,
1434 else_branch,
1435 } => {
1436 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1438 let init_ty = self.infer_expr(init);
1439 let evidence = pattern
1441 .evidentiality()
1442 .map(EvidenceLevel::from_ast)
1443 .unwrap_or_else(|| self.get_evidence(&init_ty));
1444 let final_ty = declared_ty.unwrap_or(init_ty);
1445 self.infer_expr(else_branch);
1447 if let Some(name) = pattern.binding_name() {
1448 self.env.borrow_mut().define(name, final_ty, evidence);
1449 }
1450 Type::Unit
1451 }
1452 Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1453 Stmt::Item(item) => {
1454 self.check_item(item);
1455 Type::Unit
1456 }
1457 }
1458 }
1459
1460 pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1462 match expr {
1463 Expr::Literal(lit) => self.infer_literal(lit),
1464
1465 Expr::Path(path) => {
1466 if path.segments.len() == 1 {
1467 let name = &path.segments[0].ident.name;
1468 if let Some((ty, _)) = self.env.borrow().lookup(name) {
1469 return ty;
1470 }
1471 if let Some(ty) = self.functions.get(name).cloned() {
1472 return self.freshen(&ty);
1474 }
1475 } else if path.segments.len() == 2 {
1476 let type_name = &path.segments[0].ident.name;
1478 let method_name = &path.segments[1].ident.name;
1479
1480 if let Some(methods) = self.impl_methods.get(type_name) {
1482 if let Some(ty) = methods.get(method_name) {
1483 let ty_cloned = ty.clone();
1484 return self.freshen(&ty_cloned);
1485 }
1486 }
1487
1488 if let Some(TypeDef::Enum { variants, .. }) = self.types.get(type_name) {
1490 for (variant_name, _variant_fields) in variants {
1491 if variant_name == method_name {
1492 return Type::Named {
1494 name: type_name.clone(),
1495 generics: vec![],
1496 };
1497 }
1498 }
1499 }
1500 }
1501 self.fresh_var()
1505 }
1506
1507 Expr::Binary { left, op, right } => {
1508 let lt = self.infer_expr(left);
1509 let rt = self.infer_expr(right);
1510 self.infer_binary_op(op, <, &rt)
1511 }
1512
1513 Expr::Unary { op, expr } => {
1514 let inner = self.infer_expr(expr);
1515 self.infer_unary_op(op, &inner)
1516 }
1517
1518 Expr::Call { func, args } => {
1519 let fn_type = self.infer_expr(func);
1520 let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1521
1522 if let Type::Function {
1523 params,
1524 return_type,
1525 ..
1526 } = fn_type
1527 {
1528 if params.len() != arg_types.len() {
1530 self.error(TypeError::new(format!(
1531 "expected {} arguments, found {}",
1532 params.len(),
1533 arg_types.len()
1534 )));
1535 }
1536
1537 for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1539 if !self.unify(param, arg) {
1541 let is_numeric_coercion = Self::is_numeric_coercion(param, arg);
1543 if !matches!(param, Type::Var(_))
1545 && !matches!(arg, Type::Var(_))
1546 && !is_numeric_coercion
1547 {
1548 self.error(TypeError::new(format!(
1549 "type mismatch in argument {}: expected {}, found {}",
1550 i + 1,
1551 param,
1552 arg
1553 )));
1554 }
1555 }
1556
1557 if !matches!(param, Type::Var(_)) {
1561 let expected_evidence = self.get_evidence(param);
1562 let actual_evidence = self.get_evidence(arg);
1563 self.check_evidence(
1564 expected_evidence,
1565 actual_evidence,
1566 &format!("in argument {}", i + 1),
1567 );
1568 }
1569 }
1570
1571 *return_type
1572 } else if let Type::Var(_) = &fn_type {
1573 let result_ty = self.fresh_var();
1576 let inferred_fn = Type::Function {
1577 params: arg_types,
1578 return_type: Box::new(result_ty.clone()),
1579 is_async: false,
1580 };
1581 self.unify(&fn_type, &inferred_fn);
1582 result_ty
1583 } else {
1584 self.fresh_var()
1586 }
1587 }
1588
1589 Expr::Array(elements) => {
1590 if elements.is_empty() {
1591 Type::Array {
1592 element: Box::new(self.fresh_var()),
1593 size: Some(0),
1594 }
1595 } else {
1596 let elem_ty = self.infer_expr(&elements[0]);
1597 for elem in &elements[1..] {
1598 let t = self.infer_expr(elem);
1599 if !self.unify(&elem_ty, &t) {
1600 self.error(TypeError::new("array elements must have same type"));
1601 }
1602 }
1603 Type::Array {
1604 element: Box::new(elem_ty),
1605 size: Some(elements.len()),
1606 }
1607 }
1608 }
1609
1610 Expr::Tuple(elements) => {
1611 Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1612 }
1613
1614 Expr::Block(block) => self.check_block(block),
1615
1616 Expr::If {
1617 condition,
1618 then_branch,
1619 else_branch,
1620 } => {
1621 let cond_ty = self.infer_expr(condition);
1622 if !self.unify(&Type::Bool, &cond_ty) {
1623 self.error(TypeError::new("if condition must be bool"));
1624 }
1625
1626 let then_ty = self.check_block(then_branch);
1627
1628 if let Some(else_expr) = else_branch {
1629 let else_ty = match else_expr.as_ref() {
1631 Expr::Block(block) => self.check_block(block),
1632 other => self.infer_expr(other),
1633 };
1634 let _ = self.unify(&then_ty, &else_ty);
1637
1638 let then_ev = self.get_evidence(&then_ty);
1643 let else_ev = self.get_evidence(&else_ty);
1644 let joined_ev = then_ev.join(else_ev);
1645
1646 let (inner_ty, _) = self.strip_evidence(&then_ty);
1647 if joined_ev > EvidenceLevel::Known {
1648 Type::Evidential {
1649 inner: Box::new(inner_ty),
1650 evidence: joined_ev,
1651 }
1652 } else {
1653 inner_ty
1654 }
1655 } else {
1656 Type::Unit
1657 }
1658 }
1659
1660 Expr::While {
1661 condition, body, ..
1662 } => {
1663 let cond_ty = self.infer_expr(condition);
1664 if !self.unify(&Type::Bool, &cond_ty) {
1665 self.error(TypeError::new("while condition must be bool"));
1666 }
1667 self.check_block(body);
1668 Type::Unit
1669 }
1670
1671 Expr::Loop { body, .. } => {
1672 self.check_block(body);
1673 Type::Unit
1674 }
1675
1676 Expr::For {
1677 pattern: _,
1678 iter,
1679 body,
1680 ..
1681 } => {
1682 let _ = self.infer_expr(iter);
1684 self.check_block(body);
1685 Type::Unit
1686 }
1687
1688 Expr::Pipe { expr, operations } => {
1689 let mut current = self.infer_expr(expr);
1690
1691 for op in operations {
1692 current = self.infer_pipe_op(op, ¤t);
1693 }
1694
1695 current
1696 }
1697
1698 Expr::Index { expr, index } => {
1699 let coll_ty = self.infer_expr(expr);
1700 let idx_ty = self.infer_expr(index);
1701
1702 match coll_ty {
1703 Type::Array { element, .. } | Type::Slice(element) => {
1704 if !matches!(idx_ty, Type::Int(_)) {
1705 self.error(TypeError::new("index must be integer"));
1706 }
1707 *element
1708 }
1709 _ => {
1710 self.fresh_var()
1712 }
1713 }
1714 }
1715
1716 Expr::Return(val) => {
1717 let actual_type = if let Some(e) = val {
1718 self.infer_expr(e)
1719 } else {
1720 Type::Unit
1721 };
1722
1723 if let Some(expected) = self.expected_return_type.clone() {
1725 if !self.unify(&expected, &actual_type) {
1726 self.error(TypeError::new(format!(
1727 "type mismatch in return: expected {}, found {}",
1728 expected, actual_type
1729 )));
1730 }
1731 }
1732
1733 Type::Never
1734 }
1735
1736 Expr::Evidential {
1738 expr,
1739 evidentiality,
1740 } => {
1741 let inner = self.infer_expr(expr);
1742 Type::Evidential {
1743 inner: Box::new(inner),
1744 evidence: EvidenceLevel::from_ast(*evidentiality),
1745 }
1746 }
1747
1748 Expr::Match { expr, arms } => {
1750 let scrutinee = self.infer_expr(expr);
1751 let scrutinee_ev = self.get_evidence(&scrutinee);
1752
1753 if arms.is_empty() {
1754 return Type::Never; }
1756
1757 let mut arm_types: Vec<Type> = Vec::new();
1759 let mut max_evidence = EvidenceLevel::Known;
1760
1761 for arm in arms {
1762 self.push_scope();
1763
1764 self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
1767
1768 if let Some(ref guard) = arm.guard {
1770 let guard_ty = self.infer_expr(guard);
1771 if !self.unify(&Type::Bool, &guard_ty) {
1772 self.error(TypeError::new("match guard must be bool"));
1773 }
1774 }
1775
1776 let body_ty = self.infer_expr(&arm.body);
1778 let body_ev = self.get_evidence(&body_ty);
1779
1780 max_evidence = max_evidence.join(body_ev);
1782 arm_types.push(body_ty);
1783
1784 self.pop_scope();
1785 }
1786
1787 let first_ty = &arm_types[0];
1790 for (_i, ty) in arm_types.iter().enumerate().skip(1) {
1791 let _ = self.unify(first_ty, ty);
1792 }
1793
1794 let (inner_ty, _) = self.strip_evidence(first_ty);
1796 if max_evidence > EvidenceLevel::Known {
1797 Type::Evidential {
1798 inner: Box::new(inner_ty),
1799 evidence: max_evidence,
1800 }
1801 } else {
1802 inner_ty
1803 }
1804 }
1805
1806 Expr::MethodCall {
1807 receiver,
1808 method,
1809 args,
1810 ..
1811 } => {
1812 let recv_ty = self.infer_expr(receiver);
1813 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
1814 let _arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1815
1816 let result_ty = match method.name.as_str() {
1818 "len" | "count" | "size" => Type::Int(IntSize::USize),
1820
1821 "is_empty" | "contains" | "starts_with" | "ends_with" | "is_some"
1823 | "is_none" | "is_ok" | "is_err" | "is_ascii" | "is_alphabetic"
1824 | "is_numeric" | "is_alphanumeric" | "is_whitespace" | "is_uppercase"
1825 | "is_lowercase" | "exists" | "is_file" | "is_dir" | "is_match" | "matches"
1826 | "eq" | "ne" | "lt" | "le" | "gt" | "ge" => Type::Bool,
1827
1828 "to_string" | "to_lowercase" | "to_uppercase" | "trim" | "trim_start"
1830 | "trim_end" | "to_owned" | "replace" | "replacen" | "repeat"
1831 | "to_string_lossy" => Type::Named {
1832 name: "String".to_string(),
1833 generics: vec![],
1834 },
1835
1836 "as_str" | "trim_matches" | "trim_start_matches" | "trim_end_matches"
1838 | "strip_prefix" | "strip_suffix" => Type::Ref {
1839 lifetime: None,
1840 mutable: false,
1841 inner: Box::new(Type::Str),
1842 },
1843
1844 "clone" | "cloned" | "copied" => recv_inner.clone(),
1846
1847 "unwrap" | "unwrap_or" | "unwrap_or_default" | "unwrap_or_else" | "expect"
1849 | "ok" | "err" => {
1850 if let Type::Named { name, generics } = &recv_inner {
1851 if (name == "Option" || name == "Result") && !generics.is_empty() {
1852 generics[0].clone()
1853 } else {
1854 self.fresh_var()
1855 }
1856 } else {
1857 self.fresh_var()
1858 }
1859 }
1860
1861 "collect" => self.fresh_var(),
1863
1864 "iter" | "into_iter" | "iter_mut" | "rev" | "skip" | "take" | "filter"
1866 | "map" | "filter_map" | "flat_map" | "enumerate" | "zip" | "chain"
1867 | "flatten" | "reverse" | "sorted" | "dedup" | "unique" | "peekable"
1868 | "fuse" | "cycle" | "step_by" | "take_while" | "skip_while" | "scan"
1869 | "inspect" => recv_inner.clone(),
1870
1871 "split"
1873 | "rsplit"
1874 | "splitn"
1875 | "rsplitn"
1876 | "split_whitespace"
1877 | "split_ascii_whitespace"
1878 | "lines"
1879 | "chars"
1880 | "bytes"
1881 | "char_indices"
1882 | "split_terminator"
1883 | "rsplit_terminator"
1884 | "split_inclusive"
1885 | "matches_iter" => self.fresh_var(),
1886
1887 "keys" | "values" | "values_mut" | "into_keys" | "into_values" | "entry"
1889 | "drain" => self.fresh_var(),
1890
1891 "first" | "last" | "get" | "get_mut" | "pop" | "pop_front" | "pop_back"
1893 | "find" | "find_map" | "position" | "rposition" | "next" | "next_back"
1894 | "peek" | "nth" | "last_mut" | "binary_search" | "parent" | "file_name"
1895 | "file_stem" | "extension" => Type::Named {
1896 name: "Option".to_string(),
1897 generics: vec![self.fresh_var()],
1898 },
1899
1900 "parse" | "try_into" | "try_from" => Type::Named {
1902 name: "Result".to_string(),
1903 generics: vec![self.fresh_var(), self.fresh_var()],
1904 },
1905
1906 "push" | "push_str" | "push_front" | "push_back" | "insert" | "remove"
1908 | "clear" | "sort" | "sort_by" | "sort_by_key" | "sort_unstable"
1909 | "truncate" | "resize" | "extend" | "append" | "retain" | "swap"
1910 | "swap_remove" => Type::Unit,
1911
1912 "abs" | "floor" | "ceil" | "round" | "trunc" | "fract" | "sqrt" | "cbrt"
1914 | "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sinh" | "cosh"
1915 | "tanh" | "exp" | "exp2" | "ln" | "log" | "log2" | "log10" | "pow"
1916 | "powi" | "powf" | "min" | "max" | "clamp" | "signum" | "copysign"
1917 | "saturating_add" | "saturating_sub" | "saturating_mul" | "wrapping_add"
1918 | "wrapping_sub" | "wrapping_mul" | "checked_add" | "checked_sub"
1919 | "checked_mul" | "checked_div" => recv_inner.clone(),
1920
1921 "to_digit" | "to_lowercase_char" | "to_uppercase_char" => Type::Named {
1923 name: "Option".to_string(),
1924 generics: vec![Type::Int(IntSize::U32)],
1925 },
1926
1927 "duration_since" | "elapsed" | "as_secs" | "as_millis" | "as_micros"
1929 | "as_nanos" | "from_secs" | "from_millis" => recv_inner.clone(),
1930
1931 "to_path_buf" | "join" | "with_extension" | "with_file_name" => Type::Named {
1933 name: "PathBuf".to_string(),
1934 generics: vec![],
1935 },
1936
1937 "to_str" => Type::Named {
1939 name: "Option".to_string(),
1940 generics: vec![Type::Ref {
1941 lifetime: None,
1942 mutable: false,
1943 inner: Box::new(Type::Str),
1944 }],
1945 },
1946
1947 "fmt" | "write_str" | "write_fmt" => Type::Named {
1949 name: "Result".to_string(),
1950 generics: vec![Type::Unit, self.fresh_var()],
1951 },
1952
1953 "read" | "write" | "flush" | "read_to_string" | "read_to_end" | "read_line"
1955 | "write_all" => Type::Named {
1956 name: "Result".to_string(),
1957 generics: vec![self.fresh_var(), self.fresh_var()],
1958 },
1959
1960 "metadata" | "modified" | "created" | "accessed" | "len_file"
1962 | "is_readonly" | "permissions" => Type::Named {
1963 name: "Result".to_string(),
1964 generics: vec![self.fresh_var(), self.fresh_var()],
1965 },
1966
1967 "map_err" | "and_then" | "or_else" => recv_inner.clone(),
1969
1970 "and" | "or" => recv_inner.clone(),
1972
1973 _ => self.fresh_var(),
1975 };
1976
1977 if recv_ev > EvidenceLevel::Known {
1979 Type::Evidential {
1980 inner: Box::new(result_ty),
1981 evidence: recv_ev,
1982 }
1983 } else {
1984 result_ty
1985 }
1986 }
1987
1988 Expr::Field { expr, field } => {
1989 let recv_ty = self.infer_expr(expr);
1990 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
1991
1992 let field_ty = if let Type::Named { name, .. } = &recv_inner {
1994 if let Some(struct_def) = self.types.get(name) {
1996 if let TypeDef::Struct { fields, .. } = struct_def {
1997 fields
1998 .iter()
1999 .find(|(n, _)| n == &field.name)
2000 .map(|(_, ty)| ty.clone())
2001 .unwrap_or_else(|| self.fresh_var())
2002 } else {
2003 self.fresh_var()
2004 }
2005 } else {
2006 self.fresh_var()
2007 }
2008 } else {
2009 self.fresh_var()
2010 };
2011
2012 if recv_ev > EvidenceLevel::Known {
2014 Type::Evidential {
2015 inner: Box::new(field_ty),
2016 evidence: recv_ev,
2017 }
2018 } else {
2019 field_ty
2020 }
2021 }
2022
2023 Expr::Index { expr, index, .. } => {
2024 let arr_ty = self.infer_expr(expr);
2025 let idx_ty = self.infer_expr(index);
2026 let (arr_inner, arr_ev) = self.strip_evidence(&arr_ty);
2027
2028 let _ = self.unify(&idx_ty, &Type::Int(IntSize::USize));
2030
2031 let elem_ty = match arr_inner {
2033 Type::Array { element, .. } => *element,
2034 Type::Slice(element) => *element,
2035 Type::Named { name, generics } if name == "Vec" && !generics.is_empty() => {
2036 generics[0].clone()
2037 }
2038 _ => self.fresh_var(),
2039 };
2040
2041 if arr_ev > EvidenceLevel::Known {
2043 Type::Evidential {
2044 inner: Box::new(elem_ty),
2045 evidence: arr_ev,
2046 }
2047 } else {
2048 elem_ty
2049 }
2050 }
2051
2052 _ => {
2053 self.fresh_var()
2055 }
2056 }
2057 }
2058
2059 fn infer_literal(&self, lit: &Literal) -> Type {
2061 match lit {
2062 Literal::Int { .. } => Type::Int(IntSize::I64),
2063 Literal::Float { suffix, .. } => {
2064 match suffix.as_ref().map(|s| s.as_str()) {
2065 Some("f32") => Type::Float(FloatSize::F32),
2066 Some("f64") => Type::Float(FloatSize::F64),
2067 None | Some(_) => Type::Float(FloatSize::F64),
2069 }
2070 }
2071 Literal::Bool(_) => Type::Bool,
2072 Literal::Char(_) => Type::Char,
2073 Literal::ByteChar(_) => Type::Int(IntSize::U8),
2074 Literal::String(_) => Type::Ref {
2076 lifetime: None,
2077 mutable: false,
2078 inner: Box::new(Type::Str),
2079 },
2080 Literal::MultiLineString(_) => Type::Ref {
2081 lifetime: None,
2082 mutable: false,
2083 inner: Box::new(Type::Str),
2084 },
2085 Literal::RawString(_) => Type::Ref {
2086 lifetime: None,
2087 mutable: false,
2088 inner: Box::new(Type::Str),
2089 },
2090 Literal::ByteString(bytes) => Type::Ref {
2091 lifetime: None,
2092 mutable: false,
2093 inner: Box::new(Type::Array {
2094 element: Box::new(Type::Int(IntSize::U8)),
2095 size: Some(bytes.len()),
2096 }),
2097 },
2098 Literal::InterpolatedString { .. } => Type::Str,
2099 Literal::SigilStringSql(_) => Type::Str,
2100 Literal::SigilStringRoute(_) => Type::Str,
2101 Literal::Null => Type::Unit, Literal::Empty => Type::Unit,
2103 Literal::Infinity => Type::Float(FloatSize::F64),
2104 Literal::Circle => Type::Float(FloatSize::F64),
2105 }
2106 }
2107
2108 fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
2110 let (left_inner, left_ev) = self.strip_evidence(left);
2112 let (right_inner, right_ev) = self.strip_evidence(right);
2113
2114 let is_var_or_fn = |ty: &Type| matches!(ty, Type::Var(_) | Type::Function { .. });
2116
2117 let result_ty = match op {
2118 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
2120 let _ = self.unify(&left_inner, &right_inner);
2123 left_inner
2124 }
2125
2126 BinOp::MatMul | BinOp::Hadamard | BinOp::TensorProd => {
2130 self.fresh_var()
2132 }
2133
2134 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
2136 if !self.unify(&left_inner, &right_inner)
2139 && !is_var_or_fn(&left_inner)
2140 && !is_var_or_fn(&right_inner)
2141 {
2142 self.error(TypeError::new(format!(
2143 "comparison operands must have same type: left={:?}, right={:?}",
2144 left_inner, right_inner
2145 )));
2146 }
2147 Type::Bool
2148 }
2149
2150 BinOp::And | BinOp::Or => {
2152 if !self.unify(&Type::Bool, &left_inner) {
2153 self.error(TypeError::new("logical operand must be bool"));
2154 }
2155 if !self.unify(&Type::Bool, &right_inner) {
2156 self.error(TypeError::new("logical operand must be bool"));
2157 }
2158 Type::Bool
2159 }
2160
2161 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
2163
2164 BinOp::Concat => {
2166 if !self.unify(&Type::Str, &left_inner) {
2167 self.error(TypeError::new("concat operand must be string"));
2168 }
2169 Type::Str
2170 }
2171 };
2172
2173 let combined_ev = left_ev.join(right_ev);
2175
2176 if combined_ev > EvidenceLevel::Known {
2178 Type::Evidential {
2179 inner: Box::new(result_ty),
2180 evidence: combined_ev,
2181 }
2182 } else {
2183 result_ty
2184 }
2185 }
2186
2187 fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
2189 let (inner_ty, evidence) = self.strip_evidence(inner);
2190
2191 let result = match op {
2192 UnaryOp::Neg => inner_ty,
2193 UnaryOp::Not => {
2194 if !self.unify(&Type::Bool, &inner_ty) {
2196 self.error(TypeError::new(format!(
2197 "type mismatch: '!' requires bool, found {}",
2198 inner_ty
2199 )));
2200 }
2201 Type::Bool
2202 }
2203 UnaryOp::Ref => Type::Ref {
2204 lifetime: None,
2205 mutable: false,
2206 inner: Box::new(inner_ty),
2207 },
2208 UnaryOp::RefMut => Type::Ref {
2209 lifetime: None,
2210 mutable: true,
2211 inner: Box::new(inner_ty),
2212 },
2213 UnaryOp::Deref => {
2214 if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
2215 *inner
2216 } else {
2217 self.fresh_var()
2219 }
2220 }
2221 };
2222
2223 if evidence > EvidenceLevel::Known {
2225 Type::Evidential {
2226 inner: Box::new(result),
2227 evidence,
2228 }
2229 } else {
2230 result
2231 }
2232 }
2233
2234 fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
2236 let (inner_ev_stripped, evidence) = self.strip_evidence(input);
2237
2238 let inner = match inner_ev_stripped {
2241 Type::Ref {
2242 inner: ref_inner, ..
2243 } => (*ref_inner).clone(),
2244 other => other,
2245 };
2246
2247 let result = match op {
2248 PipeOp::Transform(_body) => {
2250 if let Type::Array { element, size } = inner {
2251 Type::Array { element, size }
2252 } else if let Type::Slice(element) = inner {
2253 Type::Slice(element)
2254 } else {
2255 self.fresh_var()
2257 }
2258 }
2259
2260 PipeOp::Filter(_pred) => inner,
2262
2263 PipeOp::Sort(_) => inner,
2265
2266 PipeOp::Reduce(_) => {
2268 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2269 *element
2270 } else if let Type::Named { name, generics } = &inner {
2271 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2273 && !generics.is_empty()
2274 {
2275 generics[0].clone()
2276 } else {
2277 self.fresh_var()
2278 }
2279 } else if let Type::Var(_) = inner {
2280 self.fresh_var()
2282 } else {
2283 self.error(TypeError::new("reduce requires array or slice"));
2284 Type::Error
2285 }
2286 }
2287 PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
2288 let element = if let Type::Array { element, .. } | Type::Slice(element) = &inner {
2290 Some(element.clone())
2291 } else if let Type::Named { name, generics } = &inner {
2292 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2294 && !generics.is_empty()
2295 {
2296 Some(Box::new(generics[0].clone()))
2297 } else {
2298 None
2299 }
2300 } else {
2301 None
2302 };
2303 if let Some(element) = element {
2304 match element.as_ref() {
2305 Type::Int(_) | Type::Float(_) => *element,
2306 Type::Var(_) => *element, _ => {
2308 self.error(TypeError::new("numeric reduction requires numeric array"));
2309 Type::Error
2310 }
2311 }
2312 } else if let Type::Var(_) = inner {
2313 self.fresh_var()
2315 } else {
2316 self.error(TypeError::new("reduction requires array or slice"));
2317 Type::Error
2318 }
2319 }
2320 PipeOp::ReduceConcat => {
2321 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2323 match element.as_ref() {
2324 Type::Str => Type::Str,
2325 Type::Array { .. } => *element,
2326 Type::Var(_) => self.fresh_var(), _ => {
2328 self.error(TypeError::new(
2329 "concat reduction requires array of strings or arrays",
2330 ));
2331 Type::Error
2332 }
2333 }
2334 } else if let Type::Var(_) = inner {
2335 self.fresh_var()
2337 } else {
2338 self.error(TypeError::new("concat reduction requires array or slice"));
2339 Type::Error
2340 }
2341 }
2342 PipeOp::ReduceAll | PipeOp::ReduceAny => {
2343 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2345 match element.as_ref() {
2346 Type::Bool => Type::Bool,
2347 Type::Var(_) => Type::Bool, _ => {
2349 self.error(TypeError::new(
2350 "boolean reduction requires array of booleans",
2351 ));
2352 Type::Error
2353 }
2354 }
2355 } else if let Type::Var(_) = inner {
2356 Type::Bool
2358 } else {
2359 self.error(TypeError::new("boolean reduction requires array or slice"));
2360 Type::Error
2361 }
2362 }
2363
2364 PipeOp::Match(arms) => {
2366 if arms.is_empty() {
2368 self.error(TypeError::new("match expression has no arms"));
2369 Type::Error
2370 } else {
2371 let result_type = self.infer_expr(&arms[0].body);
2373 for arm in arms.iter().skip(1) {
2374 let arm_type = self.infer_expr(&arm.body);
2375 self.unify(&result_type, &arm_type);
2376 }
2377 result_type
2378 }
2379 }
2380
2381 PipeOp::TryMap(_) => {
2383 self.fresh_var()
2387 }
2388
2389 PipeOp::Call(callee) => {
2391 let callee_ty = self.infer_expr(callee);
2393 if let Type::Function { return_type, .. } = callee_ty {
2394 *return_type
2395 } else {
2396 self.fresh_var()
2398 }
2399 }
2400
2401 PipeOp::Method {
2403 name,
2404 type_args: _,
2405 args: _,
2406 } => {
2407 if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
2409 let fresh_ty = self.freshen(&fn_ty);
2411 if let Type::Function { return_type, .. } = fresh_ty {
2412 *return_type
2413 } else {
2414 Type::Error
2415 }
2416 } else {
2417 self.fresh_var()
2419 }
2420 }
2421
2422 PipeOp::Named { prefix, body: _ } => {
2424 if let Some(first) = prefix.first() {
2426 match first.name.as_str() {
2427 "sum" | "product" => {
2428 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2429 *element
2430 } else {
2431 self.error(TypeError::new("sum/product requires array"));
2432 Type::Error
2433 }
2434 }
2435 _ => self.fresh_var(),
2436 }
2437 } else {
2438 self.fresh_var()
2439 }
2440 }
2441
2442 PipeOp::Await => {
2444 inner
2446 }
2447
2448 PipeOp::First
2450 | PipeOp::Last
2451 | PipeOp::Middle
2452 | PipeOp::Choice
2453 | PipeOp::Nth(_)
2454 | PipeOp::Next => {
2455 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2456 *element
2457 } else if let Type::Named { name, generics } = &inner {
2458 if (name == "Vec" || name == "VecDeque" || name == "LinkedList")
2460 && !generics.is_empty()
2461 {
2462 generics[0].clone()
2463 } else {
2464 self.fresh_var()
2465 }
2466 } else if let Type::Tuple(elements) = inner {
2467 if let Some(first) = elements.first() {
2469 first.clone()
2470 } else {
2471 Type::Unit
2472 }
2473 } else if let Type::Var(_) = inner {
2474 self.fresh_var()
2476 } else {
2477 self.fresh_var()
2479 }
2480 }
2481
2482 PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
2485
2486 PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
2489
2490 PipeOp::Send(_) => {
2497 Type::Evidential {
2499 inner: Box::new(self.fresh_var()),
2500 evidence: EvidenceLevel::Reported,
2501 }
2502 }
2503
2504 PipeOp::Recv => {
2506 Type::Evidential {
2508 inner: Box::new(self.fresh_var()),
2509 evidence: EvidenceLevel::Reported,
2510 }
2511 }
2512
2513 PipeOp::Stream(_) => {
2515 self.fresh_var()
2517 }
2518
2519 PipeOp::Connect(_) => {
2521 self.fresh_var()
2523 }
2524
2525 PipeOp::Close => Type::Unit,
2527
2528 PipeOp::Header { .. } => inner,
2530
2531 PipeOp::Body(_) => inner,
2533
2534 PipeOp::Timeout(_) => inner,
2536
2537 PipeOp::Retry { .. } => inner,
2539
2540 PipeOp::Validate {
2546 predicate: _,
2547 target_evidence,
2548 } => {
2549 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2553
2554 if evidence < target_ev {
2556 self.error(
2557 TypeError::new(format!(
2558 "cannot demote evidence from {} ({}) to {} ({}) using validate",
2559 evidence.name(),
2560 evidence.symbol(),
2561 target_ev.name(),
2562 target_ev.symbol()
2563 ))
2564 .with_note("validate! can only promote evidence to a more certain level"),
2565 );
2566 }
2567
2568 return Type::Evidential {
2570 inner: Box::new(inner.clone()),
2571 evidence: target_ev,
2572 };
2573 }
2574
2575 PipeOp::Assume {
2577 reason: _,
2578 target_evidence,
2579 } => {
2580 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2581
2582 if evidence < target_ev {
2586 self.error(
2587 TypeError::new(format!(
2588 "assume! cannot demote evidence from {} ({}) to {} ({})",
2589 evidence.name(),
2590 evidence.symbol(),
2591 target_ev.name(),
2592 target_ev.symbol()
2593 ))
2594 .with_note("assume! is for promoting evidence, not demoting"),
2595 );
2596 }
2597
2598 return Type::Evidential {
2600 inner: Box::new(inner.clone()),
2601 evidence: target_ev,
2602 };
2603 }
2604
2605 PipeOp::AssertEvidence(expected_ast) => {
2607 let expected = EvidenceLevel::from_ast(*expected_ast);
2608
2609 if !evidence.satisfies(expected) {
2610 self.error(
2611 TypeError::new(format!(
2612 "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
2613 expected.name(), expected.symbol(),
2614 evidence.name(), evidence.symbol()
2615 ))
2616 .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
2617 );
2618 }
2619
2620 return input.clone();
2622 }
2623
2624 PipeOp::Also(_) => {
2631 return input.clone();
2634 }
2635
2636 PipeOp::Apply(_) => {
2639 return input.clone();
2642 }
2643
2644 PipeOp::TakeIf(_) => {
2647 return Type::Named {
2650 name: "Option".to_string(),
2651 generics: vec![input.clone()],
2652 };
2653 }
2654
2655 PipeOp::TakeUnless(_) => {
2658 return Type::Named {
2661 name: "Option".to_string(),
2662 generics: vec![input.clone()],
2663 };
2664 }
2665
2666 PipeOp::Let(func) => {
2669 let _ = self.infer_expr(func);
2671 self.fresh_var() }
2673
2674 PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
2676 PipeOp::Compose(f) => {
2677 let _ = self.infer_expr(f);
2678 self.fresh_var()
2679 }
2680 PipeOp::Zip(other) => {
2681 let _ = self.infer_expr(other);
2682 self.fresh_var() }
2684 PipeOp::Scan(f) => {
2685 let _ = self.infer_expr(f);
2686 self.fresh_var() }
2688 PipeOp::Diff => self.fresh_var(), PipeOp::Gradient(var) => {
2690 let _ = self.infer_expr(var);
2691 self.fresh_var() }
2693 PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
2694 inner.clone() }
2696 PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
2697 let _ = self.infer_expr(n);
2698 self.fresh_var() }
2700 PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
2701 PipeOp::Enumerate => self.fresh_var(), };
2703
2704 if evidence > EvidenceLevel::Known {
2706 Type::Evidential {
2707 inner: Box::new(result),
2708 evidence,
2709 }
2710 } else {
2711 result
2712 }
2713 }
2714
2715 fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
2717 match ty {
2718 Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
2719 _ => (ty.clone(), EvidenceLevel::Known),
2720 }
2721 }
2722
2723 fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
2726 let (inner_ty, ty_ev) = self.strip_evidence(ty);
2727 let final_ev = evidence.join(ty_ev);
2729
2730 match pattern {
2731 Pattern::Ident {
2732 name,
2733 evidentiality,
2734 ..
2735 } => {
2736 let ev = evidentiality
2738 .map(EvidenceLevel::from_ast)
2739 .unwrap_or(final_ev);
2740 self.env
2741 .borrow_mut()
2742 .define(name.name.clone(), inner_ty, ev);
2743 }
2744 Pattern::Tuple(patterns) => {
2745 if let Type::Tuple(types) = &inner_ty {
2746 for (pat, ty) in patterns.iter().zip(types.iter()) {
2747 self.bind_pattern(pat, ty, final_ev);
2748 }
2749 }
2750 }
2751 Pattern::Struct { fields, .. } => {
2752 for field in fields {
2755 let fresh = self.fresh_var();
2756 if let Some(ref pat) = field.pattern {
2757 self.bind_pattern(pat, &fresh, final_ev);
2758 } else {
2759 self.env
2760 .borrow_mut()
2761 .define(field.name.name.clone(), fresh, final_ev);
2762 }
2763 }
2764 }
2765 Pattern::TupleStruct { fields, .. } => {
2766 for pat in fields {
2767 let fresh = self.fresh_var();
2768 self.bind_pattern(pat, &fresh, final_ev);
2769 }
2770 }
2771 Pattern::Slice(patterns) => {
2772 let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
2773 {
2774 *element.clone()
2775 } else {
2776 self.fresh_var()
2777 };
2778 for pat in patterns {
2779 self.bind_pattern(pat, &elem_ty, final_ev);
2780 }
2781 }
2782 Pattern::Or(patterns) => {
2783 if let Some(first) = patterns.first() {
2786 self.bind_pattern(first, ty, evidence);
2787 }
2788 }
2789 Pattern::Wildcard
2790 | Pattern::Rest
2791 | Pattern::Literal(_)
2792 | Pattern::Range { .. }
2793 | Pattern::Path(_) => {
2794 }
2796 Pattern::Ref { pattern, .. } => {
2797 let inner_ty = self.fresh_var();
2800 self.bind_pattern(pattern, &inner_ty, final_ev);
2801 }
2802 Pattern::RefBinding {
2803 name,
2804 evidentiality,
2805 ..
2806 } => {
2807 let ev = evidentiality
2809 .map(EvidenceLevel::from_ast)
2810 .unwrap_or(final_ev);
2811 self.env
2812 .borrow_mut()
2813 .define(name.name.clone(), inner_ty, ev);
2814 }
2815 }
2816 }
2817
2818 fn resolve_alias(&self, ty: &Type) -> Type {
2820 if let Type::Named { name, generics } = ty {
2821 if generics.is_empty() {
2822 if let Some(TypeDef::Alias { target, .. }) = self.types.get(name) {
2823 return target.clone();
2824 }
2825 }
2826 }
2827 ty.clone()
2828 }
2829
2830 fn unify(&mut self, a: &Type, b: &Type) -> bool {
2832 let a = self.resolve_alias(a);
2834 let b = self.resolve_alias(b);
2835
2836 match (&a, &b) {
2837 (Type::Var(v), t) => {
2839 if let Some(resolved) = self.substitutions.get(v) {
2840 let resolved = resolved.clone();
2841 self.unify(&resolved, t)
2842 } else if !self.occurs_in(v, t) {
2843 self.substitutions.insert(*v, t.clone());
2844 true
2845 } else {
2846 true
2848 }
2849 }
2850 (t, Type::Var(v)) => {
2851 if let Some(resolved) = self.substitutions.get(v) {
2852 let resolved = resolved.clone();
2853 self.unify(t, &resolved)
2854 } else if !self.occurs_in(v, t) {
2855 self.substitutions.insert(*v, t.clone());
2856 true
2857 } else {
2858 true
2860 }
2861 }
2862
2863 (Type::Unit, Type::Unit) |
2865 (Type::Bool, Type::Bool) |
2866 (Type::Char, Type::Char) |
2867 (Type::Str, Type::Str) |
2868 (Type::Never, Type::Never) |
2869 (Type::Error, _) |
2870 (_, Type::Error) |
2871 (Type::Never, _) |
2873 (_, Type::Never) => true,
2874
2875 (Type::Int(_), Type::Int(_)) => true,
2878 (Type::Float(_), Type::Float(_)) => true,
2881
2882 (Type::Ref { mutable: false, inner: a, .. }, Type::Str) if matches!(a.as_ref(), Type::Str) => true,
2884 (Type::Str, Type::Ref { mutable: false, inner: b, .. }) if matches!(b.as_ref(), Type::Str) => true,
2885
2886 (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
2888 (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
2889 }
2890
2891 (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
2893
2894 (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
2896 a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
2897 }
2898
2899 (Type::Ref { mutable: ma, inner: a, .. }, Type::Ref { mutable: mb, inner: b, .. }) => {
2901 match (a.as_ref(), b.as_ref()) {
2903 (Type::Array { element: ea, .. }, Type::Slice(es)) => {
2904 ma == mb && self.unify(ea, es)
2905 }
2906 (Type::Slice(es), Type::Array { element: ea, .. }) => {
2907 ma == mb && self.unify(es, ea)
2908 }
2909 _ => ma == mb && self.unify(a, b)
2910 }
2911 }
2912
2913 (Type::Function { params: pa, return_type: ra, is_async: aa },
2915 Type::Function { params: pb, return_type: rb, is_async: ab }) => {
2916 aa == ab && pa.len() == pb.len() &&
2917 pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
2918 self.unify(ra, rb)
2919 }
2920
2921 (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
2923 na == nb && ga.len() == gb.len() &&
2924 ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y))
2925 }
2926
2927 (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
2929 self.unify(a, b)
2930 }
2931 (Type::Evidential { inner: a, .. }, b) => {
2932 self.unify(a, b)
2933 }
2934 (a, Type::Evidential { inner: b, .. }) => {
2935 self.unify(a, b)
2936 }
2937
2938 (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
2940
2941 (Type::Named { name, generics }, _) | (_, Type::Named { name, generics })
2945 if generics.is_empty() && Self::is_type_parameter(name) => {
2946 true
2947 }
2948
2949 _ => false,
2950 }
2951 }
2952
2953 fn is_type_parameter(name: &str) -> bool {
2955 if name.len() == 1
2957 && name
2958 .chars()
2959 .next()
2960 .map(|c| c.is_ascii_uppercase())
2961 .unwrap_or(false)
2962 {
2963 return true;
2964 }
2965 matches!(
2967 name,
2968 "Item" | "Output" | "Error" | "Key" | "Value" | "Idx" | "Self"
2969 )
2970 }
2971
2972 fn is_numeric_coercion(expected: &Type, actual: &Type) -> bool {
2974 match (expected, actual) {
2976 (Type::Float(_), Type::Int(_)) => true,
2977 (Type::Evidential { inner: exp, .. }, Type::Int(_)) => {
2979 matches!(exp.as_ref(), Type::Float(_))
2980 }
2981 (Type::Float(_), Type::Evidential { inner: act, .. }) => {
2982 matches!(act.as_ref(), Type::Int(_))
2983 }
2984 _ => false,
2985 }
2986 }
2987
2988 fn convert_type(&self, ty: &TypeExpr) -> Type {
2990 match ty {
2991 TypeExpr::Path(path) => {
2992 if path.segments.len() == 1 {
2993 let name = &path.segments[0].ident.name;
2994 match name.as_str() {
2995 "bool" => return Type::Bool,
2996 "char" => return Type::Char,
2997 "str" | "String" => return Type::Str,
2998 "i8" => return Type::Int(IntSize::I8),
2999 "i16" => return Type::Int(IntSize::I16),
3000 "i32" => return Type::Int(IntSize::I32),
3001 "i64" => return Type::Int(IntSize::I64),
3002 "i128" => return Type::Int(IntSize::I128),
3003 "isize" => return Type::Int(IntSize::ISize),
3004 "u8" => return Type::Int(IntSize::U8),
3005 "u16" => return Type::Int(IntSize::U16),
3006 "u32" => return Type::Int(IntSize::U32),
3007 "u64" => return Type::Int(IntSize::U64),
3008 "u128" => return Type::Int(IntSize::U128),
3009 "usize" => return Type::Int(IntSize::USize),
3010 "f32" => return Type::Float(FloatSize::F32),
3011 "f64" => return Type::Float(FloatSize::F64),
3012 "Self" => {
3014 if let Some(ref self_ty) = self.current_self_type {
3015 return Type::Named {
3016 name: self_ty.clone(),
3017 generics: vec![],
3018 };
3019 }
3020 }
3021 _ => {
3022 if let Some(ty) = self.current_generics.get(name) {
3024 return ty.clone();
3025 }
3026 }
3027 }
3028 }
3029
3030 let name = path
3031 .segments
3032 .iter()
3033 .map(|s| s.ident.name.clone())
3034 .collect::<Vec<_>>()
3035 .join("::");
3036
3037 let generics = path
3038 .segments
3039 .last()
3040 .and_then(|s| s.generics.as_ref())
3041 .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
3042 .unwrap_or_default();
3043
3044 Type::Named { name, generics }
3045 }
3046
3047 TypeExpr::Reference {
3048 lifetime,
3049 mutable,
3050 inner,
3051 } => Type::Ref {
3052 lifetime: lifetime.clone(),
3053 mutable: *mutable,
3054 inner: Box::new(self.convert_type(inner)),
3055 },
3056
3057 TypeExpr::Pointer { mutable, inner } => Type::Ptr {
3058 mutable: *mutable,
3059 inner: Box::new(self.convert_type(inner)),
3060 },
3061
3062 TypeExpr::Array { element, size: _ } => {
3063 Type::Array {
3064 element: Box::new(self.convert_type(element)),
3065 size: None, }
3067 }
3068
3069 TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
3070
3071 TypeExpr::Tuple(elements) => {
3072 Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
3073 }
3074
3075 TypeExpr::Function {
3076 params,
3077 return_type,
3078 } => Type::Function {
3079 params: params.iter().map(|t| self.convert_type(t)).collect(),
3080 return_type: Box::new(
3081 return_type
3082 .as_ref()
3083 .map(|t| self.convert_type(t))
3084 .unwrap_or(Type::Unit),
3085 ),
3086 is_async: false,
3087 },
3088
3089 TypeExpr::Evidential {
3090 inner,
3091 evidentiality,
3092 error_type,
3093 } => {
3094 let _ = error_type; Type::Evidential {
3098 inner: Box::new(self.convert_type(inner)),
3099 evidence: EvidenceLevel::from_ast(*evidentiality),
3100 }
3101 }
3102
3103 TypeExpr::Cycle { modulus: _ } => {
3104 Type::Cycle { modulus: 12 } }
3106
3107 TypeExpr::Simd { element, lanes } => {
3108 let elem_ty = self.convert_type(element);
3109 Type::Simd {
3110 element: Box::new(elem_ty),
3111 lanes: *lanes,
3112 }
3113 }
3114
3115 TypeExpr::Atomic(inner) => {
3116 let inner_ty = self.convert_type(inner);
3117 Type::Atomic(Box::new(inner_ty))
3118 }
3119
3120 TypeExpr::Never => Type::Never,
3121 TypeExpr::Infer => Type::Var(TypeVar(0)), TypeExpr::Lifetime(name) => Type::Lifetime(name.clone()),
3123 TypeExpr::TraitObject(bounds) => {
3124 let converted: Vec<Type> = bounds.iter().map(|b| self.convert_type(b)).collect();
3125 Type::TraitObject(converted)
3126 }
3127 TypeExpr::Hrtb { lifetimes, bound } => Type::Hrtb {
3128 lifetimes: lifetimes.clone(),
3129 bound: Box::new(self.convert_type(bound)),
3130 },
3131 TypeExpr::InlineStruct { fields } => Type::InlineStruct {
3132 fields: fields
3133 .iter()
3134 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
3135 .collect(),
3136 },
3137 TypeExpr::ImplTrait(bounds) => {
3138 Type::ImplTrait(bounds.iter().map(|b| self.convert_type(b)).collect())
3139 }
3140 TypeExpr::InlineEnum { variants } => {
3141 Type::InlineEnum(variants.iter().map(|v| v.name.name.clone()).collect())
3142 }
3143 TypeExpr::AssocTypeBinding { name, ty } => Type::AssocTypeBinding {
3144 name: name.name.clone(),
3145 ty: Box::new(self.convert_type(ty)),
3146 },
3147 TypeExpr::ConstExpr(_) => {
3148 Type::Var(TypeVar(0))
3151 }
3152 TypeExpr::QualifiedPath {
3153 self_type,
3154 trait_path,
3155 item_path,
3156 } => {
3157 let trait_part = trait_path
3160 .as_ref()
3161 .map(|tp| {
3162 tp.segments
3163 .iter()
3164 .map(|s| s.ident.name.clone())
3165 .collect::<Vec<_>>()
3166 .join("::")
3167 })
3168 .unwrap_or_default();
3169 let item_part = item_path
3170 .segments
3171 .iter()
3172 .map(|s| s.ident.name.clone())
3173 .collect::<Vec<_>>()
3174 .join("::");
3175 let name = if trait_part.is_empty() {
3176 format!("<_>::{}", item_part)
3177 } else {
3178 format!("<_ as {}>::{}", trait_part, item_part)
3179 };
3180 Type::Named {
3181 name,
3182 generics: vec![self.convert_type(self_type)],
3183 }
3184 }
3185 }
3186 }
3187
3188 pub fn errors(&self) -> &[TypeError] {
3190 &self.errors
3191 }
3192}
3193
3194impl Default for TypeChecker {
3195 fn default() -> Self {
3196 Self::new()
3197 }
3198}
3199
3200trait PatternExt {
3202 fn evidentiality(&self) -> Option<Evidentiality>;
3203 fn binding_name(&self) -> Option<String>;
3204 fn binding_span(&self) -> Option<Span>;
3205}
3206
3207impl PatternExt for Pattern {
3208 fn evidentiality(&self) -> Option<Evidentiality> {
3209 match self {
3210 Pattern::Ident { evidentiality, .. } => *evidentiality,
3211 _ => None,
3212 }
3213 }
3214
3215 fn binding_name(&self) -> Option<String> {
3216 match self {
3217 Pattern::Ident { name, .. } => Some(name.name.clone()),
3218 _ => None,
3219 }
3220 }
3221
3222 fn binding_span(&self) -> Option<Span> {
3223 match self {
3224 Pattern::Ident { name, .. } => Some(name.span),
3225 _ => None,
3226 }
3227 }
3228}
3229
3230impl fmt::Display for Type {
3231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3232 match self {
3233 Type::Unit => write!(f, "()"),
3234 Type::Bool => write!(f, "bool"),
3235 Type::Int(size) => write!(f, "{:?}", size),
3236 Type::Float(size) => write!(f, "{:?}", size),
3237 Type::Char => write!(f, "char"),
3238 Type::Str => write!(f, "str"),
3239 Type::Array { element, size } => {
3240 if let Some(n) = size {
3241 write!(f, "[{}; {}]", element, n)
3242 } else {
3243 write!(f, "[{}]", element)
3244 }
3245 }
3246 Type::Slice(inner) => write!(f, "[{}]", inner),
3247 Type::Tuple(elems) => {
3248 write!(f, "(")?;
3249 for (i, e) in elems.iter().enumerate() {
3250 if i > 0 {
3251 write!(f, ", ")?;
3252 }
3253 write!(f, "{}", e)?;
3254 }
3255 write!(f, ")")
3256 }
3257 Type::Named { name, generics } => {
3258 write!(f, "{}", name)?;
3259 if !generics.is_empty() {
3260 write!(f, "<")?;
3261 for (i, g) in generics.iter().enumerate() {
3262 if i > 0 {
3263 write!(f, ", ")?;
3264 }
3265 write!(f, "{}", g)?;
3266 }
3267 write!(f, ">")?;
3268 }
3269 Ok(())
3270 }
3271 Type::Function {
3272 params,
3273 return_type,
3274 is_async,
3275 } => {
3276 if *is_async {
3277 write!(f, "async ")?;
3278 }
3279 write!(f, "fn(")?;
3280 for (i, p) in params.iter().enumerate() {
3281 if i > 0 {
3282 write!(f, ", ")?;
3283 }
3284 write!(f, "{}", p)?;
3285 }
3286 write!(f, ") -> {}", return_type)
3287 }
3288 Type::Ref {
3289 lifetime,
3290 mutable,
3291 inner,
3292 } => {
3293 let lt = lifetime
3294 .as_ref()
3295 .map(|l| format!("'{} ", l))
3296 .unwrap_or_default();
3297 write!(f, "&{}{}{}", lt, if *mutable { "mut " } else { "" }, inner)
3298 }
3299 Type::Ptr { mutable, inner } => {
3300 write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
3301 }
3302 Type::Evidential { inner, evidence } => {
3303 write!(f, "{}{}", inner, evidence.symbol())
3304 }
3305 Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
3306 Type::Var(v) => write!(f, "?{}", v.0),
3307 Type::Error => write!(f, "<error>"),
3308 Type::Never => write!(f, "!"),
3309 Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
3310 Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
3311 Type::Lifetime(name) => write!(f, "'{}", name),
3312 Type::TraitObject(bounds) => {
3313 write!(f, "dyn ")?;
3314 for (i, bound) in bounds.iter().enumerate() {
3315 if i > 0 {
3316 write!(f, " + ")?;
3317 }
3318 write!(f, "{}", bound)?;
3319 }
3320 Ok(())
3321 }
3322 Type::Hrtb { lifetimes, bound } => {
3323 write!(f, "for<")?;
3324 for (i, lt) in lifetimes.iter().enumerate() {
3325 if i > 0 {
3326 write!(f, ", ")?;
3327 }
3328 write!(f, "'{}", lt)?;
3329 }
3330 write!(f, "> {}", bound)
3331 }
3332 Type::InlineStruct { fields } => {
3333 write!(f, "struct {{ ")?;
3334 for (i, (name, ty)) in fields.iter().enumerate() {
3335 if i > 0 {
3336 write!(f, ", ")?;
3337 }
3338 write!(f, "{}: {}", name, ty)?;
3339 }
3340 write!(f, " }}")
3341 }
3342 Type::ImplTrait(bounds) => {
3343 write!(f, "impl ")?;
3344 for (i, bound) in bounds.iter().enumerate() {
3345 if i > 0 {
3346 write!(f, " + ")?;
3347 }
3348 write!(f, "{}", bound)?;
3349 }
3350 Ok(())
3351 }
3352 Type::InlineEnum(variants) => {
3353 write!(f, "enum {{ ")?;
3354 for (i, name) in variants.iter().enumerate() {
3355 if i > 0 {
3356 write!(f, ", ")?;
3357 }
3358 write!(f, "{}", name)?;
3359 }
3360 write!(f, " }}")
3361 }
3362 Type::AssocTypeBinding { name, ty } => {
3363 write!(f, "{} = {}", name, ty)
3364 }
3365 }
3366 }
3367}
3368
3369#[cfg(test)]
3370mod tests {
3371 use super::*;
3372 use crate::Parser;
3373
3374 fn check(source: &str) -> Result<(), Vec<TypeError>> {
3375 let mut parser = Parser::new(source);
3376 let file = parser.parse_file().expect("parse failed");
3377 let mut checker = TypeChecker::new();
3378 checker.check_file(&file)
3379 }
3380
3381 #[test]
3382 fn test_basic_types() {
3383 assert!(check("fn main() { let x: i64 = 42; }").is_ok());
3384 assert!(check("fn main() { let x: bool = true; }").is_ok());
3385 assert!(check("fn main() { let x: f64 = 3.14; }").is_ok());
3386 }
3387
3388 #[test]
3389 fn test_type_mismatch() {
3390 assert!(check("fn main() { let x: bool = 42; }").is_err());
3391 }
3392
3393 #[test]
3394 fn test_evidence_propagation() {
3395 assert!(check(
3397 r#"
3398 fn main() {
3399 let known: i64! = 42;
3400 let uncertain: i64? = 10;
3401 let result = known + uncertain;
3402 }
3403 "#
3404 )
3405 .is_ok());
3406 }
3407
3408 #[test]
3409 fn test_function_return() {
3410 let result = check(
3411 r#"
3412 fn add(a: i64, b: i64) -> i64 {
3413 return a + b;
3414 }
3415 fn main() {
3416 let x = add(1, 2);
3417 }
3418 "#,
3419 );
3420 if let Err(errors) = &result {
3421 for e in errors {
3422 eprintln!("Error: {}", e);
3423 }
3424 }
3425 assert!(result.is_ok());
3426 }
3427
3428 #[test]
3429 fn test_array_types() {
3430 assert!(check(
3431 r#"
3432 fn main() {
3433 let arr = [1, 2, 3];
3434 let x = arr[0];
3435 }
3436 "#
3437 )
3438 .is_ok());
3439 }
3440
3441 #[test]
3446 fn test_evidence_inference_from_initializer() {
3447 assert!(check(
3449 r#"
3450 fn main() {
3451 let reported_val: i64~ = 42;
3452 // x should inherit ~ evidence from reported_val
3453 let x = reported_val + 1;
3454 }
3455 "#
3456 )
3457 .is_ok());
3458 }
3459
3460 #[test]
3461 fn test_evidence_inference_explicit_override() {
3462 assert!(check(
3464 r#"
3465 fn main() {
3466 let reported_val: i64~ = 42;
3467 // Explicit ! annotation - this would fail if we checked evidence properly
3468 // but the type system allows it as an override
3469 let x! = 42;
3470 }
3471 "#
3472 )
3473 .is_ok());
3474 }
3475
3476 #[test]
3477 fn test_if_else_evidence_join() {
3478 assert!(check(
3480 r#"
3481 fn main() {
3482 let known_val: i64! = 1;
3483 let reported_val: i64~ = 2;
3484 let cond: bool = true;
3485 // Result should have ~ evidence (join of ! and ~)
3486 let result = if cond { known_val } else { reported_val };
3487 }
3488 "#
3489 )
3490 .is_ok());
3491 }
3492
3493 #[test]
3494 fn test_binary_op_evidence_propagation() {
3495 assert!(check(
3497 r#"
3498 fn main() {
3499 let known: i64! = 1;
3500 let reported: i64~ = 2;
3501 // Result should have ~ evidence (max of ! and ~)
3502 let result = known + reported;
3503 }
3504 "#
3505 )
3506 .is_ok());
3507 }
3508
3509 #[test]
3510 fn test_match_evidence_join() {
3511 assert!(check(
3514 r#"
3515 fn main() {
3516 let x: i64 = 1;
3517 }
3518 "#
3519 )
3520 .is_ok());
3521 }
3522}