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 { name: String, ty: Box<Type> },
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum IntSize {
112 I8,
113 I16,
114 I32,
115 I64,
116 I128,
117 U8,
118 U16,
119 U32,
120 U64,
121 U128,
122 ISize,
123 USize,
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub enum FloatSize {
129 F32,
130 F64,
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
141pub enum EvidenceLevel {
142 Known, Uncertain, Reported, Paradox, }
151
152impl EvidenceLevel {
153 pub fn join(self, other: Self) -> Self {
155 std::cmp::max(self, other)
156 }
157
158 pub fn meet(self, other: Self) -> Self {
160 std::cmp::min(self, other)
161 }
162
163 pub fn from_ast(e: Evidentiality) -> Self {
165 match e {
166 Evidentiality::Known => EvidenceLevel::Known,
167 Evidentiality::Uncertain | Evidentiality::Predicted => EvidenceLevel::Uncertain,
168 Evidentiality::Reported => EvidenceLevel::Reported,
169 Evidentiality::Paradox => EvidenceLevel::Paradox,
170 }
171 }
172
173 pub fn symbol(&self) -> &'static str {
175 match self {
176 EvidenceLevel::Known => "!",
177 EvidenceLevel::Uncertain => "?",
178 EvidenceLevel::Reported => "~",
179 EvidenceLevel::Paradox => "‽",
180 }
181 }
182
183 pub fn name(&self) -> &'static str {
185 match self {
186 EvidenceLevel::Known => "known",
187 EvidenceLevel::Uncertain => "uncertain",
188 EvidenceLevel::Reported => "reported",
189 EvidenceLevel::Paradox => "paradox",
190 }
191 }
192
193 pub fn satisfies(self, required: Self) -> bool {
201 self <= required
204 }
205}
206
207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
209pub struct TypeVar(pub u32);
210
211#[derive(Debug, Clone)]
213pub struct TypeError {
214 pub message: String,
215 pub span: Option<Span>,
216 pub notes: Vec<String>,
217}
218
219impl TypeError {
220 pub fn new(message: impl Into<String>) -> Self {
221 Self {
222 message: message.into(),
223 span: None,
224 notes: Vec::new(),
225 }
226 }
227
228 pub fn with_span(mut self, span: Span) -> Self {
229 self.span = Some(span);
230 self
231 }
232
233 pub fn with_note(mut self, note: impl Into<String>) -> Self {
234 self.notes.push(note.into());
235 self
236 }
237}
238
239impl fmt::Display for TypeError {
240 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 write!(f, "{}", self.message)?;
242 if let Some(span) = self.span {
243 write!(f, " at {}", span)?;
244 }
245 for note in &self.notes {
246 write!(f, "\n note: {}", note)?;
247 }
248 Ok(())
249 }
250}
251
252#[derive(Debug, Clone)]
254pub struct TypeEnv {
255 bindings: HashMap<String, (Type, EvidenceLevel)>,
257 parent: Option<Rc<RefCell<TypeEnv>>>,
259}
260
261impl TypeEnv {
262 pub fn new() -> Self {
263 Self {
264 bindings: HashMap::new(),
265 parent: None,
266 }
267 }
268
269 pub fn with_parent(parent: Rc<RefCell<TypeEnv>>) -> Self {
270 Self {
271 bindings: HashMap::new(),
272 parent: Some(parent),
273 }
274 }
275
276 pub fn define(&mut self, name: String, ty: Type, evidence: EvidenceLevel) {
278 self.bindings.insert(name, (ty, evidence));
279 }
280
281 pub fn lookup(&self, name: &str) -> Option<(Type, EvidenceLevel)> {
283 if let Some(binding) = self.bindings.get(name) {
284 Some(binding.clone())
285 } else if let Some(ref parent) = self.parent {
286 parent.borrow().lookup(name)
287 } else {
288 None
289 }
290 }
291}
292
293impl Default for TypeEnv {
294 fn default() -> Self {
295 Self::new()
296 }
297}
298
299#[derive(Debug, Clone)]
301pub enum TypeDef {
302 Struct {
303 generics: Vec<String>,
304 fields: Vec<(String, Type)>,
305 },
306 Enum {
307 generics: Vec<String>,
308 variants: Vec<(String, Option<Vec<Type>>)>,
309 },
310 Alias {
311 generics: Vec<String>,
312 target: Type,
313 },
314}
315
316pub struct TypeChecker {
318 env: Rc<RefCell<TypeEnv>>,
320 types: HashMap<String, TypeDef>,
322 functions: HashMap<String, Type>,
324 impl_methods: HashMap<String, HashMap<String, Type>>,
326 current_self_type: Option<String>,
328 current_generics: HashMap<String, Type>,
330 expected_return_type: Option<Type>,
332 next_var: u32,
334 substitutions: HashMap<TypeVar, Type>,
336 errors: Vec<TypeError>,
338 mutable_vars: std::collections::HashSet<String>,
340}
341
342impl TypeChecker {
343 pub fn new() -> Self {
344 let mut checker = Self {
345 env: Rc::new(RefCell::new(TypeEnv::new())),
346 types: HashMap::new(),
347 functions: HashMap::new(),
348 impl_methods: HashMap::new(),
349 current_self_type: None,
350 current_generics: HashMap::new(),
351 expected_return_type: None,
352 next_var: 0,
353 substitutions: HashMap::new(),
354 errors: Vec::new(),
355 mutable_vars: std::collections::HashSet::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)); let t1 = Type::Var(TypeVar(9998));
379 self.functions.insert(
380 "Some".to_string(),
381 func(
382 vec![t1.clone()],
383 Type::Named {
384 name: "Option".to_string(),
385 generics: vec![t1],
386 },
387 ),
388 );
389
390 let t2 = Type::Var(TypeVar(9997));
392 self.functions.insert(
393 "None".to_string(),
394 func(
395 vec![],
396 Type::Named {
397 name: "Option".to_string(),
398 generics: vec![t2],
399 },
400 ),
401 );
402
403 let t3 = Type::Var(TypeVar(9996));
405 let e1 = Type::Var(TypeVar(9995));
406 self.functions.insert(
407 "Ok".to_string(),
408 func(
409 vec![t3.clone()],
410 Type::Named {
411 name: "Result".to_string(),
412 generics: vec![t3, e1],
413 },
414 ),
415 );
416
417 let t4 = Type::Var(TypeVar(9994));
419 let e2 = Type::Var(TypeVar(9993));
420 self.functions.insert(
421 "Err".to_string(),
422 func(
423 vec![e2.clone()],
424 Type::Named {
425 name: "Result".to_string(),
426 generics: vec![t4, e2],
427 },
428 ),
429 );
430
431 self.functions
436 .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
437 self.functions
438 .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
439 self.functions
440 .insert("input".to_string(), func(vec![], Type::Str));
441 self.functions
442 .insert("input_line".to_string(), func(vec![], Type::Str));
443
444 self.functions
448 .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
449 self.functions.insert(
450 "len".to_string(),
451 func(vec![any.clone()], Type::Int(IntSize::USize)),
452 );
453
454 self.functions
458 .insert("str".to_string(), func(vec![any.clone()], Type::Str));
459 self.functions
460 .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
461 self.functions
462 .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
463 self.functions
464 .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
465 self.functions.insert(
466 "split".to_string(),
467 func(
468 vec![Type::Str, Type::Str],
469 Type::Array {
470 element: Box::new(Type::Str),
471 size: None,
472 },
473 ),
474 );
475 self.functions.insert(
476 "join".to_string(),
477 func(
478 vec![
479 Type::Array {
480 element: Box::new(Type::Str),
481 size: None,
482 },
483 Type::Str,
484 ],
485 Type::Str,
486 ),
487 );
488 self.functions.insert(
489 "contains".to_string(),
490 func(vec![Type::Str, Type::Str], Type::Bool),
491 );
492 self.functions.insert(
493 "starts_with".to_string(),
494 func(vec![Type::Str, Type::Str], Type::Bool),
495 );
496 self.functions.insert(
497 "ends_with".to_string(),
498 func(vec![Type::Str, Type::Str], Type::Bool),
499 );
500 self.functions.insert(
501 "replace".to_string(),
502 func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
503 );
504 self.functions.insert(
505 "char_at".to_string(),
506 func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
507 );
508 self.functions.insert(
509 "substring".to_string(),
510 func(
511 vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
512 Type::Str,
513 ),
514 );
515
516 let f64_ty = Type::Float(FloatSize::F64);
520 let i64_ty = Type::Int(IntSize::I64);
521
522 self.functions.insert(
523 "abs".to_string(),
524 func(vec![f64_ty.clone()], f64_ty.clone()),
525 );
526 self.functions.insert(
527 "sqrt".to_string(),
528 func(vec![f64_ty.clone()], f64_ty.clone()),
529 );
530 self.functions.insert(
531 "sin".to_string(),
532 func(vec![f64_ty.clone()], f64_ty.clone()),
533 );
534 self.functions.insert(
535 "cos".to_string(),
536 func(vec![f64_ty.clone()], f64_ty.clone()),
537 );
538 self.functions.insert(
539 "tan".to_string(),
540 func(vec![f64_ty.clone()], f64_ty.clone()),
541 );
542 self.functions.insert(
543 "floor".to_string(),
544 func(vec![f64_ty.clone()], f64_ty.clone()),
545 );
546 self.functions.insert(
547 "ceil".to_string(),
548 func(vec![f64_ty.clone()], f64_ty.clone()),
549 );
550 self.functions.insert(
551 "round".to_string(),
552 func(vec![f64_ty.clone()], f64_ty.clone()),
553 );
554 self.functions.insert(
555 "pow".to_string(),
556 func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
557 );
558 self.functions.insert(
559 "log".to_string(),
560 func(vec![f64_ty.clone()], f64_ty.clone()),
561 );
562 self.functions.insert(
563 "exp".to_string(),
564 func(vec![f64_ty.clone()], f64_ty.clone()),
565 );
566 self.functions.insert(
567 "min".to_string(),
568 func(vec![any.clone(), any.clone()], any.clone()),
569 );
570 self.functions.insert(
571 "max".to_string(),
572 func(vec![any.clone(), any.clone()], any.clone()),
573 );
574
575 self.functions
579 .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
580 self.functions
581 .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
582 self.functions.insert(
583 "push".to_string(),
584 func(vec![any.clone(), any.clone()], Type::Unit),
585 );
586 self.functions
587 .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
588 self.functions
589 .insert("first".to_string(), func(vec![any.clone()], any.clone()));
590 self.functions
591 .insert("last".to_string(), func(vec![any.clone()], any.clone()));
592 self.functions
593 .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
594 self.functions
595 .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
596 self.functions.insert(
597 "range".to_string(),
598 func(
599 vec![i64_ty.clone(), i64_ty.clone()],
600 Type::Array {
601 element: Box::new(i64_ty.clone()),
602 size: None,
603 },
604 ),
605 );
606
607 self.functions
611 .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
612 self.functions.insert(
613 "assert_eq".to_string(),
614 func(vec![any.clone(), any.clone()], Type::Unit),
615 );
616 self.functions.insert(
617 "assert_ne".to_string(),
618 func(vec![any.clone(), any.clone()], Type::Unit),
619 );
620 self.functions.insert(
621 "assert_lt".to_string(),
622 func(vec![any.clone(), any.clone()], Type::Unit),
623 );
624 self.functions.insert(
625 "assert_le".to_string(),
626 func(vec![any.clone(), any.clone()], Type::Unit),
627 );
628 self.functions.insert(
629 "assert_gt".to_string(),
630 func(vec![any.clone(), any.clone()], Type::Unit),
631 );
632 self.functions.insert(
633 "assert_ge".to_string(),
634 func(vec![any.clone(), any.clone()], Type::Unit),
635 );
636 self.functions.insert(
637 "assert_true".to_string(),
638 func(vec![Type::Bool], Type::Unit),
639 );
640 self.functions.insert(
641 "assert_false".to_string(),
642 func(vec![Type::Bool], Type::Unit),
643 );
644 self.functions.insert(
645 "assert_null".to_string(),
646 func(vec![any.clone()], Type::Unit),
647 );
648 self.functions.insert(
649 "assert_not_null".to_string(),
650 func(vec![any.clone()], Type::Unit),
651 );
652 self.functions.insert(
653 "assert_contains".to_string(),
654 func(vec![any.clone(), any.clone()], Type::Unit),
655 );
656 self.functions.insert(
657 "assert_len".to_string(),
658 func(vec![any.clone(), i64_ty.clone()], Type::Unit),
659 );
660
661 self.functions
665 .insert("random".to_string(), func(vec![], f64_ty.clone()));
666 self.functions.insert(
667 "random_int".to_string(),
668 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
669 );
670 self.functions
671 .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
672
673 self.functions
677 .insert("now".to_string(), func(vec![], f64_ty.clone()));
678 self.functions
679 .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
680
681 self.functions
685 .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
686 self.functions
687 .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
688 self.functions
689 .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
690
691 self.functions
695 .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
696 self.functions
697 .insert("todo".to_string(), func(vec![], Type::Never));
698 self.functions
699 .insert("unreachable".to_string(), func(vec![], Type::Never));
700
701 self.functions.insert(
706 "known".to_string(),
707 func(
708 vec![any.clone()],
709 Type::Evidential {
710 inner: Box::new(any.clone()),
711 evidence: EvidenceLevel::Known,
712 },
713 ),
714 );
715 self.functions.insert(
717 "uncertain".to_string(),
718 func(
719 vec![any.clone()],
720 Type::Evidential {
721 inner: Box::new(any.clone()),
722 evidence: EvidenceLevel::Uncertain,
723 },
724 ),
725 );
726 self.functions.insert(
728 "reported".to_string(),
729 func(
730 vec![any.clone()],
731 Type::Evidential {
732 inner: Box::new(any.clone()),
733 evidence: EvidenceLevel::Reported,
734 },
735 ),
736 );
737 self.functions.insert(
739 "evidence_of".to_string(),
740 func(vec![any.clone()], Type::Str),
741 );
742 self.functions.insert(
744 "validate".to_string(),
745 func(
746 vec![any.clone()],
747 Type::Evidential {
748 inner: Box::new(any.clone()),
749 evidence: EvidenceLevel::Uncertain,
750 },
751 ),
752 );
753 self.functions.insert(
755 "verify".to_string(),
756 func(
757 vec![any.clone()],
758 Type::Evidential {
759 inner: Box::new(any.clone()),
760 evidence: EvidenceLevel::Known,
761 },
762 ),
763 );
764
765 self.functions.insert(
770 "freq".to_string(),
771 func(vec![i64_ty.clone()], f64_ty.clone()),
772 );
773 self.functions.insert(
775 "octave".to_string(),
776 func(vec![i64_ty.clone()], i64_ty.clone()),
777 );
778 self.functions.insert(
780 "pitch_class".to_string(),
781 func(vec![i64_ty.clone()], i64_ty.clone()),
782 );
783 self.functions.insert(
785 "mod_cycle".to_string(),
786 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
787 );
788 }
789
790 fn fresh_var(&mut self) -> Type {
792 let var = TypeVar(self.next_var);
793 self.next_var += 1;
794 Type::Var(var)
795 }
796
797 fn type_contains_var(&self, ty: &Type) -> bool {
799 match ty {
800 Type::Var(v) => !self.substitutions.contains_key(v),
801 Type::Array { element, .. } => self.type_contains_var(element.as_ref()),
802 Type::Slice(inner) => self.type_contains_var(inner.as_ref()),
803 Type::Tuple(elems) => elems.iter().any(|e| self.type_contains_var(e)),
804 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.type_contains_var(inner.as_ref()),
805 Type::Function { params, return_type, .. } => {
806 params.iter().any(|p| self.type_contains_var(p)) || self.type_contains_var(return_type.as_ref())
807 }
808 Type::Named { generics, .. } => generics.iter().any(|g| self.type_contains_var(g)),
809 Type::Evidential { inner, .. } => self.type_contains_var(inner.as_ref()),
810 Type::Atomic(inner) => self.type_contains_var(inner.as_ref()),
811 Type::Simd { element, .. } => self.type_contains_var(element.as_ref()),
812 _ => false,
813 }
814 }
815
816 fn occurs_in(&self, v: &TypeVar, t: &Type) -> bool {
819 match t {
820 Type::Var(w) => {
821 if v == w {
822 return true;
823 }
824 if let Some(resolved) = self.substitutions.get(w) {
825 self.occurs_in(v, resolved)
826 } else {
827 false
828 }
829 }
830 Type::Array { element, .. } => self.occurs_in(v, element),
831 Type::Slice(inner) => self.occurs_in(v, inner),
832 Type::Tuple(elems) => elems.iter().any(|e| self.occurs_in(v, e)),
833 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.occurs_in(v, inner),
834 Type::Function { params, return_type, .. } => {
835 params.iter().any(|p| self.occurs_in(v, p)) || self.occurs_in(v, return_type)
836 }
837 Type::Named { generics, .. } => generics.iter().any(|g| self.occurs_in(v, g)),
838 Type::Evidential { inner, .. } => self.occurs_in(v, inner),
839 Type::Atomic(inner) => self.occurs_in(v, inner),
840 Type::Simd { element, .. } => self.occurs_in(v, element),
841 _ => false,
842 }
843 }
844
845 fn freshen(&mut self, ty: &Type) -> Type {
848 let mut mapping = std::collections::HashMap::new();
849 self.freshen_inner(ty, &mut mapping)
850 }
851
852 fn freshen_inner(
853 &mut self,
854 ty: &Type,
855 mapping: &mut std::collections::HashMap<u32, Type>,
856 ) -> Type {
857 match ty {
858 Type::Var(TypeVar(id)) => {
859 if let Some(fresh) = mapping.get(id) {
860 fresh.clone()
861 } else {
862 let fresh = self.fresh_var();
863 mapping.insert(*id, fresh.clone());
864 fresh
865 }
866 }
867 Type::Array { element, size } => Type::Array {
868 element: Box::new(self.freshen_inner(element, mapping)),
869 size: *size,
870 },
871 Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
872 Type::Ref { lifetime, mutable, inner } => Type::Ref {
873 lifetime: lifetime.clone(),
874 mutable: *mutable,
875 inner: Box::new(self.freshen_inner(inner, mapping)),
876 },
877 Type::Tuple(elems) => Type::Tuple(
878 elems
879 .iter()
880 .map(|e| self.freshen_inner(e, mapping))
881 .collect(),
882 ),
883 Type::Function {
884 params,
885 return_type,
886 is_async,
887 } => Type::Function {
888 params: params
889 .iter()
890 .map(|p| self.freshen_inner(p, mapping))
891 .collect(),
892 return_type: Box::new(self.freshen_inner(return_type, mapping)),
893 is_async: *is_async,
894 },
895 Type::Evidential { inner, evidence } => Type::Evidential {
896 inner: Box::new(self.freshen_inner(inner, mapping)),
897 evidence: *evidence,
898 },
899 Type::Named { name, generics } => Type::Named {
900 name: name.clone(),
901 generics: generics
902 .iter()
903 .map(|g| self.freshen_inner(g, mapping))
904 .collect(),
905 },
906 _ => ty.clone(),
908 }
909 }
910
911 fn push_scope(&mut self) {
913 let new_env = TypeEnv::with_parent(self.env.clone());
914 self.env = Rc::new(RefCell::new(new_env));
915 }
916
917 fn pop_scope(&mut self) {
919 let parent = self.env.borrow().parent.clone();
920 if let Some(p) = parent {
921 self.env = p;
922 }
923 }
924
925 fn error(&mut self, err: TypeError) {
927 self.errors.push(err);
928 }
929
930 fn check_evidence(
933 &mut self,
934 expected: EvidenceLevel,
935 actual: EvidenceLevel,
936 context: &str,
937 ) -> bool {
938 if actual.satisfies(expected) {
939 true
940 } else {
941 let mut err = TypeError::new(format!(
942 "evidence mismatch {}: expected {} ({}), found {} ({})",
943 context,
944 expected.name(),
945 expected.symbol(),
946 actual.name(),
947 actual.symbol(),
948 ));
949
950 match (expected, actual) {
952 (EvidenceLevel::Known, EvidenceLevel::Reported) => {
953 err = err.with_note(
954 "reported data (~) cannot be used where known data (!) is required",
955 );
956 err = err.with_note(
957 "help: use |validate!{...} to verify and promote evidence level",
958 );
959 }
960 (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
961 err = err.with_note(
962 "uncertain data (?) cannot be used where known data (!) is required",
963 );
964 err = err.with_note(
965 "help: use pattern matching or unwrap to handle the uncertainty",
966 );
967 }
968 (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
969 err = err.with_note(
970 "reported data (~) cannot be used where uncertain data (?) is required",
971 );
972 err = err.with_note("help: use |validate?{...} to verify external data");
973 }
974 _ => {
975 err = err.with_note(format!(
976 "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
977 ));
978 }
979 }
980
981 self.error(err);
982 false
983 }
984 }
985
986 fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
988 match ty {
989 Type::Evidential { evidence, .. } => *evidence,
990 _ => EvidenceLevel::Known,
991 }
992 }
993
994 pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
996 for item in &file.items {
998 self.collect_type_def(&item.node);
999 }
1000
1001 for item in &file.items {
1003 self.collect_fn_sig(&item.node);
1004 }
1005
1006 for item in &file.items {
1008 self.check_item(&item.node);
1009 }
1010
1011 if self.errors.is_empty() {
1012 Ok(())
1013 } else {
1014 Err(std::mem::take(&mut self.errors))
1015 }
1016 }
1017
1018 fn collect_type_def(&mut self, item: &Item) {
1020 match item {
1021 Item::Struct(s) => {
1022 let generics = s
1023 .generics
1024 .as_ref()
1025 .map(|g| {
1026 g.params
1027 .iter()
1028 .filter_map(|p| {
1029 if let GenericParam::Type { name, .. } = p {
1030 Some(name.name.clone())
1031 } else {
1032 None
1033 }
1034 })
1035 .collect()
1036 })
1037 .unwrap_or_default();
1038
1039 let fields = match &s.fields {
1040 StructFields::Named(fs) => fs
1041 .iter()
1042 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
1043 .collect(),
1044 StructFields::Tuple(ts) => ts
1045 .iter()
1046 .enumerate()
1047 .map(|(i, t)| (i.to_string(), self.convert_type(t)))
1048 .collect(),
1049 StructFields::Unit => vec![],
1050 };
1051
1052 if self.types.contains_key(&s.name.name) {
1054 self.error(TypeError::new(format!(
1055 "duplicate type definition: '{}'",
1056 s.name.name
1057 )));
1058 }
1059 self.types
1060 .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
1061 }
1062 Item::Enum(e) => {
1063 let generics = e
1064 .generics
1065 .as_ref()
1066 .map(|g| {
1067 g.params
1068 .iter()
1069 .filter_map(|p| {
1070 if let GenericParam::Type { name, .. } = p {
1071 Some(name.name.clone())
1072 } else {
1073 None
1074 }
1075 })
1076 .collect()
1077 })
1078 .unwrap_or_default();
1079
1080 let variants = e
1081 .variants
1082 .iter()
1083 .map(|v| {
1084 let fields = match &v.fields {
1085 StructFields::Tuple(ts) => {
1086 Some(ts.iter().map(|t| self.convert_type(t)).collect())
1087 }
1088 StructFields::Named(fs) => {
1089 Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
1090 }
1091 StructFields::Unit => None,
1092 };
1093 (v.name.name.clone(), fields)
1094 })
1095 .collect();
1096
1097 self.types
1098 .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
1099 }
1100 Item::TypeAlias(t) => {
1101 let generics = t
1102 .generics
1103 .as_ref()
1104 .map(|g| {
1105 g.params
1106 .iter()
1107 .filter_map(|p| {
1108 if let GenericParam::Type { name, .. } = p {
1109 Some(name.name.clone())
1110 } else {
1111 None
1112 }
1113 })
1114 .collect()
1115 })
1116 .unwrap_or_default();
1117
1118 let target = self.convert_type(&t.ty);
1119 self.types
1120 .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
1121 }
1122 _ => {}
1123 }
1124 }
1125
1126 fn collect_fn_sig(&mut self, item: &Item) {
1128 match item {
1129 Item::Function(f) => {
1130 let params: Vec<Type> = 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 if self.functions.contains_key(&f.name.name) {
1146 self.error(TypeError::new(format!(
1147 "duplicate function definition: '{}'",
1148 f.name.name
1149 )));
1150 }
1151 self.functions.insert(f.name.name.clone(), fn_type);
1152 }
1153 Item::Impl(impl_block) => {
1154 let type_name = self.type_path_to_name(&impl_block.self_ty);
1156
1157 self.current_self_type = Some(type_name.clone());
1159
1160 if let Some(ref generics) = impl_block.generics {
1162 for param in &generics.params {
1163 if let crate::ast::GenericParam::Type { name, .. } = param {
1164 let type_var = self.fresh_var();
1165 self.current_generics.insert(name.name.clone(), type_var);
1166 }
1167 }
1168 }
1169
1170 for impl_item in &impl_block.items {
1172 if let crate::ast::ImplItem::Function(f) = impl_item {
1173 let params: Vec<Type> =
1174 f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1175
1176 let return_type = f
1177 .return_type
1178 .as_ref()
1179 .map(|t| self.convert_type(t))
1180 .unwrap_or(Type::Unit);
1181
1182 let fn_type = Type::Function {
1183 params,
1184 return_type: Box::new(return_type),
1185 is_async: f.is_async,
1186 };
1187
1188 self.impl_methods
1190 .entry(type_name.clone())
1191 .or_insert_with(HashMap::new)
1192 .insert(f.name.name.clone(), fn_type);
1193 }
1194 }
1195
1196 self.current_self_type = None;
1198 self.current_generics.clear();
1199 }
1200 _ => {}
1201 }
1202 }
1203
1204 fn type_path_to_name(&self, ty: &crate::ast::TypeExpr) -> String {
1206 match ty {
1207 crate::ast::TypeExpr::Path(path) => {
1208 path.segments
1209 .iter()
1210 .map(|s| s.ident.name.clone())
1211 .collect::<Vec<_>>()
1212 .join("::")
1213 }
1214 _ => "Unknown".to_string(),
1215 }
1216 }
1217
1218 fn check_item(&mut self, item: &Item) {
1220 match item {
1221 Item::Function(f) => self.check_function(f),
1222 Item::Const(c) => {
1223 let declared = self.convert_type(&c.ty);
1224 let inferred = self.infer_expr(&c.value);
1225 if !self.unify(&declared, &inferred) {
1226 self.error(
1227 TypeError::new(format!(
1228 "type mismatch in const '{}': expected {:?}, found {:?}",
1229 c.name.name, declared, inferred
1230 ))
1231 .with_span(c.name.span),
1232 );
1233 }
1234 }
1235 Item::Static(s) => {
1236 let declared = self.convert_type(&s.ty);
1237 let inferred = self.infer_expr(&s.value);
1238 if !self.unify(&declared, &inferred) {
1239 self.error(
1240 TypeError::new(format!(
1241 "type mismatch in static '{}': expected {:?}, found {:?}",
1242 s.name.name, declared, inferred
1243 ))
1244 .with_span(s.name.span),
1245 );
1246 }
1247 }
1248 Item::Impl(impl_block) => {
1249 let type_name = self.type_path_to_name(&impl_block.self_ty);
1251 self.current_self_type = Some(type_name);
1252
1253 if let Some(ref generics) = impl_block.generics {
1255 for param in &generics.params {
1256 if let crate::ast::GenericParam::Type { name, .. } = param {
1257 let type_var = self.fresh_var();
1258 self.current_generics.insert(name.name.clone(), type_var);
1259 }
1260 }
1261 }
1262
1263 for impl_item in &impl_block.items {
1265 if let crate::ast::ImplItem::Function(f) = impl_item {
1266 self.check_function(f);
1267 }
1268 }
1269
1270 self.current_self_type = None;
1272 self.current_generics.clear();
1273 }
1274 _ => {}
1275 }
1276 }
1277
1278 fn check_function(&mut self, func: &Function) {
1280 self.push_scope();
1281
1282 for param in &func.params {
1284 let ty = self.convert_type(¶m.ty);
1285 let type_evidence = self.get_evidence(&ty);
1288 let evidence = param
1289 .pattern
1290 .evidentiality()
1291 .map(EvidenceLevel::from_ast)
1292 .unwrap_or(type_evidence);
1293
1294 if let Some(name) = param.pattern.binding_name() {
1295 self.env.borrow_mut().define(name, ty, evidence);
1296 }
1297 }
1298
1299 let expected_return = func
1301 .return_type
1302 .as_ref()
1303 .map(|t| self.convert_type(t))
1304 .unwrap_or(Type::Unit);
1305 let old_return_type = self.expected_return_type.clone();
1306 self.expected_return_type = Some(expected_return.clone());
1307
1308 if let Some(ref body) = func.body {
1310 let body_type = self.check_block(body);
1311
1312 self.expected_return_type = old_return_type;
1314
1315 let expected_return = func
1317 .return_type
1318 .as_ref()
1319 .map(|t| self.convert_type(t))
1320 .unwrap_or(Type::Unit);
1321
1322 let _ = self.unify(&expected_return, &body_type);
1326
1327 let type_has_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1333 let name_evidence = func.name.evidentiality.as_ref()
1335 .map(|e| EvidenceLevel::from_ast(*e));
1336 let has_explicit_evidence = type_has_evidence || name_evidence.is_some();
1337 let actual_evidence = self.get_evidence(&body_type);
1338
1339 if has_explicit_evidence {
1340 if name_evidence.is_none() {
1344 let expected_evidence = self.get_evidence(&expected_return);
1345 self.check_evidence(
1346 expected_evidence,
1347 actual_evidence,
1348 &format!("in return type of '{}'", func.name.name),
1349 );
1350 }
1351 } else {
1353 if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1356 self.error(
1357 TypeError::new(format!(
1358 "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1359 func.name.name,
1360 actual_evidence.name(),
1361 actual_evidence.symbol(),
1362 ))
1363 .with_span(func.name.span)
1364 .with_note("help: add explicit evidence annotation to the return type")
1365 .with_note(format!(
1366 "example: fn {}(...) -> {}{} {{ ... }}",
1367 func.name.name,
1368 expected_return,
1369 actual_evidence.symbol()
1370 )),
1371 );
1372 }
1373 }
1375 }
1376
1377 self.pop_scope();
1378 }
1379
1380 fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1382 match ty {
1383 Some(TypeExpr::Evidential { .. }) => true,
1384 Some(TypeExpr::Reference { inner, .. })
1385 | Some(TypeExpr::Pointer { inner, .. })
1386 | Some(TypeExpr::Slice(inner))
1387 | Some(TypeExpr::Array { element: inner, .. }) => {
1388 self.type_has_explicit_evidence(Some(inner.as_ref()))
1389 }
1390 Some(TypeExpr::Tuple(elements)) => elements
1391 .iter()
1392 .any(|e| self.type_has_explicit_evidence(Some(e))),
1393 _ => false,
1394 }
1395 }
1396
1397 fn check_block(&mut self, block: &Block) -> Type {
1399 self.push_scope();
1400
1401 let mut diverges = false;
1402 for stmt in &block.stmts {
1403 let stmt_ty = self.check_stmt(stmt);
1404 if matches!(stmt_ty, Type::Never) {
1405 diverges = true;
1406 }
1407 }
1408
1409 let result = if let Some(ref expr) = block.expr {
1410 self.infer_expr(expr)
1411 } else if diverges {
1412 Type::Never
1413 } else {
1414 Type::Unit
1415 };
1416
1417 self.pop_scope();
1418 result
1419 }
1420
1421 fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1423 match stmt {
1424 Stmt::Let { pattern, ty, init } => {
1425 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1426 let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1427
1428 let final_ty = match (&declared_ty, &init_ty) {
1429 (Some(d), Some(i)) => {
1430 if !self.unify(d, i) {
1431 let binding_name = pattern.binding_name().unwrap_or_else(|| "<pattern>".to_string());
1433 let mut err = TypeError::new(format!(
1434 "type mismatch in let binding '{}': expected {:?}, found {:?}",
1435 binding_name, d, i
1436 ));
1437 if let Some(span) = pattern.binding_span() {
1438 err = err.with_span(span);
1439 }
1440 self.error(err);
1441 }
1442 d.clone()
1443 }
1444 (Some(d), None) => d.clone(),
1445 (None, Some(i)) => i.clone(),
1446 (None, None) => self.fresh_var(),
1447 };
1448
1449 let evidence = pattern
1455 .evidentiality()
1456 .map(EvidenceLevel::from_ast)
1457 .unwrap_or_else(|| {
1458 init_ty
1460 .as_ref()
1461 .map(|ty| self.get_evidence(ty))
1462 .unwrap_or(EvidenceLevel::Known)
1463 });
1464
1465 if let Some(name) = pattern.binding_name() {
1466 if pattern.is_mutable() {
1468 self.mutable_vars.insert(name.clone());
1469 }
1470 self.env.borrow_mut().define(name, final_ty, evidence);
1471 }
1472 Type::Unit
1473 }
1474 Stmt::LetElse { pattern, ty, init, else_branch } => {
1475 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1477 let init_ty = self.infer_expr(init);
1478 let evidence = pattern
1480 .evidentiality()
1481 .map(EvidenceLevel::from_ast)
1482 .unwrap_or_else(|| self.get_evidence(&init_ty));
1483 let final_ty = declared_ty.unwrap_or(init_ty);
1484 self.infer_expr(else_branch);
1486 if let Some(name) = pattern.binding_name() {
1487 self.env.borrow_mut().define(name, final_ty, evidence);
1488 }
1489 Type::Unit
1490 }
1491 Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1492 Stmt::Item(item) => {
1493 self.check_item(item);
1494 Type::Unit
1495 }
1496 }
1497 }
1498
1499 pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1501 match expr {
1502 Expr::Literal(lit) => self.infer_literal(lit),
1503
1504 Expr::Path(path) => {
1505 if path.segments.len() == 1 {
1506 let name = &path.segments[0].ident.name;
1507 if let Some((ty, _)) = self.env.borrow().lookup(name) {
1508 return ty;
1509 }
1510 if let Some(ty) = self.functions.get(name).cloned() {
1511 return self.freshen(&ty);
1513 }
1514 } else if path.segments.len() == 2 {
1515 let type_name = &path.segments[0].ident.name;
1517 let method_name = &path.segments[1].ident.name;
1518
1519 if let Some(methods) = self.impl_methods.get(type_name) {
1521 if let Some(ty) = methods.get(method_name) {
1522 let ty_cloned = ty.clone();
1523 return self.freshen(&ty_cloned);
1524 }
1525 }
1526
1527 if let Some(TypeDef::Enum { variants, .. }) = self.types.get(type_name).cloned() {
1529 for (variant_name, _variant_fields) in &variants {
1530 if variant_name == method_name {
1531 return Type::Named {
1533 name: type_name.clone(),
1534 generics: vec![],
1535 };
1536 }
1537 }
1538 let available: Vec<_> = variants.iter().map(|(n, _)| n.as_str()).collect();
1540 self.error(TypeError::new(format!(
1541 "no variant '{}' on enum '{}'. Available variants: {}",
1542 method_name, type_name, available.join(", ")
1543 )));
1544 return Type::Named {
1545 name: type_name.clone(),
1546 generics: vec![],
1547 };
1548 }
1549 }
1550 self.fresh_var()
1554 }
1555
1556 Expr::Binary { left, op, right } => {
1557 let lt = self.infer_expr(left);
1558 let rt = self.infer_expr(right);
1559 self.infer_binary_op(op, <, &rt)
1560 }
1561
1562 Expr::Unary { op, expr } => {
1563 let inner = self.infer_expr(expr);
1564 self.infer_unary_op(op, &inner)
1565 }
1566
1567 Expr::Call { func, args } => {
1568 let fn_type = self.infer_expr(func);
1569 let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1570
1571 if let Type::Function {
1572 params,
1573 return_type,
1574 ..
1575 } = fn_type
1576 {
1577 if params.len() != arg_types.len() {
1579 self.error(TypeError::new(format!(
1580 "expected {} arguments, found {}",
1581 params.len(),
1582 arg_types.len()
1583 )));
1584 }
1585
1586 for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1588 if !self.unify(param, arg) {
1590 let is_numeric_coercion = Self::is_numeric_coercion(param, arg);
1592 if !matches!(param, Type::Var(_)) && !matches!(arg, Type::Var(_)) && !is_numeric_coercion {
1594 self.error(TypeError::new(format!(
1595 "type mismatch in argument {}: expected {}, found {}",
1596 i + 1, param, arg
1597 )));
1598 }
1599 }
1600
1601 if !matches!(param, Type::Var(_)) {
1605 let expected_evidence = self.get_evidence(param);
1606 let actual_evidence = self.get_evidence(arg);
1607 self.check_evidence(
1608 expected_evidence,
1609 actual_evidence,
1610 &format!("in argument {}", i + 1),
1611 );
1612 }
1613 }
1614
1615 *return_type
1616 } else if let Type::Var(_) = &fn_type {
1617 let result_ty = self.fresh_var();
1620 let inferred_fn = Type::Function {
1621 params: arg_types,
1622 return_type: Box::new(result_ty.clone()),
1623 is_async: false,
1624 };
1625 self.unify(&fn_type, &inferred_fn);
1626 result_ty
1627 } else {
1628 self.fresh_var()
1630 }
1631 }
1632
1633 Expr::Array(elements) => {
1634 if elements.is_empty() {
1635 Type::Array {
1636 element: Box::new(self.fresh_var()),
1637 size: Some(0),
1638 }
1639 } else {
1640 let elem_ty = self.infer_expr(&elements[0]);
1641 for elem in &elements[1..] {
1642 let t = self.infer_expr(elem);
1643 if !self.unify(&elem_ty, &t) {
1644 self.error(TypeError::new("array elements must have same type"));
1645 }
1646 }
1647 Type::Array {
1648 element: Box::new(elem_ty),
1649 size: Some(elements.len()),
1650 }
1651 }
1652 }
1653
1654 Expr::Tuple(elements) => {
1655 Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1656 }
1657
1658 Expr::Block(block) => self.check_block(block),
1659
1660 Expr::If {
1661 condition,
1662 then_branch,
1663 else_branch,
1664 } => {
1665 let cond_ty = self.infer_expr(condition);
1666 if !self.unify(&Type::Bool, &cond_ty) {
1667 self.error(TypeError::new("if condition must be bool"));
1668 }
1669
1670 let then_ty = self.check_block(then_branch);
1671
1672 if let Some(else_expr) = else_branch {
1673 let else_ty = match else_expr.as_ref() {
1675 Expr::Block(block) => self.check_block(block),
1676 other => self.infer_expr(other),
1677 };
1678 let _ = self.unify(&then_ty, &else_ty);
1681
1682 let then_ev = self.get_evidence(&then_ty);
1687 let else_ev = self.get_evidence(&else_ty);
1688 let joined_ev = then_ev.join(else_ev);
1689
1690 let (inner_ty, _) = self.strip_evidence(&then_ty);
1691 if joined_ev > EvidenceLevel::Known {
1692 Type::Evidential {
1693 inner: Box::new(inner_ty),
1694 evidence: joined_ev,
1695 }
1696 } else {
1697 inner_ty
1698 }
1699 } else {
1700 Type::Unit
1701 }
1702 }
1703
1704 Expr::While {
1705 condition,
1706 body,
1707 ..
1708 } => {
1709 let cond_ty = self.infer_expr(condition);
1710 if !self.unify(&Type::Bool, &cond_ty) {
1711 self.error(TypeError::new("while condition must be bool"));
1712 }
1713 self.check_block(body);
1714 Type::Unit
1715 }
1716
1717 Expr::Loop { body, .. } => {
1718 self.check_block(body);
1719 Type::Unit
1720 }
1721
1722 Expr::For {
1723 pattern: _,
1724 iter,
1725 body,
1726 ..
1727 } => {
1728 let _ = self.infer_expr(iter);
1730 self.check_block(body);
1731 Type::Unit
1732 }
1733
1734 Expr::Pipe { expr, operations } => {
1735 let mut current = self.infer_expr(expr);
1736
1737 for op in operations {
1738 current = self.infer_pipe_op(op, ¤t);
1739 }
1740
1741 current
1742 }
1743
1744 Expr::Index { expr, index } => {
1745 let coll_ty = self.infer_expr(expr);
1746 let idx_ty = self.infer_expr(index);
1747
1748 if let Expr::Unary { op: UnaryOp::Neg, expr: inner } = index.as_ref() {
1750 if let Expr::Literal(Literal::Int { .. }) = inner.as_ref() {
1751 self.error(TypeError::new("negative index is not allowed"));
1752 }
1753 }
1754
1755 match coll_ty {
1756 Type::Array { element, .. } | Type::Slice(element) => {
1757 if !matches!(idx_ty, Type::Int(_)) {
1758 self.error(TypeError::new("index must be integer"));
1759 }
1760 *element
1761 }
1762 _ => {
1763 self.fresh_var()
1765 }
1766 }
1767 }
1768
1769 Expr::Return(val) => {
1770 let actual_type = if let Some(e) = val {
1771 self.infer_expr(e)
1772 } else {
1773 Type::Unit
1774 };
1775
1776 if let Some(expected) = self.expected_return_type.clone() {
1778 if !self.unify(&expected, &actual_type) {
1779 self.error(TypeError::new(format!(
1780 "type mismatch in return: expected {}, found {}",
1781 expected, actual_type
1782 )));
1783 }
1784 }
1785
1786 Type::Never
1787 }
1788
1789 Expr::Assign { target, value } => {
1791 if let Expr::Path(path) = target.as_ref() {
1793 if path.segments.len() == 1 {
1794 let name = &path.segments[0].ident.name;
1795 if !self.mutable_vars.contains(name) {
1797 self.error(TypeError::new(format!(
1798 "cannot assign to immutable variable '{}'",
1799 name
1800 )));
1801 }
1802 }
1803 }
1804 let val_ty = self.infer_expr(value);
1806 let target_ty = self.infer_expr(target);
1808 if !self.unify(&target_ty, &val_ty) {
1809 self.error(TypeError::new(format!(
1810 "type mismatch in assignment: expected {}, found {}",
1811 target_ty, val_ty
1812 )));
1813 }
1814 Type::Unit
1815 }
1816
1817 Expr::Evidential {
1819 expr,
1820 evidentiality,
1821 } => {
1822 let inner = self.infer_expr(expr);
1823 Type::Evidential {
1824 inner: Box::new(inner),
1825 evidence: EvidenceLevel::from_ast(*evidentiality),
1826 }
1827 }
1828
1829 Expr::Match { expr, arms } => {
1831 let scrutinee = self.infer_expr(expr);
1832 let scrutinee_ev = self.get_evidence(&scrutinee);
1833
1834 if arms.is_empty() {
1835 return Type::Never; }
1837
1838 let mut arm_types: Vec<Type> = Vec::new();
1840 let mut max_evidence = EvidenceLevel::Known;
1841
1842 for arm in arms {
1843 self.push_scope();
1844
1845 self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
1848
1849 if let Some(ref guard) = arm.guard {
1851 let guard_ty = self.infer_expr(guard);
1852 if !self.unify(&Type::Bool, &guard_ty) {
1853 self.error(TypeError::new("match guard must be bool"));
1854 }
1855 }
1856
1857 let body_ty = self.infer_expr(&arm.body);
1859 let body_ev = self.get_evidence(&body_ty);
1860
1861 max_evidence = max_evidence.join(body_ev);
1863 arm_types.push(body_ty);
1864
1865 self.pop_scope();
1866 }
1867
1868 let first_ty = &arm_types[0];
1870 for (i, ty) in arm_types.iter().enumerate().skip(1) {
1871 if !self.unify(first_ty, ty) {
1872 self.error(TypeError::new(format!(
1873 "type mismatch in match arm {}: expected {:?}, found {:?}",
1874 i + 1, first_ty, ty
1875 )));
1876 }
1877 }
1878
1879 let (inner_ty, _) = self.strip_evidence(first_ty);
1881 if max_evidence > EvidenceLevel::Known {
1882 Type::Evidential {
1883 inner: Box::new(inner_ty),
1884 evidence: max_evidence,
1885 }
1886 } else {
1887 inner_ty
1888 }
1889 }
1890
1891 Expr::MethodCall {
1892 receiver,
1893 method,
1894 args,
1895 ..
1896 } => {
1897 let recv_ty = self.infer_expr(receiver);
1898 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
1899 let _arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1900
1901 let result_ty = match method.name.as_str() {
1903 "len" | "count" | "size" => Type::Int(IntSize::USize),
1905
1906 "is_empty" | "contains" | "starts_with" | "ends_with" | "is_some"
1908 | "is_none" | "is_ok" | "is_err" | "is_ascii" | "is_alphabetic"
1909 | "is_numeric" | "is_alphanumeric" | "is_whitespace" | "is_uppercase"
1910 | "is_lowercase" | "exists" | "is_file" | "is_dir" | "is_match"
1911 | "matches" | "eq" | "ne" | "lt" | "le" | "gt" | "ge" => Type::Bool,
1912
1913 "to_string" | "to_lowercase" | "to_uppercase" | "trim" | "trim_start"
1915 | "trim_end" | "to_owned" | "replace" | "replacen" | "repeat"
1916 | "to_string_lossy" => Type::Named {
1917 name: "String".to_string(),
1918 generics: vec![],
1919 },
1920
1921 "as_str" | "trim_matches" | "trim_start_matches" | "trim_end_matches"
1923 | "strip_prefix" | "strip_suffix" => Type::Ref {
1924 lifetime: None,
1925 mutable: false,
1926 inner: Box::new(Type::Str),
1927 },
1928
1929 "clone" | "cloned" | "copied" => recv_inner.clone(),
1931
1932 "unwrap" | "unwrap_or" | "unwrap_or_default" | "unwrap_or_else"
1934 | "expect" | "ok" | "err" => {
1935 if let Type::Named { name, generics } = &recv_inner {
1936 if (name == "Option" || name == "Result") && !generics.is_empty() {
1937 generics[0].clone()
1938 } else {
1939 self.fresh_var()
1940 }
1941 } else {
1942 self.fresh_var()
1943 }
1944 }
1945
1946 "collect" => self.fresh_var(),
1948
1949 "iter" | "into_iter" | "iter_mut" | "rev" | "skip" | "take"
1951 | "filter" | "map" | "filter_map" | "flat_map" | "enumerate"
1952 | "zip" | "chain" | "flatten" | "reverse" | "sorted"
1953 | "dedup" | "unique" | "peekable" | "fuse" | "cycle" | "step_by"
1954 | "take_while" | "skip_while" | "scan" | "inspect" => recv_inner.clone(),
1955
1956 "split" | "rsplit" | "splitn" | "rsplitn" | "split_whitespace"
1958 | "split_ascii_whitespace" | "lines" | "chars" | "bytes"
1959 | "char_indices" | "split_terminator" | "rsplit_terminator"
1960 | "split_inclusive" | "matches_iter" => self.fresh_var(),
1961
1962 "keys" | "values" | "values_mut" | "into_keys"
1964 | "into_values" | "entry" | "drain" => self.fresh_var(),
1965
1966 "first" | "last" | "get" | "get_mut" | "pop" | "pop_front"
1968 | "pop_back" | "find" | "find_map" | "position" | "rposition"
1969 | "next" | "next_back" | "peek" | "nth" | "last_mut"
1970 | "binary_search" | "parent" | "file_name" | "file_stem"
1971 | "extension" => Type::Named {
1972 name: "Option".to_string(),
1973 generics: vec![self.fresh_var()],
1974 },
1975
1976 "parse" | "try_into" | "try_from" => Type::Named {
1978 name: "Result".to_string(),
1979 generics: vec![self.fresh_var(), self.fresh_var()],
1980 },
1981
1982 "push" => {
1984 if let Type::Named { name, generics } = &recv_inner {
1986 if name == "Vec" && !generics.is_empty() && !_arg_types.is_empty() {
1987 let elem_ty = &generics[0];
1988 let arg_ty = &_arg_types[0];
1989 if !self.unify(elem_ty, arg_ty) {
1990 self.error(TypeError::new(format!(
1991 "type mismatch in Vec::push: expected {}, found {}",
1992 elem_ty, arg_ty
1993 )));
1994 }
1995 }
1996 }
1997 Type::Unit
1998 }
1999
2000 "push_str" | "push_front" | "push_back" | "insert"
2002 | "remove" | "clear" | "sort" | "sort_by" | "sort_by_key"
2003 | "sort_unstable" | "truncate" | "resize" | "extend" | "append"
2004 | "retain" | "swap" | "swap_remove" => Type::Unit,
2005
2006 "abs" | "floor" | "ceil" | "round" | "trunc" | "fract" | "sqrt"
2008 | "cbrt" | "sin" | "cos" | "tan" | "asin" | "acos" | "atan"
2009 | "sinh" | "cosh" | "tanh" | "exp" | "exp2" | "ln" | "log"
2010 | "log2" | "log10" | "pow" | "powi" | "powf" | "min" | "max"
2011 | "clamp" | "signum" | "copysign" | "saturating_add"
2012 | "saturating_sub" | "saturating_mul" | "wrapping_add"
2013 | "wrapping_sub" | "wrapping_mul" | "checked_add" | "checked_sub"
2014 | "checked_mul" | "checked_div" => recv_inner.clone(),
2015
2016 "to_digit" | "to_lowercase_char" | "to_uppercase_char" => Type::Named {
2018 name: "Option".to_string(),
2019 generics: vec![Type::Int(IntSize::U32)],
2020 },
2021
2022 "duration_since" | "elapsed" | "as_secs" | "as_millis" | "as_micros"
2024 | "as_nanos" | "from_secs" | "from_millis" => recv_inner.clone(),
2025
2026 "to_path_buf" | "join" | "with_extension" | "with_file_name" => {
2028 Type::Named {
2029 name: "PathBuf".to_string(),
2030 generics: vec![],
2031 }
2032 }
2033
2034 "to_str" => Type::Named {
2036 name: "Option".to_string(),
2037 generics: vec![Type::Ref {
2038 lifetime: None,
2039 mutable: false,
2040 inner: Box::new(Type::Str),
2041 }],
2042 },
2043
2044 "fmt" | "write_str" | "write_fmt" => Type::Named {
2046 name: "Result".to_string(),
2047 generics: vec![Type::Unit, self.fresh_var()],
2048 },
2049
2050 "read" | "write" | "flush" | "read_to_string" | "read_to_end"
2052 | "read_line" | "write_all" => Type::Named {
2053 name: "Result".to_string(),
2054 generics: vec![self.fresh_var(), self.fresh_var()],
2055 },
2056
2057 "metadata" | "modified" | "created" | "accessed" | "len_file"
2059 | "is_readonly" | "permissions" => Type::Named {
2060 name: "Result".to_string(),
2061 generics: vec![self.fresh_var(), self.fresh_var()],
2062 },
2063
2064 "map_err" | "and_then" | "or_else" => recv_inner.clone(),
2066
2067 "and" | "or" => recv_inner.clone(),
2069
2070 _ => {
2072 let is_primitive = matches!(
2074 &recv_inner,
2075 Type::Int(_) | Type::Float(_) | Type::Bool | Type::Char | Type::Str | Type::Unit
2076 );
2077 if is_primitive {
2078 self.error(TypeError::new(format!(
2079 "no method '{}' on primitive type {:?}",
2080 method.name, recv_inner
2081 )));
2082 }
2083 self.fresh_var()
2084 }
2085 };
2086
2087 if recv_ev > EvidenceLevel::Known {
2089 Type::Evidential {
2090 inner: Box::new(result_ty),
2091 evidence: recv_ev,
2092 }
2093 } else {
2094 result_ty
2095 }
2096 }
2097
2098 Expr::Field { expr, field } => {
2099 let recv_ty = self.infer_expr(expr);
2100 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
2101
2102 let field_ty = if let Type::Named { name, .. } = &recv_inner {
2104 if let Some(struct_def) = self.types.get(name) {
2106 if let TypeDef::Struct { fields, .. } = struct_def {
2107 if let Some((_, ty)) = fields.iter().find(|(n, _)| n == &field.name) {
2108 ty.clone()
2109 } else {
2110 let available: Vec<_> = fields.iter().map(|(n, _)| n.as_str()).collect();
2112 self.error(TypeError::new(format!(
2113 "no field '{}' on type '{}'. Available fields: {}",
2114 field.name, name, available.join(", ")
2115 )));
2116 self.fresh_var()
2117 }
2118 } else {
2119 self.fresh_var()
2120 }
2121 } else {
2122 self.fresh_var()
2123 }
2124 } else {
2125 self.fresh_var()
2126 };
2127
2128 if recv_ev > EvidenceLevel::Known {
2130 Type::Evidential {
2131 inner: Box::new(field_ty),
2132 evidence: recv_ev,
2133 }
2134 } else {
2135 field_ty
2136 }
2137 }
2138
2139 Expr::Index { expr, index, .. } => {
2140 let arr_ty = self.infer_expr(expr);
2141 let idx_ty = self.infer_expr(index);
2142 let (arr_inner, arr_ev) = self.strip_evidence(&arr_ty);
2143
2144 let _ = self.unify(&idx_ty, &Type::Int(IntSize::USize));
2146
2147 let elem_ty = match arr_inner {
2149 Type::Array { element, .. } => *element,
2150 Type::Slice(element) => *element,
2151 Type::Named { name, generics } if name == "Vec" && !generics.is_empty() => {
2152 generics[0].clone()
2153 }
2154 _ => self.fresh_var(),
2155 };
2156
2157 if arr_ev > EvidenceLevel::Known {
2159 Type::Evidential {
2160 inner: Box::new(elem_ty),
2161 evidence: arr_ev,
2162 }
2163 } else {
2164 elem_ty
2165 }
2166 }
2167
2168 Expr::Struct { path, fields, rest: _ } => {
2169 let struct_name = path.segments.first()
2171 .map(|s| s.ident.name.clone())
2172 .unwrap_or_default();
2173
2174 if let Some(TypeDef::Struct { fields: struct_fields, generics }) = self.types.get(&struct_name).cloned() {
2176 for field_init in fields {
2178 let field_name = &field_init.name.name;
2179 if !struct_fields.iter().any(|(n, _)| n == field_name) {
2180 self.error(TypeError::new(format!(
2181 "unknown field '{}' on struct '{}'",
2182 field_name, struct_name
2183 )));
2184 }
2185 if let Some(ref value) = field_init.value {
2187 self.infer_expr(value);
2188 }
2189 }
2190
2191 let provided: std::collections::HashSet<_> = fields.iter().map(|f| f.name.name.as_str()).collect();
2193 for (field_name, _) in &struct_fields {
2194 if !provided.contains(field_name.as_str()) {
2195 self.error(TypeError::new(format!(
2196 "missing field '{}' in struct '{}'",
2197 field_name, struct_name
2198 )));
2199 }
2200 }
2201
2202 Type::Named {
2204 name: struct_name,
2205 generics: generics.iter().map(|_| self.fresh_var()).collect(),
2206 }
2207 } else {
2208 self.error(TypeError::new(format!(
2210 "unknown struct type '{}'",
2211 struct_name
2212 )));
2213 self.fresh_var()
2214 }
2215 }
2216
2217 _ => {
2218 self.fresh_var()
2220 }
2221 }
2222 }
2223
2224 fn infer_literal(&self, lit: &Literal) -> Type {
2226 match lit {
2227 Literal::Int { .. } => Type::Int(IntSize::I64),
2228 Literal::Float { suffix, .. } => {
2229 match suffix.as_ref().map(|s| s.as_str()) {
2230 Some("f32") => Type::Float(FloatSize::F32),
2231 Some("f64") => Type::Float(FloatSize::F64),
2232 None | Some(_) => Type::Float(FloatSize::F64),
2234 }
2235 }
2236 Literal::Bool(_) => Type::Bool,
2237 Literal::Char(_) => Type::Char,
2238 Literal::ByteChar(_) => Type::Int(IntSize::U8),
2239 Literal::String(_) => Type::Ref {
2241 lifetime: None,
2242 mutable: false,
2243 inner: Box::new(Type::Str),
2244 },
2245 Literal::MultiLineString(_) => Type::Ref {
2246 lifetime: None,
2247 mutable: false,
2248 inner: Box::new(Type::Str),
2249 },
2250 Literal::RawString(_) => Type::Ref {
2251 lifetime: None,
2252 mutable: false,
2253 inner: Box::new(Type::Str),
2254 },
2255 Literal::ByteString(bytes) => Type::Ref {
2256 lifetime: None,
2257 mutable: false,
2258 inner: Box::new(Type::Array {
2259 element: Box::new(Type::Int(IntSize::U8)),
2260 size: Some(bytes.len()),
2261 }),
2262 },
2263 Literal::InterpolatedString { .. } => Type::Str,
2264 Literal::SigilStringSql(_) => Type::Str,
2265 Literal::SigilStringRoute(_) => Type::Str,
2266 Literal::Null => Type::Unit, Literal::Empty => Type::Unit,
2268 Literal::Infinity => Type::Float(FloatSize::F64),
2269 Literal::Circle => Type::Float(FloatSize::F64),
2270 }
2271 }
2272
2273 fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
2275 let (left_inner, left_ev) = self.strip_evidence(left);
2277 let (right_inner, right_ev) = self.strip_evidence(right);
2278
2279 let is_var_or_fn = |ty: &Type| {
2281 matches!(ty, Type::Var(_) | Type::Function { .. })
2282 };
2283
2284 let result_ty = match op {
2285 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
2287 let _ = self.unify(&left_inner, &right_inner);
2290 left_inner
2291 }
2292
2293 BinOp::MatMul | BinOp::Hadamard | BinOp::TensorProd => {
2297 self.fresh_var()
2299 }
2300
2301 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
2303 if !self.unify(&left_inner, &right_inner)
2306 && !is_var_or_fn(&left_inner)
2307 && !is_var_or_fn(&right_inner)
2308 {
2309 self.error(TypeError::new(format!(
2310 "comparison operands must have same type: left={:?}, right={:?}",
2311 left_inner, right_inner
2312 )));
2313 }
2314 Type::Bool
2315 }
2316
2317 BinOp::And | BinOp::Or => {
2319 if !self.unify(&Type::Bool, &left_inner) {
2320 self.error(TypeError::new("logical operand must be bool"));
2321 }
2322 if !self.unify(&Type::Bool, &right_inner) {
2323 self.error(TypeError::new("logical operand must be bool"));
2324 }
2325 Type::Bool
2326 }
2327
2328 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
2330
2331 BinOp::Concat => {
2333 if !self.unify(&Type::Str, &left_inner) {
2334 self.error(TypeError::new("concat operand must be string"));
2335 }
2336 Type::Str
2337 }
2338 };
2339
2340 let combined_ev = left_ev.join(right_ev);
2342
2343 if combined_ev > EvidenceLevel::Known {
2345 Type::Evidential {
2346 inner: Box::new(result_ty),
2347 evidence: combined_ev,
2348 }
2349 } else {
2350 result_ty
2351 }
2352 }
2353
2354 fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
2356 let (inner_ty, evidence) = self.strip_evidence(inner);
2357
2358 let result = match op {
2359 UnaryOp::Neg => inner_ty,
2360 UnaryOp::Not => {
2361 if !self.unify(&Type::Bool, &inner_ty) {
2363 self.error(TypeError::new(format!(
2364 "type mismatch: '!' requires bool, found {}",
2365 inner_ty
2366 )));
2367 }
2368 Type::Bool
2369 }
2370 UnaryOp::Ref => Type::Ref {
2371 lifetime: None,
2372 mutable: false,
2373 inner: Box::new(inner_ty),
2374 },
2375 UnaryOp::RefMut => Type::Ref {
2376 lifetime: None,
2377 mutable: true,
2378 inner: Box::new(inner_ty),
2379 },
2380 UnaryOp::Deref => {
2381 if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
2382 *inner
2383 } else {
2384 self.fresh_var()
2386 }
2387 }
2388 };
2389
2390 if evidence > EvidenceLevel::Known {
2392 Type::Evidential {
2393 inner: Box::new(result),
2394 evidence,
2395 }
2396 } else {
2397 result
2398 }
2399 }
2400
2401 fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
2403 let (inner_ev_stripped, evidence) = self.strip_evidence(input);
2404
2405 let inner = match inner_ev_stripped {
2408 Type::Ref { inner: ref_inner, .. } => (*ref_inner).clone(),
2409 other => other,
2410 };
2411
2412 let result = match op {
2413 PipeOp::Transform(_body) => {
2415 if let Type::Array { element, size } = inner {
2416 Type::Array { element, size }
2417 } else if let Type::Slice(element) = inner {
2418 Type::Slice(element)
2419 } else {
2420 self.fresh_var()
2422 }
2423 }
2424
2425 PipeOp::Filter(_pred) => inner,
2427
2428 PipeOp::Sort(_) => inner,
2430
2431 PipeOp::Reduce(_) => {
2433 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2434 *element
2435 } else if let Type::Named { name, generics } = &inner {
2436 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2438 && !generics.is_empty() {
2439 generics[0].clone()
2440 } else {
2441 self.fresh_var()
2442 }
2443 } else if let Type::Var(_) = inner {
2444 self.fresh_var()
2446 } else {
2447 self.error(TypeError::new("reduce requires array or slice"));
2448 Type::Error
2449 }
2450 }
2451 PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
2452 let element = if let Type::Array { element, .. } | Type::Slice(element) = &inner {
2454 Some(element.clone())
2455 } else if let Type::Named { name, generics } = &inner {
2456 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2458 && !generics.is_empty() {
2459 Some(Box::new(generics[0].clone()))
2460 } else {
2461 None
2462 }
2463 } else {
2464 None
2465 };
2466 if let Some(element) = element {
2467 match element.as_ref() {
2468 Type::Int(_) | Type::Float(_) => *element,
2469 Type::Var(_) => *element, _ => {
2471 self.error(TypeError::new("numeric reduction requires numeric array"));
2472 Type::Error
2473 }
2474 }
2475 } else if let Type::Var(_) = inner {
2476 self.fresh_var()
2478 } else {
2479 self.error(TypeError::new("reduction requires array or slice"));
2480 Type::Error
2481 }
2482 }
2483 PipeOp::ReduceConcat => {
2484 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2486 match element.as_ref() {
2487 Type::Str => Type::Str,
2488 Type::Array { .. } => *element,
2489 Type::Var(_) => self.fresh_var(), _ => {
2491 self.error(TypeError::new(
2492 "concat reduction requires array of strings or arrays",
2493 ));
2494 Type::Error
2495 }
2496 }
2497 } else if let Type::Var(_) = inner {
2498 self.fresh_var()
2500 } else {
2501 self.error(TypeError::new("concat reduction requires array or slice"));
2502 Type::Error
2503 }
2504 }
2505 PipeOp::ReduceAll | PipeOp::ReduceAny => {
2506 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2508 match element.as_ref() {
2509 Type::Bool => Type::Bool,
2510 Type::Var(_) => Type::Bool, _ => {
2512 self.error(TypeError::new(
2513 "boolean reduction requires array of booleans",
2514 ));
2515 Type::Error
2516 }
2517 }
2518 } else if let Type::Var(_) = inner {
2519 Type::Bool
2521 } else {
2522 self.error(TypeError::new("boolean reduction requires array or slice"));
2523 Type::Error
2524 }
2525 }
2526
2527 PipeOp::Match(arms) => {
2529 if arms.is_empty() {
2531 self.error(TypeError::new("match expression has no arms"));
2532 Type::Error
2533 } else {
2534 let result_type = self.infer_expr(&arms[0].body);
2536 for arm in arms.iter().skip(1) {
2537 let arm_type = self.infer_expr(&arm.body);
2538 self.unify(&result_type, &arm_type);
2539 }
2540 result_type
2541 }
2542 }
2543
2544 PipeOp::TryMap(_) => {
2546 self.fresh_var()
2550 }
2551
2552 PipeOp::Call(callee) => {
2554 let callee_ty = self.infer_expr(callee);
2556 if let Type::Function { return_type, .. } = callee_ty {
2557 *return_type
2558 } else {
2559 self.fresh_var()
2561 }
2562 }
2563
2564 PipeOp::Method { name, type_args: _, args: _ } => {
2566 if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
2568 let fresh_ty = self.freshen(&fn_ty);
2570 if let Type::Function { return_type, .. } = fresh_ty {
2571 *return_type
2572 } else {
2573 Type::Error
2574 }
2575 } else {
2576 self.fresh_var()
2578 }
2579 }
2580
2581 PipeOp::Named { prefix, body: _ } => {
2583 if let Some(first) = prefix.first() {
2585 match first.name.as_str() {
2586 "sum" | "product" => {
2587 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2588 *element
2589 } else {
2590 self.error(TypeError::new("sum/product requires array"));
2591 Type::Error
2592 }
2593 }
2594 _ => self.fresh_var(),
2595 }
2596 } else {
2597 self.fresh_var()
2598 }
2599 }
2600
2601 PipeOp::Await => {
2603 inner
2605 }
2606
2607 PipeOp::First
2609 | PipeOp::Last
2610 | PipeOp::Middle
2611 | PipeOp::Choice
2612 | PipeOp::Nth(_)
2613 | PipeOp::Next => {
2614 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2615 *element
2616 } else if let Type::Named { name, generics } = &inner {
2617 if (name == "Vec" || name == "VecDeque" || name == "LinkedList")
2619 && !generics.is_empty() {
2620 generics[0].clone()
2621 } else {
2622 self.fresh_var()
2623 }
2624 } else if let Type::Tuple(elements) = inner {
2625 if let Some(first) = elements.first() {
2627 first.clone()
2628 } else {
2629 Type::Unit
2630 }
2631 } else if let Type::Var(_) = inner {
2632 self.fresh_var()
2634 } else {
2635 self.fresh_var()
2637 }
2638 }
2639
2640 PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
2643
2644 PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
2647
2648 PipeOp::Send(_) => {
2655 Type::Evidential {
2657 inner: Box::new(self.fresh_var()),
2658 evidence: EvidenceLevel::Reported,
2659 }
2660 }
2661
2662 PipeOp::Recv => {
2664 Type::Evidential {
2666 inner: Box::new(self.fresh_var()),
2667 evidence: EvidenceLevel::Reported,
2668 }
2669 }
2670
2671 PipeOp::Stream(_) => {
2673 self.fresh_var()
2675 }
2676
2677 PipeOp::Connect(_) => {
2679 self.fresh_var()
2681 }
2682
2683 PipeOp::Close => Type::Unit,
2685
2686 PipeOp::Header { .. } => inner,
2688
2689 PipeOp::Body(_) => inner,
2691
2692 PipeOp::Timeout(_) => inner,
2694
2695 PipeOp::Retry { .. } => inner,
2697
2698 PipeOp::Validate {
2704 predicate: _,
2705 target_evidence,
2706 } => {
2707 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2711
2712 if evidence < target_ev {
2714 self.error(
2715 TypeError::new(format!(
2716 "cannot demote evidence from {} ({}) to {} ({}) using validate",
2717 evidence.name(),
2718 evidence.symbol(),
2719 target_ev.name(),
2720 target_ev.symbol()
2721 ))
2722 .with_note("validate! can only promote evidence to a more certain level"),
2723 );
2724 }
2725
2726 return Type::Evidential {
2728 inner: Box::new(inner.clone()),
2729 evidence: target_ev,
2730 };
2731 }
2732
2733 PipeOp::Assume {
2735 reason: _,
2736 target_evidence,
2737 } => {
2738 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2739
2740 if evidence < target_ev {
2744 self.error(
2745 TypeError::new(format!(
2746 "assume! cannot demote evidence from {} ({}) to {} ({})",
2747 evidence.name(),
2748 evidence.symbol(),
2749 target_ev.name(),
2750 target_ev.symbol()
2751 ))
2752 .with_note("assume! is for promoting evidence, not demoting"),
2753 );
2754 }
2755
2756 return Type::Evidential {
2758 inner: Box::new(inner.clone()),
2759 evidence: target_ev,
2760 };
2761 }
2762
2763 PipeOp::AssertEvidence(expected_ast) => {
2765 let expected = EvidenceLevel::from_ast(*expected_ast);
2766
2767 if !evidence.satisfies(expected) {
2768 self.error(
2769 TypeError::new(format!(
2770 "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
2771 expected.name(), expected.symbol(),
2772 evidence.name(), evidence.symbol()
2773 ))
2774 .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
2775 );
2776 }
2777
2778 return input.clone();
2780 }
2781
2782 PipeOp::Also(_) => {
2789 return input.clone();
2792 }
2793
2794 PipeOp::Apply(_) => {
2797 return input.clone();
2800 }
2801
2802 PipeOp::TakeIf(_) => {
2805 return Type::Named {
2808 name: "Option".to_string(),
2809 generics: vec![input.clone()],
2810 };
2811 }
2812
2813 PipeOp::TakeUnless(_) => {
2816 return Type::Named {
2819 name: "Option".to_string(),
2820 generics: vec![input.clone()],
2821 };
2822 }
2823
2824 PipeOp::Let(func) => {
2827 let _ = self.infer_expr(func);
2829 self.fresh_var() }
2831
2832 PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
2834 PipeOp::Compose(f) => {
2835 let _ = self.infer_expr(f);
2836 self.fresh_var()
2837 }
2838 PipeOp::Zip(other) => {
2839 let _ = self.infer_expr(other);
2840 self.fresh_var() }
2842 PipeOp::Scan(f) => {
2843 let _ = self.infer_expr(f);
2844 self.fresh_var() }
2846 PipeOp::Diff => self.fresh_var(), PipeOp::Gradient(var) => {
2848 let _ = self.infer_expr(var);
2849 self.fresh_var() }
2851 PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
2852 inner.clone() }
2854 PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
2855 let _ = self.infer_expr(n);
2856 self.fresh_var() }
2858 PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
2859 PipeOp::Enumerate => self.fresh_var(), };
2861
2862 if evidence > EvidenceLevel::Known {
2864 Type::Evidential {
2865 inner: Box::new(result),
2866 evidence,
2867 }
2868 } else {
2869 result
2870 }
2871 }
2872
2873 fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
2875 match ty {
2876 Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
2877 _ => (ty.clone(), EvidenceLevel::Known),
2878 }
2879 }
2880
2881 fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
2884 let (inner_ty, ty_ev) = self.strip_evidence(ty);
2885 let final_ev = evidence.join(ty_ev);
2887
2888 match pattern {
2889 Pattern::Ident {
2890 name,
2891 evidentiality,
2892 ..
2893 } => {
2894 let ev = evidentiality
2896 .map(EvidenceLevel::from_ast)
2897 .unwrap_or(final_ev);
2898 self.env
2899 .borrow_mut()
2900 .define(name.name.clone(), inner_ty, ev);
2901 }
2902 Pattern::Tuple(patterns) => {
2903 if let Type::Tuple(types) = &inner_ty {
2904 for (pat, ty) in patterns.iter().zip(types.iter()) {
2905 self.bind_pattern(pat, ty, final_ev);
2906 }
2907 }
2908 }
2909 Pattern::Struct { fields, .. } => {
2910 for field in fields {
2913 let fresh = self.fresh_var();
2914 if let Some(ref pat) = field.pattern {
2915 self.bind_pattern(pat, &fresh, final_ev);
2916 } else {
2917 self.env
2918 .borrow_mut()
2919 .define(field.name.name.clone(), fresh, final_ev);
2920 }
2921 }
2922 }
2923 Pattern::TupleStruct { fields, .. } => {
2924 for pat in fields {
2925 let fresh = self.fresh_var();
2926 self.bind_pattern(pat, &fresh, final_ev);
2927 }
2928 }
2929 Pattern::Slice(patterns) => {
2930 let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
2931 {
2932 *element.clone()
2933 } else {
2934 self.fresh_var()
2935 };
2936 for pat in patterns {
2937 self.bind_pattern(pat, &elem_ty, final_ev);
2938 }
2939 }
2940 Pattern::Or(patterns) => {
2941 if let Some(first) = patterns.first() {
2944 self.bind_pattern(first, ty, evidence);
2945 }
2946 }
2947 Pattern::Wildcard | Pattern::Rest | Pattern::Literal(_) | Pattern::Range { .. } | Pattern::Path(_) => {
2948 }
2950 Pattern::Ref { pattern, .. } => {
2951 let inner_ty = self.fresh_var();
2954 self.bind_pattern(pattern, &inner_ty, final_ev);
2955 }
2956 Pattern::RefBinding {
2957 name,
2958 evidentiality,
2959 ..
2960 } => {
2961 let ev = evidentiality
2963 .map(EvidenceLevel::from_ast)
2964 .unwrap_or(final_ev);
2965 self.env
2966 .borrow_mut()
2967 .define(name.name.clone(), inner_ty, ev);
2968 }
2969 }
2970 }
2971
2972 fn resolve_alias(&self, ty: &Type) -> Type {
2974 if let Type::Named { name, generics } = ty {
2975 if generics.is_empty() {
2976 if let Some(TypeDef::Alias { target, .. }) = self.types.get(name) {
2977 return target.clone();
2978 }
2979 }
2980 }
2981 ty.clone()
2982 }
2983
2984 fn unify(&mut self, a: &Type, b: &Type) -> bool {
2986 let a = self.resolve_alias(a);
2988 let b = self.resolve_alias(b);
2989
2990 match (&a, &b) {
2991 (Type::Var(v), t) => {
2993 if let Some(resolved) = self.substitutions.get(v) {
2994 let resolved = resolved.clone();
2995 self.unify(&resolved, t)
2996 } else if !self.occurs_in(v, t) {
2997 self.substitutions.insert(*v, t.clone());
2998 true
2999 } else {
3000 true
3002 }
3003 }
3004 (t, Type::Var(v)) => {
3005 if let Some(resolved) = self.substitutions.get(v) {
3006 let resolved = resolved.clone();
3007 self.unify(t, &resolved)
3008 } else if !self.occurs_in(v, t) {
3009 self.substitutions.insert(*v, t.clone());
3010 true
3011 } else {
3012 true
3014 }
3015 }
3016
3017 (Type::Unit, Type::Unit) |
3019 (Type::Bool, Type::Bool) |
3020 (Type::Char, Type::Char) |
3021 (Type::Str, Type::Str) |
3022 (Type::Never, Type::Never) |
3023 (Type::Error, _) |
3024 (_, Type::Error) |
3025 (Type::Never, _) |
3027 (_, Type::Never) => true,
3028
3029 (Type::Int(_), Type::Int(_)) => true,
3032 (Type::Float(_), Type::Float(_)) => true,
3035
3036 (Type::Ref { mutable: false, inner: a, .. }, Type::Str) if matches!(a.as_ref(), Type::Str) => true,
3038 (Type::Str, Type::Ref { mutable: false, inner: b, .. }) if matches!(b.as_ref(), Type::Str) => true,
3039
3040 (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
3042 (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
3043 }
3044
3045 (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
3047
3048 (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
3050 a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
3051 }
3052
3053 (Type::Ref { mutable: ma, inner: a, .. }, Type::Ref { mutable: mb, inner: b, .. }) => {
3055 match (a.as_ref(), b.as_ref()) {
3057 (Type::Array { element: ea, .. }, Type::Slice(es)) => {
3058 ma == mb && self.unify(ea, es)
3059 }
3060 (Type::Slice(es), Type::Array { element: ea, .. }) => {
3061 ma == mb && self.unify(es, ea)
3062 }
3063 _ => ma == mb && self.unify(a, b)
3064 }
3065 }
3066
3067 (Type::Function { params: pa, return_type: ra, is_async: aa },
3069 Type::Function { params: pb, return_type: rb, is_async: ab }) => {
3070 aa == ab && pa.len() == pb.len() &&
3071 pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
3072 self.unify(ra, rb)
3073 }
3074
3075 (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
3077 na == nb && ga.len() == gb.len() &&
3078 ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y))
3079 }
3080
3081 (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
3083 self.unify(a, b)
3084 }
3085 (Type::Evidential { inner: a, .. }, b) => {
3086 self.unify(a, b)
3087 }
3088 (a, Type::Evidential { inner: b, .. }) => {
3089 self.unify(a, b)
3090 }
3091
3092 (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
3094
3095 (Type::Named { name, generics }, _) | (_, Type::Named { name, generics })
3099 if generics.is_empty() && Self::is_type_parameter(name) => {
3100 true
3101 }
3102
3103 _ => false,
3104 }
3105 }
3106
3107 fn is_type_parameter(name: &str) -> bool {
3109 if name.len() == 1 && name.chars().next().map(|c| c.is_ascii_uppercase()).unwrap_or(false) {
3111 return true;
3112 }
3113 matches!(name, "Item" | "Output" | "Error" | "Key" | "Value" | "Idx" | "Self")
3115 }
3116
3117 fn is_numeric_coercion(expected: &Type, actual: &Type) -> bool {
3119 match (expected, actual) {
3121 (Type::Float(_), Type::Int(_)) => true,
3122 (Type::Evidential { inner: exp, .. }, Type::Int(_)) => {
3124 matches!(exp.as_ref(), Type::Float(_))
3125 }
3126 (Type::Float(_), Type::Evidential { inner: act, .. }) => {
3127 matches!(act.as_ref(), Type::Int(_))
3128 }
3129 _ => false,
3130 }
3131 }
3132
3133 fn convert_type(&self, ty: &TypeExpr) -> Type {
3135 match ty {
3136 TypeExpr::Path(path) => {
3137 if path.segments.len() == 1 {
3138 let name = &path.segments[0].ident.name;
3139 match name.as_str() {
3140 "bool" => return Type::Bool,
3141 "char" => return Type::Char,
3142 "str" | "String" => return Type::Str,
3143 "i8" => return Type::Int(IntSize::I8),
3144 "i16" => return Type::Int(IntSize::I16),
3145 "i32" => return Type::Int(IntSize::I32),
3146 "i64" => return Type::Int(IntSize::I64),
3147 "i128" => return Type::Int(IntSize::I128),
3148 "isize" => return Type::Int(IntSize::ISize),
3149 "u8" => return Type::Int(IntSize::U8),
3150 "u16" => return Type::Int(IntSize::U16),
3151 "u32" => return Type::Int(IntSize::U32),
3152 "u64" => return Type::Int(IntSize::U64),
3153 "u128" => return Type::Int(IntSize::U128),
3154 "usize" => return Type::Int(IntSize::USize),
3155 "f32" => return Type::Float(FloatSize::F32),
3156 "f64" => return Type::Float(FloatSize::F64),
3157 "Self" => {
3159 if let Some(ref self_ty) = self.current_self_type {
3160 return Type::Named {
3161 name: self_ty.clone(),
3162 generics: vec![],
3163 };
3164 }
3165 }
3166 _ => {
3167 if let Some(ty) = self.current_generics.get(name) {
3169 return ty.clone();
3170 }
3171 }
3172 }
3173 }
3174
3175 let name = path
3176 .segments
3177 .iter()
3178 .map(|s| s.ident.name.clone())
3179 .collect::<Vec<_>>()
3180 .join("::");
3181
3182 let generics = path
3183 .segments
3184 .last()
3185 .and_then(|s| s.generics.as_ref())
3186 .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
3187 .unwrap_or_default();
3188
3189 Type::Named { name, generics }
3190 }
3191
3192 TypeExpr::Reference { lifetime, mutable, inner } => Type::Ref {
3193 lifetime: lifetime.clone(),
3194 mutable: *mutable,
3195 inner: Box::new(self.convert_type(inner)),
3196 },
3197
3198 TypeExpr::Pointer { mutable, inner } => Type::Ptr {
3199 mutable: *mutable,
3200 inner: Box::new(self.convert_type(inner)),
3201 },
3202
3203 TypeExpr::Array { element, size: _ } => {
3204 Type::Array {
3205 element: Box::new(self.convert_type(element)),
3206 size: None, }
3208 }
3209
3210 TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
3211
3212 TypeExpr::Tuple(elements) => {
3213 Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
3214 }
3215
3216 TypeExpr::Function {
3217 params,
3218 return_type,
3219 } => Type::Function {
3220 params: params.iter().map(|t| self.convert_type(t)).collect(),
3221 return_type: Box::new(
3222 return_type
3223 .as_ref()
3224 .map(|t| self.convert_type(t))
3225 .unwrap_or(Type::Unit),
3226 ),
3227 is_async: false,
3228 },
3229
3230 TypeExpr::Evidential {
3231 inner,
3232 evidentiality,
3233 error_type,
3234 } => {
3235 let _ = error_type; Type::Evidential {
3239 inner: Box::new(self.convert_type(inner)),
3240 evidence: EvidenceLevel::from_ast(*evidentiality),
3241 }
3242 }
3243
3244 TypeExpr::Cycle { modulus: _ } => {
3245 Type::Cycle { modulus: 12 } }
3247
3248 TypeExpr::Simd { element, lanes } => {
3249 let elem_ty = self.convert_type(element);
3250 Type::Simd {
3251 element: Box::new(elem_ty),
3252 lanes: *lanes,
3253 }
3254 }
3255
3256 TypeExpr::Atomic(inner) => {
3257 let inner_ty = self.convert_type(inner);
3258 Type::Atomic(Box::new(inner_ty))
3259 }
3260
3261 TypeExpr::Never => Type::Never,
3262 TypeExpr::Infer => Type::Var(TypeVar(0)), TypeExpr::Lifetime(name) => Type::Lifetime(name.clone()),
3264 TypeExpr::TraitObject(bounds) => {
3265 let converted: Vec<Type> = bounds.iter().map(|b| self.convert_type(b)).collect();
3266 Type::TraitObject(converted)
3267 }
3268 TypeExpr::Hrtb { lifetimes, bound } => Type::Hrtb {
3269 lifetimes: lifetimes.clone(),
3270 bound: Box::new(self.convert_type(bound)),
3271 },
3272 TypeExpr::InlineStruct { fields } => Type::InlineStruct {
3273 fields: fields
3274 .iter()
3275 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
3276 .collect(),
3277 },
3278 TypeExpr::ImplTrait(bounds) => {
3279 Type::ImplTrait(bounds.iter().map(|b| self.convert_type(b)).collect())
3280 }
3281 TypeExpr::InlineEnum { variants } => {
3282 Type::InlineEnum(variants.iter().map(|v| v.name.name.clone()).collect())
3283 }
3284 TypeExpr::AssocTypeBinding { name, ty } => Type::AssocTypeBinding {
3285 name: name.name.clone(),
3286 ty: Box::new(self.convert_type(ty)),
3287 },
3288 TypeExpr::ConstExpr(_) => {
3289 Type::Var(TypeVar(0))
3292 }
3293 TypeExpr::QualifiedPath { self_type, trait_path, item_path } => {
3294 let trait_part = trait_path.as_ref()
3297 .map(|tp| tp.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::"))
3298 .unwrap_or_default();
3299 let item_part = item_path.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::");
3300 let name = if trait_part.is_empty() {
3301 format!("<_>::{}", item_part)
3302 } else {
3303 format!("<_ as {}>::{}", trait_part, item_part)
3304 };
3305 Type::Named {
3306 name,
3307 generics: vec![self.convert_type(self_type)],
3308 }
3309 }
3310 }
3311 }
3312
3313 pub fn errors(&self) -> &[TypeError] {
3315 &self.errors
3316 }
3317}
3318
3319impl Default for TypeChecker {
3320 fn default() -> Self {
3321 Self::new()
3322 }
3323}
3324
3325trait PatternExt {
3327 fn evidentiality(&self) -> Option<Evidentiality>;
3328 fn binding_name(&self) -> Option<String>;
3329 fn binding_span(&self) -> Option<Span>;
3330 fn is_mutable(&self) -> bool;
3331}
3332
3333impl PatternExt for Pattern {
3334 fn evidentiality(&self) -> Option<Evidentiality> {
3335 match self {
3336 Pattern::Ident { evidentiality, .. } => *evidentiality,
3337 _ => None,
3338 }
3339 }
3340
3341 fn binding_name(&self) -> Option<String> {
3342 match self {
3343 Pattern::Ident { name, .. } => Some(name.name.clone()),
3344 _ => None,
3345 }
3346 }
3347
3348 fn binding_span(&self) -> Option<Span> {
3349 match self {
3350 Pattern::Ident { name, .. } => Some(name.span),
3351 _ => None,
3352 }
3353 }
3354
3355 fn is_mutable(&self) -> bool {
3356 match self {
3357 Pattern::Ident { mutable, .. } => *mutable,
3358 _ => false,
3359 }
3360 }
3361}
3362
3363impl fmt::Display for Type {
3364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3365 match self {
3366 Type::Unit => write!(f, "()"),
3367 Type::Bool => write!(f, "bool"),
3368 Type::Int(size) => write!(f, "{:?}", size),
3369 Type::Float(size) => write!(f, "{:?}", size),
3370 Type::Char => write!(f, "char"),
3371 Type::Str => write!(f, "str"),
3372 Type::Array { element, size } => {
3373 if let Some(n) = size {
3374 write!(f, "[{}; {}]", element, n)
3375 } else {
3376 write!(f, "[{}]", element)
3377 }
3378 }
3379 Type::Slice(inner) => write!(f, "[{}]", inner),
3380 Type::Tuple(elems) => {
3381 write!(f, "(")?;
3382 for (i, e) in elems.iter().enumerate() {
3383 if i > 0 {
3384 write!(f, ", ")?;
3385 }
3386 write!(f, "{}", e)?;
3387 }
3388 write!(f, ")")
3389 }
3390 Type::Named { name, generics } => {
3391 write!(f, "{}", name)?;
3392 if !generics.is_empty() {
3393 write!(f, "<")?;
3394 for (i, g) in generics.iter().enumerate() {
3395 if i > 0 {
3396 write!(f, ", ")?;
3397 }
3398 write!(f, "{}", g)?;
3399 }
3400 write!(f, ">")?;
3401 }
3402 Ok(())
3403 }
3404 Type::Function {
3405 params,
3406 return_type,
3407 is_async,
3408 } => {
3409 if *is_async {
3410 write!(f, "async ")?;
3411 }
3412 write!(f, "fn(")?;
3413 for (i, p) in params.iter().enumerate() {
3414 if i > 0 {
3415 write!(f, ", ")?;
3416 }
3417 write!(f, "{}", p)?;
3418 }
3419 write!(f, ") -> {}", return_type)
3420 }
3421 Type::Ref { lifetime, mutable, inner } => {
3422 let lt = lifetime.as_ref().map(|l| format!("'{} ", l)).unwrap_or_default();
3423 write!(f, "&{}{}{}", lt, if *mutable { "mut " } else { "" }, inner)
3424 }
3425 Type::Ptr { mutable, inner } => {
3426 write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
3427 }
3428 Type::Evidential { inner, evidence } => {
3429 write!(f, "{}{}", inner, evidence.symbol())
3430 }
3431 Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
3432 Type::Var(v) => write!(f, "?{}", v.0),
3433 Type::Error => write!(f, "<error>"),
3434 Type::Never => write!(f, "!"),
3435 Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
3436 Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
3437 Type::Lifetime(name) => write!(f, "'{}", name),
3438 Type::TraitObject(bounds) => {
3439 write!(f, "dyn ")?;
3440 for (i, bound) in bounds.iter().enumerate() {
3441 if i > 0 {
3442 write!(f, " + ")?;
3443 }
3444 write!(f, "{}", bound)?;
3445 }
3446 Ok(())
3447 }
3448 Type::Hrtb { lifetimes, bound } => {
3449 write!(f, "for<")?;
3450 for (i, lt) in lifetimes.iter().enumerate() {
3451 if i > 0 {
3452 write!(f, ", ")?;
3453 }
3454 write!(f, "'{}", lt)?;
3455 }
3456 write!(f, "> {}", bound)
3457 }
3458 Type::InlineStruct { fields } => {
3459 write!(f, "struct {{ ")?;
3460 for (i, (name, ty)) in fields.iter().enumerate() {
3461 if i > 0 {
3462 write!(f, ", ")?;
3463 }
3464 write!(f, "{}: {}", name, ty)?;
3465 }
3466 write!(f, " }}")
3467 }
3468 Type::ImplTrait(bounds) => {
3469 write!(f, "impl ")?;
3470 for (i, bound) in bounds.iter().enumerate() {
3471 if i > 0 {
3472 write!(f, " + ")?;
3473 }
3474 write!(f, "{}", bound)?;
3475 }
3476 Ok(())
3477 }
3478 Type::InlineEnum(variants) => {
3479 write!(f, "enum {{ ")?;
3480 for (i, name) in variants.iter().enumerate() {
3481 if i > 0 {
3482 write!(f, ", ")?;
3483 }
3484 write!(f, "{}", name)?;
3485 }
3486 write!(f, " }}")
3487 }
3488 Type::AssocTypeBinding { name, ty } => {
3489 write!(f, "{} = {}", name, ty)
3490 }
3491 }
3492 }
3493}
3494
3495#[cfg(test)]
3496mod tests {
3497 use super::*;
3498 use crate::Parser;
3499
3500 fn check(source: &str) -> Result<(), Vec<TypeError>> {
3501 let mut parser = Parser::new(source);
3502 let file = parser.parse_file().expect("parse failed");
3503 let mut checker = TypeChecker::new();
3504 checker.check_file(&file)
3505 }
3506
3507 #[test]
3508 fn test_basic_types() {
3509 assert!(check("fn main() { let x: i64 = 42; }").is_ok());
3510 assert!(check("fn main() { let x: bool = true; }").is_ok());
3511 assert!(check("fn main() { let x: f64 = 3.14; }").is_ok());
3512 }
3513
3514 #[test]
3515 fn test_type_mismatch() {
3516 assert!(check("fn main() { let x: bool = 42; }").is_err());
3517 }
3518
3519 #[test]
3520 fn test_evidence_propagation() {
3521 assert!(check(
3523 r#"
3524 fn main() {
3525 let known: i64! = 42;
3526 let uncertain: i64? = 10;
3527 let result = known + uncertain;
3528 }
3529 "#
3530 )
3531 .is_ok());
3532 }
3533
3534 #[test]
3535 fn test_function_return() {
3536 let result = check(
3537 r#"
3538 fn add(a: i64, b: i64) -> i64 {
3539 return a + b;
3540 }
3541 fn main() {
3542 let x = add(1, 2);
3543 }
3544 "#,
3545 );
3546 if let Err(errors) = &result {
3547 for e in errors {
3548 eprintln!("Error: {}", e);
3549 }
3550 }
3551 assert!(result.is_ok());
3552 }
3553
3554 #[test]
3555 fn test_array_types() {
3556 assert!(check(
3557 r#"
3558 fn main() {
3559 let arr = [1, 2, 3];
3560 let x = arr[0];
3561 }
3562 "#
3563 )
3564 .is_ok());
3565 }
3566
3567 #[test]
3572 fn test_evidence_inference_from_initializer() {
3573 assert!(check(
3575 r#"
3576 fn main() {
3577 let reported_val: i64~ = 42;
3578 // x should inherit ~ evidence from reported_val
3579 let x = reported_val + 1;
3580 }
3581 "#
3582 )
3583 .is_ok());
3584 }
3585
3586 #[test]
3587 fn test_evidence_inference_explicit_override() {
3588 assert!(check(
3590 r#"
3591 fn main() {
3592 let reported_val: i64~ = 42;
3593 // Explicit ! annotation - this would fail if we checked evidence properly
3594 // but the type system allows it as an override
3595 let x! = 42;
3596 }
3597 "#
3598 )
3599 .is_ok());
3600 }
3601
3602 #[test]
3603 fn test_if_else_evidence_join() {
3604 assert!(check(
3606 r#"
3607 fn main() {
3608 let known_val: i64! = 1;
3609 let reported_val: i64~ = 2;
3610 let cond: bool = true;
3611 // Result should have ~ evidence (join of ! and ~)
3612 let result = if cond { known_val } else { reported_val };
3613 }
3614 "#
3615 )
3616 .is_ok());
3617 }
3618
3619 #[test]
3620 fn test_binary_op_evidence_propagation() {
3621 assert!(check(
3623 r#"
3624 fn main() {
3625 let known: i64! = 1;
3626 let reported: i64~ = 2;
3627 // Result should have ~ evidence (max of ! and ~)
3628 let result = known + reported;
3629 }
3630 "#
3631 )
3632 .is_ok());
3633 }
3634
3635 #[test]
3636 fn test_match_evidence_join() {
3637 assert!(check(
3640 r#"
3641 fn main() {
3642 let x: i64 = 1;
3643 }
3644 "#
3645 )
3646 .is_ok());
3647 }
3648}