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}
339
340impl TypeChecker {
341 pub fn new() -> Self {
342 let mut checker = Self {
343 env: Rc::new(RefCell::new(TypeEnv::new())),
344 types: HashMap::new(),
345 functions: HashMap::new(),
346 impl_methods: HashMap::new(),
347 current_self_type: None,
348 current_generics: HashMap::new(),
349 expected_return_type: None,
350 next_var: 0,
351 substitutions: HashMap::new(),
352 errors: Vec::new(),
353 };
354
355 checker.register_builtins();
357 checker
358 }
359
360 fn register_builtins(&mut self) {
361 let func = |params: Vec<Type>, ret: Type| Type::Function {
363 params,
364 return_type: Box::new(ret),
365 is_async: false,
366 };
367
368 let any = Type::Var(TypeVar(9999)); self.functions
376 .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
377 self.functions
378 .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
379 self.functions
380 .insert("input".to_string(), func(vec![], Type::Str));
381 self.functions
382 .insert("input_line".to_string(), func(vec![], Type::Str));
383
384 self.functions
388 .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
389 self.functions.insert(
390 "len".to_string(),
391 func(vec![any.clone()], Type::Int(IntSize::USize)),
392 );
393
394 self.functions
398 .insert("str".to_string(), func(vec![any.clone()], Type::Str));
399 self.functions
400 .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
401 self.functions
402 .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
403 self.functions
404 .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
405 self.functions.insert(
406 "split".to_string(),
407 func(
408 vec![Type::Str, Type::Str],
409 Type::Array {
410 element: Box::new(Type::Str),
411 size: None,
412 },
413 ),
414 );
415 self.functions.insert(
416 "join".to_string(),
417 func(
418 vec![
419 Type::Array {
420 element: Box::new(Type::Str),
421 size: None,
422 },
423 Type::Str,
424 ],
425 Type::Str,
426 ),
427 );
428 self.functions.insert(
429 "contains".to_string(),
430 func(vec![Type::Str, Type::Str], Type::Bool),
431 );
432 self.functions.insert(
433 "starts_with".to_string(),
434 func(vec![Type::Str, Type::Str], Type::Bool),
435 );
436 self.functions.insert(
437 "ends_with".to_string(),
438 func(vec![Type::Str, Type::Str], Type::Bool),
439 );
440 self.functions.insert(
441 "replace".to_string(),
442 func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
443 );
444 self.functions.insert(
445 "char_at".to_string(),
446 func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
447 );
448 self.functions.insert(
449 "substring".to_string(),
450 func(
451 vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
452 Type::Str,
453 ),
454 );
455
456 let f64_ty = Type::Float(FloatSize::F64);
460 let i64_ty = Type::Int(IntSize::I64);
461
462 self.functions.insert(
463 "abs".to_string(),
464 func(vec![f64_ty.clone()], f64_ty.clone()),
465 );
466 self.functions.insert(
467 "sqrt".to_string(),
468 func(vec![f64_ty.clone()], f64_ty.clone()),
469 );
470 self.functions.insert(
471 "sin".to_string(),
472 func(vec![f64_ty.clone()], f64_ty.clone()),
473 );
474 self.functions.insert(
475 "cos".to_string(),
476 func(vec![f64_ty.clone()], f64_ty.clone()),
477 );
478 self.functions.insert(
479 "tan".to_string(),
480 func(vec![f64_ty.clone()], f64_ty.clone()),
481 );
482 self.functions.insert(
483 "floor".to_string(),
484 func(vec![f64_ty.clone()], f64_ty.clone()),
485 );
486 self.functions.insert(
487 "ceil".to_string(),
488 func(vec![f64_ty.clone()], f64_ty.clone()),
489 );
490 self.functions.insert(
491 "round".to_string(),
492 func(vec![f64_ty.clone()], f64_ty.clone()),
493 );
494 self.functions.insert(
495 "pow".to_string(),
496 func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
497 );
498 self.functions.insert(
499 "log".to_string(),
500 func(vec![f64_ty.clone()], f64_ty.clone()),
501 );
502 self.functions.insert(
503 "exp".to_string(),
504 func(vec![f64_ty.clone()], f64_ty.clone()),
505 );
506 self.functions.insert(
507 "min".to_string(),
508 func(vec![any.clone(), any.clone()], any.clone()),
509 );
510 self.functions.insert(
511 "max".to_string(),
512 func(vec![any.clone(), any.clone()], any.clone()),
513 );
514
515 self.functions
519 .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
520 self.functions
521 .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
522 self.functions.insert(
523 "push".to_string(),
524 func(vec![any.clone(), any.clone()], Type::Unit),
525 );
526 self.functions
527 .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
528 self.functions
529 .insert("first".to_string(), func(vec![any.clone()], any.clone()));
530 self.functions
531 .insert("last".to_string(), func(vec![any.clone()], any.clone()));
532 self.functions
533 .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
534 self.functions
535 .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
536 self.functions.insert(
537 "range".to_string(),
538 func(
539 vec![i64_ty.clone(), i64_ty.clone()],
540 Type::Array {
541 element: Box::new(i64_ty.clone()),
542 size: None,
543 },
544 ),
545 );
546
547 self.functions
551 .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
552 self.functions.insert(
553 "assert_eq".to_string(),
554 func(vec![any.clone(), any.clone()], Type::Unit),
555 );
556 self.functions.insert(
557 "assert_ne".to_string(),
558 func(vec![any.clone(), any.clone()], Type::Unit),
559 );
560 self.functions.insert(
561 "assert_lt".to_string(),
562 func(vec![any.clone(), any.clone()], Type::Unit),
563 );
564 self.functions.insert(
565 "assert_le".to_string(),
566 func(vec![any.clone(), any.clone()], Type::Unit),
567 );
568 self.functions.insert(
569 "assert_gt".to_string(),
570 func(vec![any.clone(), any.clone()], Type::Unit),
571 );
572 self.functions.insert(
573 "assert_ge".to_string(),
574 func(vec![any.clone(), any.clone()], Type::Unit),
575 );
576 self.functions.insert(
577 "assert_true".to_string(),
578 func(vec![Type::Bool], Type::Unit),
579 );
580 self.functions.insert(
581 "assert_false".to_string(),
582 func(vec![Type::Bool], Type::Unit),
583 );
584 self.functions.insert(
585 "assert_null".to_string(),
586 func(vec![any.clone()], Type::Unit),
587 );
588 self.functions.insert(
589 "assert_not_null".to_string(),
590 func(vec![any.clone()], Type::Unit),
591 );
592 self.functions.insert(
593 "assert_contains".to_string(),
594 func(vec![any.clone(), any.clone()], Type::Unit),
595 );
596 self.functions.insert(
597 "assert_len".to_string(),
598 func(vec![any.clone(), i64_ty.clone()], Type::Unit),
599 );
600
601 self.functions
605 .insert("random".to_string(), func(vec![], f64_ty.clone()));
606 self.functions.insert(
607 "random_int".to_string(),
608 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
609 );
610 self.functions
611 .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
612
613 self.functions
617 .insert("now".to_string(), func(vec![], f64_ty.clone()));
618 self.functions
619 .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
620
621 self.functions
625 .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
626 self.functions
627 .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
628 self.functions
629 .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
630
631 self.functions
635 .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
636 self.functions
637 .insert("todo".to_string(), func(vec![], Type::Never));
638 self.functions
639 .insert("unreachable".to_string(), func(vec![], Type::Never));
640
641 self.functions.insert(
646 "known".to_string(),
647 func(
648 vec![any.clone()],
649 Type::Evidential {
650 inner: Box::new(any.clone()),
651 evidence: EvidenceLevel::Known,
652 },
653 ),
654 );
655 self.functions.insert(
657 "uncertain".to_string(),
658 func(
659 vec![any.clone()],
660 Type::Evidential {
661 inner: Box::new(any.clone()),
662 evidence: EvidenceLevel::Uncertain,
663 },
664 ),
665 );
666 self.functions.insert(
668 "reported".to_string(),
669 func(
670 vec![any.clone()],
671 Type::Evidential {
672 inner: Box::new(any.clone()),
673 evidence: EvidenceLevel::Reported,
674 },
675 ),
676 );
677 self.functions.insert(
679 "evidence_of".to_string(),
680 func(vec![any.clone()], Type::Str),
681 );
682 self.functions.insert(
684 "validate".to_string(),
685 func(
686 vec![any.clone()],
687 Type::Evidential {
688 inner: Box::new(any.clone()),
689 evidence: EvidenceLevel::Uncertain,
690 },
691 ),
692 );
693 self.functions.insert(
695 "verify".to_string(),
696 func(
697 vec![any.clone()],
698 Type::Evidential {
699 inner: Box::new(any.clone()),
700 evidence: EvidenceLevel::Known,
701 },
702 ),
703 );
704
705 self.functions.insert(
710 "freq".to_string(),
711 func(vec![i64_ty.clone()], f64_ty.clone()),
712 );
713 self.functions.insert(
715 "octave".to_string(),
716 func(vec![i64_ty.clone()], i64_ty.clone()),
717 );
718 self.functions.insert(
720 "pitch_class".to_string(),
721 func(vec![i64_ty.clone()], i64_ty.clone()),
722 );
723 self.functions.insert(
725 "mod_cycle".to_string(),
726 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
727 );
728 }
729
730 fn fresh_var(&mut self) -> Type {
732 let var = TypeVar(self.next_var);
733 self.next_var += 1;
734 Type::Var(var)
735 }
736
737 fn type_contains_var(&self, ty: &Type) -> bool {
739 match ty {
740 Type::Var(v) => !self.substitutions.contains_key(v),
741 Type::Array { element, .. } => self.type_contains_var(element.as_ref()),
742 Type::Slice(inner) => self.type_contains_var(inner.as_ref()),
743 Type::Tuple(elems) => elems.iter().any(|e| self.type_contains_var(e)),
744 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.type_contains_var(inner.as_ref()),
745 Type::Function { params, return_type, .. } => {
746 params.iter().any(|p| self.type_contains_var(p)) || self.type_contains_var(return_type.as_ref())
747 }
748 Type::Named { generics, .. } => generics.iter().any(|g| self.type_contains_var(g)),
749 Type::Evidential { inner, .. } => self.type_contains_var(inner.as_ref()),
750 Type::Atomic(inner) => self.type_contains_var(inner.as_ref()),
751 Type::Simd { element, .. } => self.type_contains_var(element.as_ref()),
752 _ => false,
753 }
754 }
755
756 fn occurs_in(&self, v: &TypeVar, t: &Type) -> bool {
759 match t {
760 Type::Var(w) => {
761 if v == w {
762 return true;
763 }
764 if let Some(resolved) = self.substitutions.get(w) {
765 self.occurs_in(v, resolved)
766 } else {
767 false
768 }
769 }
770 Type::Array { element, .. } => self.occurs_in(v, element),
771 Type::Slice(inner) => self.occurs_in(v, inner),
772 Type::Tuple(elems) => elems.iter().any(|e| self.occurs_in(v, e)),
773 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.occurs_in(v, inner),
774 Type::Function { params, return_type, .. } => {
775 params.iter().any(|p| self.occurs_in(v, p)) || self.occurs_in(v, return_type)
776 }
777 Type::Named { generics, .. } => generics.iter().any(|g| self.occurs_in(v, g)),
778 Type::Evidential { inner, .. } => self.occurs_in(v, inner),
779 Type::Atomic(inner) => self.occurs_in(v, inner),
780 Type::Simd { element, .. } => self.occurs_in(v, element),
781 _ => false,
782 }
783 }
784
785 fn freshen(&mut self, ty: &Type) -> Type {
788 let mut mapping = std::collections::HashMap::new();
789 self.freshen_inner(ty, &mut mapping)
790 }
791
792 fn freshen_inner(
793 &mut self,
794 ty: &Type,
795 mapping: &mut std::collections::HashMap<u32, Type>,
796 ) -> Type {
797 match ty {
798 Type::Var(TypeVar(id)) => {
799 if let Some(fresh) = mapping.get(id) {
800 fresh.clone()
801 } else {
802 let fresh = self.fresh_var();
803 mapping.insert(*id, fresh.clone());
804 fresh
805 }
806 }
807 Type::Array { element, size } => Type::Array {
808 element: Box::new(self.freshen_inner(element, mapping)),
809 size: *size,
810 },
811 Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
812 Type::Ref { lifetime, mutable, inner } => Type::Ref {
813 lifetime: lifetime.clone(),
814 mutable: *mutable,
815 inner: Box::new(self.freshen_inner(inner, mapping)),
816 },
817 Type::Tuple(elems) => Type::Tuple(
818 elems
819 .iter()
820 .map(|e| self.freshen_inner(e, mapping))
821 .collect(),
822 ),
823 Type::Function {
824 params,
825 return_type,
826 is_async,
827 } => Type::Function {
828 params: params
829 .iter()
830 .map(|p| self.freshen_inner(p, mapping))
831 .collect(),
832 return_type: Box::new(self.freshen_inner(return_type, mapping)),
833 is_async: *is_async,
834 },
835 Type::Evidential { inner, evidence } => Type::Evidential {
836 inner: Box::new(self.freshen_inner(inner, mapping)),
837 evidence: *evidence,
838 },
839 Type::Named { name, generics } => Type::Named {
840 name: name.clone(),
841 generics: generics
842 .iter()
843 .map(|g| self.freshen_inner(g, mapping))
844 .collect(),
845 },
846 _ => ty.clone(),
848 }
849 }
850
851 fn push_scope(&mut self) {
853 let new_env = TypeEnv::with_parent(self.env.clone());
854 self.env = Rc::new(RefCell::new(new_env));
855 }
856
857 fn pop_scope(&mut self) {
859 let parent = self.env.borrow().parent.clone();
860 if let Some(p) = parent {
861 self.env = p;
862 }
863 }
864
865 fn error(&mut self, err: TypeError) {
867 self.errors.push(err);
868 }
869
870 fn check_evidence(
873 &mut self,
874 expected: EvidenceLevel,
875 actual: EvidenceLevel,
876 context: &str,
877 ) -> bool {
878 if actual.satisfies(expected) {
879 true
880 } else {
881 let mut err = TypeError::new(format!(
882 "evidence mismatch {}: expected {} ({}), found {} ({})",
883 context,
884 expected.name(),
885 expected.symbol(),
886 actual.name(),
887 actual.symbol(),
888 ));
889
890 match (expected, actual) {
892 (EvidenceLevel::Known, EvidenceLevel::Reported) => {
893 err = err.with_note(
894 "reported data (~) cannot be used where known data (!) is required",
895 );
896 err = err.with_note(
897 "help: use |validate!{...} to verify and promote evidence level",
898 );
899 }
900 (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
901 err = err.with_note(
902 "uncertain data (?) cannot be used where known data (!) is required",
903 );
904 err = err.with_note(
905 "help: use pattern matching or unwrap to handle the uncertainty",
906 );
907 }
908 (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
909 err = err.with_note(
910 "reported data (~) cannot be used where uncertain data (?) is required",
911 );
912 err = err.with_note("help: use |validate?{...} to verify external data");
913 }
914 _ => {
915 err = err.with_note(format!(
916 "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
917 ));
918 }
919 }
920
921 self.error(err);
922 false
923 }
924 }
925
926 fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
928 match ty {
929 Type::Evidential { evidence, .. } => *evidence,
930 _ => EvidenceLevel::Known,
931 }
932 }
933
934 pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
936 for item in &file.items {
938 self.collect_type_def(&item.node);
939 }
940
941 for item in &file.items {
943 self.collect_fn_sig(&item.node);
944 }
945
946 for item in &file.items {
948 self.check_item(&item.node);
949 }
950
951 if self.errors.is_empty() {
952 Ok(())
953 } else {
954 Err(std::mem::take(&mut self.errors))
955 }
956 }
957
958 fn collect_type_def(&mut self, item: &Item) {
960 match item {
961 Item::Struct(s) => {
962 let generics = s
963 .generics
964 .as_ref()
965 .map(|g| {
966 g.params
967 .iter()
968 .filter_map(|p| {
969 if let GenericParam::Type { name, .. } = p {
970 Some(name.name.clone())
971 } else {
972 None
973 }
974 })
975 .collect()
976 })
977 .unwrap_or_default();
978
979 let fields = match &s.fields {
980 StructFields::Named(fs) => fs
981 .iter()
982 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
983 .collect(),
984 StructFields::Tuple(ts) => ts
985 .iter()
986 .enumerate()
987 .map(|(i, t)| (i.to_string(), self.convert_type(t)))
988 .collect(),
989 StructFields::Unit => vec![],
990 };
991
992 if self.types.contains_key(&s.name.name) {
994 self.error(TypeError::new(format!(
995 "duplicate type definition: '{}'",
996 s.name.name
997 )));
998 }
999 self.types
1000 .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
1001 }
1002 Item::Enum(e) => {
1003 let generics = e
1004 .generics
1005 .as_ref()
1006 .map(|g| {
1007 g.params
1008 .iter()
1009 .filter_map(|p| {
1010 if let GenericParam::Type { name, .. } = p {
1011 Some(name.name.clone())
1012 } else {
1013 None
1014 }
1015 })
1016 .collect()
1017 })
1018 .unwrap_or_default();
1019
1020 let variants = e
1021 .variants
1022 .iter()
1023 .map(|v| {
1024 let fields = match &v.fields {
1025 StructFields::Tuple(ts) => {
1026 Some(ts.iter().map(|t| self.convert_type(t)).collect())
1027 }
1028 StructFields::Named(fs) => {
1029 Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
1030 }
1031 StructFields::Unit => None,
1032 };
1033 (v.name.name.clone(), fields)
1034 })
1035 .collect();
1036
1037 self.types
1038 .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
1039 }
1040 Item::TypeAlias(t) => {
1041 let generics = t
1042 .generics
1043 .as_ref()
1044 .map(|g| {
1045 g.params
1046 .iter()
1047 .filter_map(|p| {
1048 if let GenericParam::Type { name, .. } = p {
1049 Some(name.name.clone())
1050 } else {
1051 None
1052 }
1053 })
1054 .collect()
1055 })
1056 .unwrap_or_default();
1057
1058 let target = self.convert_type(&t.ty);
1059 self.types
1060 .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
1061 }
1062 _ => {}
1063 }
1064 }
1065
1066 fn collect_fn_sig(&mut self, item: &Item) {
1068 match item {
1069 Item::Function(f) => {
1070 let params: Vec<Type> = f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1071
1072 let return_type = f
1073 .return_type
1074 .as_ref()
1075 .map(|t| self.convert_type(t))
1076 .unwrap_or(Type::Unit);
1077
1078 let fn_type = Type::Function {
1079 params,
1080 return_type: Box::new(return_type),
1081 is_async: f.is_async,
1082 };
1083
1084 if self.functions.contains_key(&f.name.name) {
1086 self.error(TypeError::new(format!(
1087 "duplicate function definition: '{}'",
1088 f.name.name
1089 )));
1090 }
1091 self.functions.insert(f.name.name.clone(), fn_type);
1092 }
1093 Item::Impl(impl_block) => {
1094 let type_name = self.type_path_to_name(&impl_block.self_ty);
1096
1097 self.current_self_type = Some(type_name.clone());
1099
1100 if let Some(ref generics) = impl_block.generics {
1102 for param in &generics.params {
1103 if let crate::ast::GenericParam::Type { name, .. } = param {
1104 let type_var = self.fresh_var();
1105 self.current_generics.insert(name.name.clone(), type_var);
1106 }
1107 }
1108 }
1109
1110 for impl_item in &impl_block.items {
1112 if let crate::ast::ImplItem::Function(f) = impl_item {
1113 let params: Vec<Type> =
1114 f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1115
1116 let return_type = f
1117 .return_type
1118 .as_ref()
1119 .map(|t| self.convert_type(t))
1120 .unwrap_or(Type::Unit);
1121
1122 let fn_type = Type::Function {
1123 params,
1124 return_type: Box::new(return_type),
1125 is_async: f.is_async,
1126 };
1127
1128 self.impl_methods
1130 .entry(type_name.clone())
1131 .or_insert_with(HashMap::new)
1132 .insert(f.name.name.clone(), fn_type);
1133 }
1134 }
1135
1136 self.current_self_type = None;
1138 self.current_generics.clear();
1139 }
1140 _ => {}
1141 }
1142 }
1143
1144 fn type_path_to_name(&self, ty: &crate::ast::TypeExpr) -> String {
1146 match ty {
1147 crate::ast::TypeExpr::Path(path) => {
1148 path.segments
1149 .iter()
1150 .map(|s| s.ident.name.clone())
1151 .collect::<Vec<_>>()
1152 .join("::")
1153 }
1154 _ => "Unknown".to_string(),
1155 }
1156 }
1157
1158 fn check_item(&mut self, item: &Item) {
1160 match item {
1161 Item::Function(f) => self.check_function(f),
1162 Item::Const(c) => {
1163 let declared = self.convert_type(&c.ty);
1164 let inferred = self.infer_expr(&c.value);
1165 if !self.unify(&declared, &inferred) {
1166 self.error(
1167 TypeError::new(format!(
1168 "type mismatch in const '{}': expected {:?}, found {:?}",
1169 c.name.name, declared, inferred
1170 ))
1171 .with_span(c.name.span),
1172 );
1173 }
1174 }
1175 Item::Static(s) => {
1176 let declared = self.convert_type(&s.ty);
1177 let inferred = self.infer_expr(&s.value);
1178 if !self.unify(&declared, &inferred) {
1179 self.error(
1180 TypeError::new(format!(
1181 "type mismatch in static '{}': expected {:?}, found {:?}",
1182 s.name.name, declared, inferred
1183 ))
1184 .with_span(s.name.span),
1185 );
1186 }
1187 }
1188 Item::Impl(impl_block) => {
1189 let type_name = self.type_path_to_name(&impl_block.self_ty);
1191 self.current_self_type = Some(type_name);
1192
1193 if let Some(ref generics) = impl_block.generics {
1195 for param in &generics.params {
1196 if let crate::ast::GenericParam::Type { name, .. } = param {
1197 let type_var = self.fresh_var();
1198 self.current_generics.insert(name.name.clone(), type_var);
1199 }
1200 }
1201 }
1202
1203 for impl_item in &impl_block.items {
1205 if let crate::ast::ImplItem::Function(f) = impl_item {
1206 self.check_function(f);
1207 }
1208 }
1209
1210 self.current_self_type = None;
1212 self.current_generics.clear();
1213 }
1214 _ => {}
1215 }
1216 }
1217
1218 fn check_function(&mut self, func: &Function) {
1220 self.push_scope();
1221
1222 for param in &func.params {
1224 let ty = self.convert_type(¶m.ty);
1225 let type_evidence = self.get_evidence(&ty);
1228 let evidence = param
1229 .pattern
1230 .evidentiality()
1231 .map(EvidenceLevel::from_ast)
1232 .unwrap_or(type_evidence);
1233
1234 if let Some(name) = param.pattern.binding_name() {
1235 self.env.borrow_mut().define(name, ty, evidence);
1236 }
1237 }
1238
1239 let expected_return = func
1241 .return_type
1242 .as_ref()
1243 .map(|t| self.convert_type(t))
1244 .unwrap_or(Type::Unit);
1245 let old_return_type = self.expected_return_type.clone();
1246 self.expected_return_type = Some(expected_return.clone());
1247
1248 if let Some(ref body) = func.body {
1250 let body_type = self.check_block(body);
1251
1252 self.expected_return_type = old_return_type;
1254
1255 let expected_return = func
1257 .return_type
1258 .as_ref()
1259 .map(|t| self.convert_type(t))
1260 .unwrap_or(Type::Unit);
1261
1262 let _ = self.unify(&expected_return, &body_type);
1266
1267 let type_has_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1273 let name_evidence = func.name.evidentiality.as_ref()
1275 .map(|e| EvidenceLevel::from_ast(*e));
1276 let has_explicit_evidence = type_has_evidence || name_evidence.is_some();
1277 let actual_evidence = self.get_evidence(&body_type);
1278
1279 if has_explicit_evidence {
1280 if name_evidence.is_none() {
1284 let expected_evidence = self.get_evidence(&expected_return);
1285 self.check_evidence(
1286 expected_evidence,
1287 actual_evidence,
1288 &format!("in return type of '{}'", func.name.name),
1289 );
1290 }
1291 } else {
1293 if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1296 self.error(
1297 TypeError::new(format!(
1298 "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1299 func.name.name,
1300 actual_evidence.name(),
1301 actual_evidence.symbol(),
1302 ))
1303 .with_span(func.name.span)
1304 .with_note("help: add explicit evidence annotation to the return type")
1305 .with_note(format!(
1306 "example: fn {}(...) -> {}{} {{ ... }}",
1307 func.name.name,
1308 expected_return,
1309 actual_evidence.symbol()
1310 )),
1311 );
1312 }
1313 }
1315 }
1316
1317 self.pop_scope();
1318 }
1319
1320 fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1322 match ty {
1323 Some(TypeExpr::Evidential { .. }) => true,
1324 Some(TypeExpr::Reference { inner, .. })
1325 | Some(TypeExpr::Pointer { inner, .. })
1326 | Some(TypeExpr::Slice(inner))
1327 | Some(TypeExpr::Array { element: inner, .. }) => {
1328 self.type_has_explicit_evidence(Some(inner.as_ref()))
1329 }
1330 Some(TypeExpr::Tuple(elements)) => elements
1331 .iter()
1332 .any(|e| self.type_has_explicit_evidence(Some(e))),
1333 _ => false,
1334 }
1335 }
1336
1337 fn check_block(&mut self, block: &Block) -> Type {
1339 self.push_scope();
1340
1341 let mut diverges = false;
1342 for stmt in &block.stmts {
1343 let stmt_ty = self.check_stmt(stmt);
1344 if matches!(stmt_ty, Type::Never) {
1345 diverges = true;
1346 }
1347 }
1348
1349 let result = if let Some(ref expr) = block.expr {
1350 self.infer_expr(expr)
1351 } else if diverges {
1352 Type::Never
1353 } else {
1354 Type::Unit
1355 };
1356
1357 self.pop_scope();
1358 result
1359 }
1360
1361 fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1363 match stmt {
1364 Stmt::Let { pattern, ty, init } => {
1365 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1366 let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1367
1368 let final_ty = match (&declared_ty, &init_ty) {
1369 (Some(d), Some(i)) => {
1370 if !self.unify(d, i) {
1371 let binding_name = pattern.binding_name().unwrap_or_else(|| "<pattern>".to_string());
1373 let mut err = TypeError::new(format!(
1374 "type mismatch in let binding '{}': expected {:?}, found {:?}",
1375 binding_name, d, i
1376 ));
1377 if let Some(span) = pattern.binding_span() {
1378 err = err.with_span(span);
1379 }
1380 self.error(err);
1381 }
1382 d.clone()
1383 }
1384 (Some(d), None) => d.clone(),
1385 (None, Some(i)) => i.clone(),
1386 (None, None) => self.fresh_var(),
1387 };
1388
1389 let evidence = pattern
1395 .evidentiality()
1396 .map(EvidenceLevel::from_ast)
1397 .unwrap_or_else(|| {
1398 init_ty
1400 .as_ref()
1401 .map(|ty| self.get_evidence(ty))
1402 .unwrap_or(EvidenceLevel::Known)
1403 });
1404
1405 if let Some(name) = pattern.binding_name() {
1406 self.env.borrow_mut().define(name, final_ty, evidence);
1407 }
1408 Type::Unit
1409 }
1410 Stmt::LetElse { pattern, ty, init, else_branch } => {
1411 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1413 let init_ty = self.infer_expr(init);
1414 let evidence = pattern
1416 .evidentiality()
1417 .map(EvidenceLevel::from_ast)
1418 .unwrap_or_else(|| self.get_evidence(&init_ty));
1419 let final_ty = declared_ty.unwrap_or(init_ty);
1420 self.infer_expr(else_branch);
1422 if let Some(name) = pattern.binding_name() {
1423 self.env.borrow_mut().define(name, final_ty, evidence);
1424 }
1425 Type::Unit
1426 }
1427 Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1428 Stmt::Item(item) => {
1429 self.check_item(item);
1430 Type::Unit
1431 }
1432 }
1433 }
1434
1435 pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1437 match expr {
1438 Expr::Literal(lit) => self.infer_literal(lit),
1439
1440 Expr::Path(path) => {
1441 if path.segments.len() == 1 {
1442 let name = &path.segments[0].ident.name;
1443 if let Some((ty, _)) = self.env.borrow().lookup(name) {
1444 return ty;
1445 }
1446 if let Some(ty) = self.functions.get(name).cloned() {
1447 return self.freshen(&ty);
1449 }
1450 } else if path.segments.len() == 2 {
1451 let type_name = &path.segments[0].ident.name;
1453 let method_name = &path.segments[1].ident.name;
1454
1455 if let Some(methods) = self.impl_methods.get(type_name) {
1457 if let Some(ty) = methods.get(method_name) {
1458 let ty_cloned = ty.clone();
1459 return self.freshen(&ty_cloned);
1460 }
1461 }
1462
1463 if let Some(TypeDef::Enum { variants, .. }) = self.types.get(type_name) {
1465 for (variant_name, _variant_fields) in variants {
1466 if variant_name == method_name {
1467 return Type::Named {
1469 name: type_name.clone(),
1470 generics: vec![],
1471 };
1472 }
1473 }
1474 }
1475 }
1476 self.fresh_var()
1480 }
1481
1482 Expr::Binary { left, op, right } => {
1483 let lt = self.infer_expr(left);
1484 let rt = self.infer_expr(right);
1485 self.infer_binary_op(op, <, &rt)
1486 }
1487
1488 Expr::Unary { op, expr } => {
1489 let inner = self.infer_expr(expr);
1490 self.infer_unary_op(op, &inner)
1491 }
1492
1493 Expr::Call { func, args } => {
1494 let fn_type = self.infer_expr(func);
1495 let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1496
1497 if let Type::Function {
1498 params,
1499 return_type,
1500 ..
1501 } = fn_type
1502 {
1503 if params.len() != arg_types.len() {
1505 self.error(TypeError::new(format!(
1506 "expected {} arguments, found {}",
1507 params.len(),
1508 arg_types.len()
1509 )));
1510 }
1511
1512 for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1514 if !self.unify(param, arg) {
1516 let is_numeric_coercion = Self::is_numeric_coercion(param, arg);
1518 if !matches!(param, Type::Var(_)) && !matches!(arg, Type::Var(_)) && !is_numeric_coercion {
1520 self.error(TypeError::new(format!(
1521 "type mismatch in argument {}: expected {}, found {}",
1522 i + 1, param, arg
1523 )));
1524 }
1525 }
1526
1527 if !matches!(param, Type::Var(_)) {
1531 let expected_evidence = self.get_evidence(param);
1532 let actual_evidence = self.get_evidence(arg);
1533 self.check_evidence(
1534 expected_evidence,
1535 actual_evidence,
1536 &format!("in argument {}", i + 1),
1537 );
1538 }
1539 }
1540
1541 *return_type
1542 } else if let Type::Var(_) = &fn_type {
1543 let result_ty = self.fresh_var();
1546 let inferred_fn = Type::Function {
1547 params: arg_types,
1548 return_type: Box::new(result_ty.clone()),
1549 is_async: false,
1550 };
1551 self.unify(&fn_type, &inferred_fn);
1552 result_ty
1553 } else {
1554 self.fresh_var()
1556 }
1557 }
1558
1559 Expr::Array(elements) => {
1560 if elements.is_empty() {
1561 Type::Array {
1562 element: Box::new(self.fresh_var()),
1563 size: Some(0),
1564 }
1565 } else {
1566 let elem_ty = self.infer_expr(&elements[0]);
1567 for elem in &elements[1..] {
1568 let t = self.infer_expr(elem);
1569 if !self.unify(&elem_ty, &t) {
1570 self.error(TypeError::new("array elements must have same type"));
1571 }
1572 }
1573 Type::Array {
1574 element: Box::new(elem_ty),
1575 size: Some(elements.len()),
1576 }
1577 }
1578 }
1579
1580 Expr::Tuple(elements) => {
1581 Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1582 }
1583
1584 Expr::Block(block) => self.check_block(block),
1585
1586 Expr::If {
1587 condition,
1588 then_branch,
1589 else_branch,
1590 } => {
1591 let cond_ty = self.infer_expr(condition);
1592 if !self.unify(&Type::Bool, &cond_ty) {
1593 self.error(TypeError::new("if condition must be bool"));
1594 }
1595
1596 let then_ty = self.check_block(then_branch);
1597
1598 if let Some(else_expr) = else_branch {
1599 let else_ty = match else_expr.as_ref() {
1601 Expr::Block(block) => self.check_block(block),
1602 other => self.infer_expr(other),
1603 };
1604 let _ = self.unify(&then_ty, &else_ty);
1607
1608 let then_ev = self.get_evidence(&then_ty);
1613 let else_ev = self.get_evidence(&else_ty);
1614 let joined_ev = then_ev.join(else_ev);
1615
1616 let (inner_ty, _) = self.strip_evidence(&then_ty);
1617 if joined_ev > EvidenceLevel::Known {
1618 Type::Evidential {
1619 inner: Box::new(inner_ty),
1620 evidence: joined_ev,
1621 }
1622 } else {
1623 inner_ty
1624 }
1625 } else {
1626 Type::Unit
1627 }
1628 }
1629
1630 Expr::While {
1631 condition,
1632 body,
1633 ..
1634 } => {
1635 let cond_ty = self.infer_expr(condition);
1636 if !self.unify(&Type::Bool, &cond_ty) {
1637 self.error(TypeError::new("while condition must be bool"));
1638 }
1639 self.check_block(body);
1640 Type::Unit
1641 }
1642
1643 Expr::Loop { body, .. } => {
1644 self.check_block(body);
1645 Type::Unit
1646 }
1647
1648 Expr::For {
1649 pattern: _,
1650 iter,
1651 body,
1652 ..
1653 } => {
1654 let _ = self.infer_expr(iter);
1656 self.check_block(body);
1657 Type::Unit
1658 }
1659
1660 Expr::Pipe { expr, operations } => {
1661 let mut current = self.infer_expr(expr);
1662
1663 for op in operations {
1664 current = self.infer_pipe_op(op, ¤t);
1665 }
1666
1667 current
1668 }
1669
1670 Expr::Index { expr, index } => {
1671 let coll_ty = self.infer_expr(expr);
1672 let idx_ty = self.infer_expr(index);
1673
1674 match coll_ty {
1675 Type::Array { element, .. } | Type::Slice(element) => {
1676 if !matches!(idx_ty, Type::Int(_)) {
1677 self.error(TypeError::new("index must be integer"));
1678 }
1679 *element
1680 }
1681 _ => {
1682 self.fresh_var()
1684 }
1685 }
1686 }
1687
1688 Expr::Return(val) => {
1689 let actual_type = if let Some(e) = val {
1690 self.infer_expr(e)
1691 } else {
1692 Type::Unit
1693 };
1694
1695 if let Some(expected) = self.expected_return_type.clone() {
1697 if !self.unify(&expected, &actual_type) {
1698 self.error(TypeError::new(format!(
1699 "type mismatch in return: expected {}, found {}",
1700 expected, actual_type
1701 )));
1702 }
1703 }
1704
1705 Type::Never
1706 }
1707
1708 Expr::Evidential {
1710 expr,
1711 evidentiality,
1712 } => {
1713 let inner = self.infer_expr(expr);
1714 Type::Evidential {
1715 inner: Box::new(inner),
1716 evidence: EvidenceLevel::from_ast(*evidentiality),
1717 }
1718 }
1719
1720 Expr::Match { expr, arms } => {
1722 let scrutinee = self.infer_expr(expr);
1723 let scrutinee_ev = self.get_evidence(&scrutinee);
1724
1725 if arms.is_empty() {
1726 return Type::Never; }
1728
1729 let mut arm_types: Vec<Type> = Vec::new();
1731 let mut max_evidence = EvidenceLevel::Known;
1732
1733 for arm in arms {
1734 self.push_scope();
1735
1736 self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
1739
1740 if let Some(ref guard) = arm.guard {
1742 let guard_ty = self.infer_expr(guard);
1743 if !self.unify(&Type::Bool, &guard_ty) {
1744 self.error(TypeError::new("match guard must be bool"));
1745 }
1746 }
1747
1748 let body_ty = self.infer_expr(&arm.body);
1750 let body_ev = self.get_evidence(&body_ty);
1751
1752 max_evidence = max_evidence.join(body_ev);
1754 arm_types.push(body_ty);
1755
1756 self.pop_scope();
1757 }
1758
1759 let first_ty = &arm_types[0];
1762 for (_i, ty) in arm_types.iter().enumerate().skip(1) {
1763 let _ = self.unify(first_ty, ty);
1764 }
1765
1766 let (inner_ty, _) = self.strip_evidence(first_ty);
1768 if max_evidence > EvidenceLevel::Known {
1769 Type::Evidential {
1770 inner: Box::new(inner_ty),
1771 evidence: max_evidence,
1772 }
1773 } else {
1774 inner_ty
1775 }
1776 }
1777
1778 Expr::MethodCall {
1779 receiver,
1780 method,
1781 args,
1782 ..
1783 } => {
1784 let recv_ty = self.infer_expr(receiver);
1785 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
1786 let _arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1787
1788 let result_ty = match method.name.as_str() {
1790 "len" | "count" | "size" => Type::Int(IntSize::USize),
1792
1793 "is_empty" | "contains" | "starts_with" | "ends_with" | "is_some"
1795 | "is_none" | "is_ok" | "is_err" | "is_ascii" | "is_alphabetic"
1796 | "is_numeric" | "is_alphanumeric" | "is_whitespace" | "is_uppercase"
1797 | "is_lowercase" | "exists" | "is_file" | "is_dir" | "is_match"
1798 | "matches" | "eq" | "ne" | "lt" | "le" | "gt" | "ge" => Type::Bool,
1799
1800 "to_string" | "to_lowercase" | "to_uppercase" | "trim" | "trim_start"
1802 | "trim_end" | "to_owned" | "replace" | "replacen" | "repeat"
1803 | "to_string_lossy" => Type::Named {
1804 name: "String".to_string(),
1805 generics: vec![],
1806 },
1807
1808 "as_str" | "trim_matches" | "trim_start_matches" | "trim_end_matches"
1810 | "strip_prefix" | "strip_suffix" => Type::Ref {
1811 lifetime: None,
1812 mutable: false,
1813 inner: Box::new(Type::Str),
1814 },
1815
1816 "clone" | "cloned" | "copied" => recv_inner.clone(),
1818
1819 "unwrap" | "unwrap_or" | "unwrap_or_default" | "unwrap_or_else"
1821 | "expect" | "ok" | "err" => {
1822 if let Type::Named { name, generics } = &recv_inner {
1823 if (name == "Option" || name == "Result") && !generics.is_empty() {
1824 generics[0].clone()
1825 } else {
1826 self.fresh_var()
1827 }
1828 } else {
1829 self.fresh_var()
1830 }
1831 }
1832
1833 "collect" => self.fresh_var(),
1835
1836 "iter" | "into_iter" | "iter_mut" | "rev" | "skip" | "take"
1838 | "filter" | "map" | "filter_map" | "flat_map" | "enumerate"
1839 | "zip" | "chain" | "flatten" | "reverse" | "sorted"
1840 | "dedup" | "unique" | "peekable" | "fuse" | "cycle" | "step_by"
1841 | "take_while" | "skip_while" | "scan" | "inspect" => recv_inner.clone(),
1842
1843 "split" | "rsplit" | "splitn" | "rsplitn" | "split_whitespace"
1845 | "split_ascii_whitespace" | "lines" | "chars" | "bytes"
1846 | "char_indices" | "split_terminator" | "rsplit_terminator"
1847 | "split_inclusive" | "matches_iter" => self.fresh_var(),
1848
1849 "keys" | "values" | "values_mut" | "into_keys"
1851 | "into_values" | "entry" | "drain" => self.fresh_var(),
1852
1853 "first" | "last" | "get" | "get_mut" | "pop" | "pop_front"
1855 | "pop_back" | "find" | "find_map" | "position" | "rposition"
1856 | "next" | "next_back" | "peek" | "nth" | "last_mut"
1857 | "binary_search" | "parent" | "file_name" | "file_stem"
1858 | "extension" => Type::Named {
1859 name: "Option".to_string(),
1860 generics: vec![self.fresh_var()],
1861 },
1862
1863 "parse" | "try_into" | "try_from" => Type::Named {
1865 name: "Result".to_string(),
1866 generics: vec![self.fresh_var(), self.fresh_var()],
1867 },
1868
1869 "push" | "push_str" | "push_front" | "push_back" | "insert"
1871 | "remove" | "clear" | "sort" | "sort_by" | "sort_by_key"
1872 | "sort_unstable" | "truncate" | "resize" | "extend" | "append"
1873 | "retain" | "swap" | "swap_remove" => Type::Unit,
1874
1875 "abs" | "floor" | "ceil" | "round" | "trunc" | "fract" | "sqrt"
1877 | "cbrt" | "sin" | "cos" | "tan" | "asin" | "acos" | "atan"
1878 | "sinh" | "cosh" | "tanh" | "exp" | "exp2" | "ln" | "log"
1879 | "log2" | "log10" | "pow" | "powi" | "powf" | "min" | "max"
1880 | "clamp" | "signum" | "copysign" | "saturating_add"
1881 | "saturating_sub" | "saturating_mul" | "wrapping_add"
1882 | "wrapping_sub" | "wrapping_mul" | "checked_add" | "checked_sub"
1883 | "checked_mul" | "checked_div" => recv_inner.clone(),
1884
1885 "to_digit" | "to_lowercase_char" | "to_uppercase_char" => Type::Named {
1887 name: "Option".to_string(),
1888 generics: vec![Type::Int(IntSize::U32)],
1889 },
1890
1891 "duration_since" | "elapsed" | "as_secs" | "as_millis" | "as_micros"
1893 | "as_nanos" | "from_secs" | "from_millis" => recv_inner.clone(),
1894
1895 "to_path_buf" | "join" | "with_extension" | "with_file_name" => {
1897 Type::Named {
1898 name: "PathBuf".to_string(),
1899 generics: vec![],
1900 }
1901 }
1902
1903 "to_str" => Type::Named {
1905 name: "Option".to_string(),
1906 generics: vec![Type::Ref {
1907 lifetime: None,
1908 mutable: false,
1909 inner: Box::new(Type::Str),
1910 }],
1911 },
1912
1913 "fmt" | "write_str" | "write_fmt" => Type::Named {
1915 name: "Result".to_string(),
1916 generics: vec![Type::Unit, self.fresh_var()],
1917 },
1918
1919 "read" | "write" | "flush" | "read_to_string" | "read_to_end"
1921 | "read_line" | "write_all" => Type::Named {
1922 name: "Result".to_string(),
1923 generics: vec![self.fresh_var(), self.fresh_var()],
1924 },
1925
1926 "metadata" | "modified" | "created" | "accessed" | "len_file"
1928 | "is_readonly" | "permissions" => Type::Named {
1929 name: "Result".to_string(),
1930 generics: vec![self.fresh_var(), self.fresh_var()],
1931 },
1932
1933 "map_err" | "and_then" | "or_else" => recv_inner.clone(),
1935
1936 "and" | "or" => recv_inner.clone(),
1938
1939 _ => self.fresh_var(),
1941 };
1942
1943 if recv_ev > EvidenceLevel::Known {
1945 Type::Evidential {
1946 inner: Box::new(result_ty),
1947 evidence: recv_ev,
1948 }
1949 } else {
1950 result_ty
1951 }
1952 }
1953
1954 Expr::Field { expr, field } => {
1955 let recv_ty = self.infer_expr(expr);
1956 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
1957
1958 let field_ty = if let Type::Named { name, .. } = &recv_inner {
1960 if let Some(struct_def) = self.types.get(name) {
1962 if let TypeDef::Struct { fields, .. } = struct_def {
1963 fields
1964 .iter()
1965 .find(|(n, _)| n == &field.name)
1966 .map(|(_, ty)| ty.clone())
1967 .unwrap_or_else(|| self.fresh_var())
1968 } else {
1969 self.fresh_var()
1970 }
1971 } else {
1972 self.fresh_var()
1973 }
1974 } else {
1975 self.fresh_var()
1976 };
1977
1978 if recv_ev > EvidenceLevel::Known {
1980 Type::Evidential {
1981 inner: Box::new(field_ty),
1982 evidence: recv_ev,
1983 }
1984 } else {
1985 field_ty
1986 }
1987 }
1988
1989 Expr::Index { expr, index, .. } => {
1990 let arr_ty = self.infer_expr(expr);
1991 let idx_ty = self.infer_expr(index);
1992 let (arr_inner, arr_ev) = self.strip_evidence(&arr_ty);
1993
1994 let _ = self.unify(&idx_ty, &Type::Int(IntSize::USize));
1996
1997 let elem_ty = match arr_inner {
1999 Type::Array { element, .. } => *element,
2000 Type::Slice(element) => *element,
2001 Type::Named { name, generics } if name == "Vec" && !generics.is_empty() => {
2002 generics[0].clone()
2003 }
2004 _ => self.fresh_var(),
2005 };
2006
2007 if arr_ev > EvidenceLevel::Known {
2009 Type::Evidential {
2010 inner: Box::new(elem_ty),
2011 evidence: arr_ev,
2012 }
2013 } else {
2014 elem_ty
2015 }
2016 }
2017
2018 _ => {
2019 self.fresh_var()
2021 }
2022 }
2023 }
2024
2025 fn infer_literal(&self, lit: &Literal) -> Type {
2027 match lit {
2028 Literal::Int { .. } => Type::Int(IntSize::I64),
2029 Literal::Float { suffix, .. } => {
2030 match suffix.as_ref().map(|s| s.as_str()) {
2031 Some("f32") => Type::Float(FloatSize::F32),
2032 Some("f64") => Type::Float(FloatSize::F64),
2033 None | Some(_) => Type::Float(FloatSize::F64),
2035 }
2036 }
2037 Literal::Bool(_) => Type::Bool,
2038 Literal::Char(_) => Type::Char,
2039 Literal::ByteChar(_) => Type::Int(IntSize::U8),
2040 Literal::String(_) => Type::Ref {
2042 lifetime: None,
2043 mutable: false,
2044 inner: Box::new(Type::Str),
2045 },
2046 Literal::MultiLineString(_) => Type::Ref {
2047 lifetime: None,
2048 mutable: false,
2049 inner: Box::new(Type::Str),
2050 },
2051 Literal::RawString(_) => Type::Ref {
2052 lifetime: None,
2053 mutable: false,
2054 inner: Box::new(Type::Str),
2055 },
2056 Literal::ByteString(bytes) => Type::Ref {
2057 lifetime: None,
2058 mutable: false,
2059 inner: Box::new(Type::Array {
2060 element: Box::new(Type::Int(IntSize::U8)),
2061 size: Some(bytes.len()),
2062 }),
2063 },
2064 Literal::InterpolatedString { .. } => Type::Str,
2065 Literal::SigilStringSql(_) => Type::Str,
2066 Literal::SigilStringRoute(_) => Type::Str,
2067 Literal::Null => Type::Unit, Literal::Empty => Type::Unit,
2069 Literal::Infinity => Type::Float(FloatSize::F64),
2070 Literal::Circle => Type::Float(FloatSize::F64),
2071 }
2072 }
2073
2074 fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
2076 let (left_inner, left_ev) = self.strip_evidence(left);
2078 let (right_inner, right_ev) = self.strip_evidence(right);
2079
2080 let is_var_or_fn = |ty: &Type| {
2082 matches!(ty, Type::Var(_) | Type::Function { .. })
2083 };
2084
2085 let result_ty = match op {
2086 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
2088 let _ = self.unify(&left_inner, &right_inner);
2091 left_inner
2092 }
2093
2094 BinOp::MatMul | BinOp::Hadamard | BinOp::TensorProd => {
2098 self.fresh_var()
2100 }
2101
2102 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
2104 if !self.unify(&left_inner, &right_inner)
2107 && !is_var_or_fn(&left_inner)
2108 && !is_var_or_fn(&right_inner)
2109 {
2110 self.error(TypeError::new(format!(
2111 "comparison operands must have same type: left={:?}, right={:?}",
2112 left_inner, right_inner
2113 )));
2114 }
2115 Type::Bool
2116 }
2117
2118 BinOp::And | BinOp::Or => {
2120 if !self.unify(&Type::Bool, &left_inner) {
2121 self.error(TypeError::new("logical operand must be bool"));
2122 }
2123 if !self.unify(&Type::Bool, &right_inner) {
2124 self.error(TypeError::new("logical operand must be bool"));
2125 }
2126 Type::Bool
2127 }
2128
2129 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
2131
2132 BinOp::Concat => {
2134 if !self.unify(&Type::Str, &left_inner) {
2135 self.error(TypeError::new("concat operand must be string"));
2136 }
2137 Type::Str
2138 }
2139 };
2140
2141 let combined_ev = left_ev.join(right_ev);
2143
2144 if combined_ev > EvidenceLevel::Known {
2146 Type::Evidential {
2147 inner: Box::new(result_ty),
2148 evidence: combined_ev,
2149 }
2150 } else {
2151 result_ty
2152 }
2153 }
2154
2155 fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
2157 let (inner_ty, evidence) = self.strip_evidence(inner);
2158
2159 let result = match op {
2160 UnaryOp::Neg => inner_ty,
2161 UnaryOp::Not => {
2162 if !self.unify(&Type::Bool, &inner_ty) {
2164 self.error(TypeError::new(format!(
2165 "type mismatch: '!' requires bool, found {}",
2166 inner_ty
2167 )));
2168 }
2169 Type::Bool
2170 }
2171 UnaryOp::Ref => Type::Ref {
2172 lifetime: None,
2173 mutable: false,
2174 inner: Box::new(inner_ty),
2175 },
2176 UnaryOp::RefMut => Type::Ref {
2177 lifetime: None,
2178 mutable: true,
2179 inner: Box::new(inner_ty),
2180 },
2181 UnaryOp::Deref => {
2182 if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
2183 *inner
2184 } else {
2185 self.fresh_var()
2187 }
2188 }
2189 };
2190
2191 if evidence > EvidenceLevel::Known {
2193 Type::Evidential {
2194 inner: Box::new(result),
2195 evidence,
2196 }
2197 } else {
2198 result
2199 }
2200 }
2201
2202 fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
2204 let (inner_ev_stripped, evidence) = self.strip_evidence(input);
2205
2206 let inner = match inner_ev_stripped {
2209 Type::Ref { inner: ref_inner, .. } => (*ref_inner).clone(),
2210 other => other,
2211 };
2212
2213 let result = match op {
2214 PipeOp::Transform(_body) => {
2216 if let Type::Array { element, size } = inner {
2217 Type::Array { element, size }
2218 } else if let Type::Slice(element) = inner {
2219 Type::Slice(element)
2220 } else {
2221 self.fresh_var()
2223 }
2224 }
2225
2226 PipeOp::Filter(_pred) => inner,
2228
2229 PipeOp::Sort(_) => inner,
2231
2232 PipeOp::Reduce(_) => {
2234 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2235 *element
2236 } else if let Type::Named { name, generics } = &inner {
2237 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2239 && !generics.is_empty() {
2240 generics[0].clone()
2241 } else {
2242 self.fresh_var()
2243 }
2244 } else if let Type::Var(_) = inner {
2245 self.fresh_var()
2247 } else {
2248 self.error(TypeError::new("reduce requires array or slice"));
2249 Type::Error
2250 }
2251 }
2252 PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
2253 let element = if let Type::Array { element, .. } | Type::Slice(element) = &inner {
2255 Some(element.clone())
2256 } else if let Type::Named { name, generics } = &inner {
2257 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2259 && !generics.is_empty() {
2260 Some(Box::new(generics[0].clone()))
2261 } else {
2262 None
2263 }
2264 } else {
2265 None
2266 };
2267 if let Some(element) = element {
2268 match element.as_ref() {
2269 Type::Int(_) | Type::Float(_) => *element,
2270 Type::Var(_) => *element, _ => {
2272 self.error(TypeError::new("numeric reduction requires numeric array"));
2273 Type::Error
2274 }
2275 }
2276 } else if let Type::Var(_) = inner {
2277 self.fresh_var()
2279 } else {
2280 self.error(TypeError::new("reduction requires array or slice"));
2281 Type::Error
2282 }
2283 }
2284 PipeOp::ReduceConcat => {
2285 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2287 match element.as_ref() {
2288 Type::Str => Type::Str,
2289 Type::Array { .. } => *element,
2290 Type::Var(_) => self.fresh_var(), _ => {
2292 self.error(TypeError::new(
2293 "concat reduction requires array of strings or arrays",
2294 ));
2295 Type::Error
2296 }
2297 }
2298 } else if let Type::Var(_) = inner {
2299 self.fresh_var()
2301 } else {
2302 self.error(TypeError::new("concat reduction requires array or slice"));
2303 Type::Error
2304 }
2305 }
2306 PipeOp::ReduceAll | PipeOp::ReduceAny => {
2307 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2309 match element.as_ref() {
2310 Type::Bool => Type::Bool,
2311 Type::Var(_) => Type::Bool, _ => {
2313 self.error(TypeError::new(
2314 "boolean reduction requires array of booleans",
2315 ));
2316 Type::Error
2317 }
2318 }
2319 } else if let Type::Var(_) = inner {
2320 Type::Bool
2322 } else {
2323 self.error(TypeError::new("boolean reduction requires array or slice"));
2324 Type::Error
2325 }
2326 }
2327
2328 PipeOp::Match(arms) => {
2330 if arms.is_empty() {
2332 self.error(TypeError::new("match expression has no arms"));
2333 Type::Error
2334 } else {
2335 let result_type = self.infer_expr(&arms[0].body);
2337 for arm in arms.iter().skip(1) {
2338 let arm_type = self.infer_expr(&arm.body);
2339 self.unify(&result_type, &arm_type);
2340 }
2341 result_type
2342 }
2343 }
2344
2345 PipeOp::TryMap(_) => {
2347 self.fresh_var()
2351 }
2352
2353 PipeOp::Call(callee) => {
2355 let callee_ty = self.infer_expr(callee);
2357 if let Type::Function { return_type, .. } = callee_ty {
2358 *return_type
2359 } else {
2360 self.fresh_var()
2362 }
2363 }
2364
2365 PipeOp::Method { name, type_args: _, args: _ } => {
2367 if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
2369 let fresh_ty = self.freshen(&fn_ty);
2371 if let Type::Function { return_type, .. } = fresh_ty {
2372 *return_type
2373 } else {
2374 Type::Error
2375 }
2376 } else {
2377 self.fresh_var()
2379 }
2380 }
2381
2382 PipeOp::Named { prefix, body: _ } => {
2384 if let Some(first) = prefix.first() {
2386 match first.name.as_str() {
2387 "sum" | "product" => {
2388 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2389 *element
2390 } else {
2391 self.error(TypeError::new("sum/product requires array"));
2392 Type::Error
2393 }
2394 }
2395 _ => self.fresh_var(),
2396 }
2397 } else {
2398 self.fresh_var()
2399 }
2400 }
2401
2402 PipeOp::Await => {
2404 inner
2406 }
2407
2408 PipeOp::First
2410 | PipeOp::Last
2411 | PipeOp::Middle
2412 | PipeOp::Choice
2413 | PipeOp::Nth(_)
2414 | PipeOp::Next => {
2415 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2416 *element
2417 } else if let Type::Named { name, generics } = &inner {
2418 if (name == "Vec" || name == "VecDeque" || name == "LinkedList")
2420 && !generics.is_empty() {
2421 generics[0].clone()
2422 } else {
2423 self.fresh_var()
2424 }
2425 } else if let Type::Tuple(elements) = inner {
2426 if let Some(first) = elements.first() {
2428 first.clone()
2429 } else {
2430 Type::Unit
2431 }
2432 } else if let Type::Var(_) = inner {
2433 self.fresh_var()
2435 } else {
2436 self.fresh_var()
2438 }
2439 }
2440
2441 PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
2444
2445 PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
2448
2449 PipeOp::Send(_) => {
2456 Type::Evidential {
2458 inner: Box::new(self.fresh_var()),
2459 evidence: EvidenceLevel::Reported,
2460 }
2461 }
2462
2463 PipeOp::Recv => {
2465 Type::Evidential {
2467 inner: Box::new(self.fresh_var()),
2468 evidence: EvidenceLevel::Reported,
2469 }
2470 }
2471
2472 PipeOp::Stream(_) => {
2474 self.fresh_var()
2476 }
2477
2478 PipeOp::Connect(_) => {
2480 self.fresh_var()
2482 }
2483
2484 PipeOp::Close => Type::Unit,
2486
2487 PipeOp::Header { .. } => inner,
2489
2490 PipeOp::Body(_) => inner,
2492
2493 PipeOp::Timeout(_) => inner,
2495
2496 PipeOp::Retry { .. } => inner,
2498
2499 PipeOp::Validate {
2505 predicate: _,
2506 target_evidence,
2507 } => {
2508 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2512
2513 if evidence < target_ev {
2515 self.error(
2516 TypeError::new(format!(
2517 "cannot demote evidence from {} ({}) to {} ({}) using validate",
2518 evidence.name(),
2519 evidence.symbol(),
2520 target_ev.name(),
2521 target_ev.symbol()
2522 ))
2523 .with_note("validate! can only promote evidence to a more certain level"),
2524 );
2525 }
2526
2527 return Type::Evidential {
2529 inner: Box::new(inner.clone()),
2530 evidence: target_ev,
2531 };
2532 }
2533
2534 PipeOp::Assume {
2536 reason: _,
2537 target_evidence,
2538 } => {
2539 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2540
2541 if evidence < target_ev {
2545 self.error(
2546 TypeError::new(format!(
2547 "assume! cannot demote evidence from {} ({}) to {} ({})",
2548 evidence.name(),
2549 evidence.symbol(),
2550 target_ev.name(),
2551 target_ev.symbol()
2552 ))
2553 .with_note("assume! is for promoting evidence, not demoting"),
2554 );
2555 }
2556
2557 return Type::Evidential {
2559 inner: Box::new(inner.clone()),
2560 evidence: target_ev,
2561 };
2562 }
2563
2564 PipeOp::AssertEvidence(expected_ast) => {
2566 let expected = EvidenceLevel::from_ast(*expected_ast);
2567
2568 if !evidence.satisfies(expected) {
2569 self.error(
2570 TypeError::new(format!(
2571 "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
2572 expected.name(), expected.symbol(),
2573 evidence.name(), evidence.symbol()
2574 ))
2575 .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
2576 );
2577 }
2578
2579 return input.clone();
2581 }
2582
2583 PipeOp::Also(_) => {
2590 return input.clone();
2593 }
2594
2595 PipeOp::Apply(_) => {
2598 return input.clone();
2601 }
2602
2603 PipeOp::TakeIf(_) => {
2606 return Type::Named {
2609 name: "Option".to_string(),
2610 generics: vec![input.clone()],
2611 };
2612 }
2613
2614 PipeOp::TakeUnless(_) => {
2617 return Type::Named {
2620 name: "Option".to_string(),
2621 generics: vec![input.clone()],
2622 };
2623 }
2624
2625 PipeOp::Let(func) => {
2628 let _ = self.infer_expr(func);
2630 self.fresh_var() }
2632
2633 PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
2635 PipeOp::Compose(f) => {
2636 let _ = self.infer_expr(f);
2637 self.fresh_var()
2638 }
2639 PipeOp::Zip(other) => {
2640 let _ = self.infer_expr(other);
2641 self.fresh_var() }
2643 PipeOp::Scan(f) => {
2644 let _ = self.infer_expr(f);
2645 self.fresh_var() }
2647 PipeOp::Diff => self.fresh_var(), PipeOp::Gradient(var) => {
2649 let _ = self.infer_expr(var);
2650 self.fresh_var() }
2652 PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
2653 inner.clone() }
2655 PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
2656 let _ = self.infer_expr(n);
2657 self.fresh_var() }
2659 PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
2660 PipeOp::Enumerate => self.fresh_var(), };
2662
2663 if evidence > EvidenceLevel::Known {
2665 Type::Evidential {
2666 inner: Box::new(result),
2667 evidence,
2668 }
2669 } else {
2670 result
2671 }
2672 }
2673
2674 fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
2676 match ty {
2677 Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
2678 _ => (ty.clone(), EvidenceLevel::Known),
2679 }
2680 }
2681
2682 fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
2685 let (inner_ty, ty_ev) = self.strip_evidence(ty);
2686 let final_ev = evidence.join(ty_ev);
2688
2689 match pattern {
2690 Pattern::Ident {
2691 name,
2692 evidentiality,
2693 ..
2694 } => {
2695 let ev = evidentiality
2697 .map(EvidenceLevel::from_ast)
2698 .unwrap_or(final_ev);
2699 self.env
2700 .borrow_mut()
2701 .define(name.name.clone(), inner_ty, ev);
2702 }
2703 Pattern::Tuple(patterns) => {
2704 if let Type::Tuple(types) = &inner_ty {
2705 for (pat, ty) in patterns.iter().zip(types.iter()) {
2706 self.bind_pattern(pat, ty, final_ev);
2707 }
2708 }
2709 }
2710 Pattern::Struct { fields, .. } => {
2711 for field in fields {
2714 let fresh = self.fresh_var();
2715 if let Some(ref pat) = field.pattern {
2716 self.bind_pattern(pat, &fresh, final_ev);
2717 } else {
2718 self.env
2719 .borrow_mut()
2720 .define(field.name.name.clone(), fresh, final_ev);
2721 }
2722 }
2723 }
2724 Pattern::TupleStruct { fields, .. } => {
2725 for pat in fields {
2726 let fresh = self.fresh_var();
2727 self.bind_pattern(pat, &fresh, final_ev);
2728 }
2729 }
2730 Pattern::Slice(patterns) => {
2731 let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
2732 {
2733 *element.clone()
2734 } else {
2735 self.fresh_var()
2736 };
2737 for pat in patterns {
2738 self.bind_pattern(pat, &elem_ty, final_ev);
2739 }
2740 }
2741 Pattern::Or(patterns) => {
2742 if let Some(first) = patterns.first() {
2745 self.bind_pattern(first, ty, evidence);
2746 }
2747 }
2748 Pattern::Wildcard | Pattern::Rest | Pattern::Literal(_) | Pattern::Range { .. } | Pattern::Path(_) => {
2749 }
2751 Pattern::Ref { pattern, .. } => {
2752 let inner_ty = self.fresh_var();
2755 self.bind_pattern(pattern, &inner_ty, final_ev);
2756 }
2757 Pattern::RefBinding {
2758 name,
2759 evidentiality,
2760 ..
2761 } => {
2762 let ev = evidentiality
2764 .map(EvidenceLevel::from_ast)
2765 .unwrap_or(final_ev);
2766 self.env
2767 .borrow_mut()
2768 .define(name.name.clone(), inner_ty, ev);
2769 }
2770 }
2771 }
2772
2773 fn resolve_alias(&self, ty: &Type) -> Type {
2775 if let Type::Named { name, generics } = ty {
2776 if generics.is_empty() {
2777 if let Some(TypeDef::Alias { target, .. }) = self.types.get(name) {
2778 return target.clone();
2779 }
2780 }
2781 }
2782 ty.clone()
2783 }
2784
2785 fn unify(&mut self, a: &Type, b: &Type) -> bool {
2787 let a = self.resolve_alias(a);
2789 let b = self.resolve_alias(b);
2790
2791 match (&a, &b) {
2792 (Type::Var(v), t) => {
2794 if let Some(resolved) = self.substitutions.get(v) {
2795 let resolved = resolved.clone();
2796 self.unify(&resolved, t)
2797 } else if !self.occurs_in(v, t) {
2798 self.substitutions.insert(*v, t.clone());
2799 true
2800 } else {
2801 true
2803 }
2804 }
2805 (t, Type::Var(v)) => {
2806 if let Some(resolved) = self.substitutions.get(v) {
2807 let resolved = resolved.clone();
2808 self.unify(t, &resolved)
2809 } else if !self.occurs_in(v, t) {
2810 self.substitutions.insert(*v, t.clone());
2811 true
2812 } else {
2813 true
2815 }
2816 }
2817
2818 (Type::Unit, Type::Unit) |
2820 (Type::Bool, Type::Bool) |
2821 (Type::Char, Type::Char) |
2822 (Type::Str, Type::Str) |
2823 (Type::Never, Type::Never) |
2824 (Type::Error, _) |
2825 (_, Type::Error) |
2826 (Type::Never, _) |
2828 (_, Type::Never) => true,
2829
2830 (Type::Int(_), Type::Int(_)) => true,
2833 (Type::Float(_), Type::Float(_)) => true,
2836
2837 (Type::Ref { mutable: false, inner: a, .. }, Type::Str) if matches!(a.as_ref(), Type::Str) => true,
2839 (Type::Str, Type::Ref { mutable: false, inner: b, .. }) if matches!(b.as_ref(), Type::Str) => true,
2840
2841 (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
2843 (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
2844 }
2845
2846 (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
2848
2849 (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
2851 a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
2852 }
2853
2854 (Type::Ref { mutable: ma, inner: a, .. }, Type::Ref { mutable: mb, inner: b, .. }) => {
2856 match (a.as_ref(), b.as_ref()) {
2858 (Type::Array { element: ea, .. }, Type::Slice(es)) => {
2859 ma == mb && self.unify(ea, es)
2860 }
2861 (Type::Slice(es), Type::Array { element: ea, .. }) => {
2862 ma == mb && self.unify(es, ea)
2863 }
2864 _ => ma == mb && self.unify(a, b)
2865 }
2866 }
2867
2868 (Type::Function { params: pa, return_type: ra, is_async: aa },
2870 Type::Function { params: pb, return_type: rb, is_async: ab }) => {
2871 aa == ab && pa.len() == pb.len() &&
2872 pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
2873 self.unify(ra, rb)
2874 }
2875
2876 (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
2878 na == nb && ga.len() == gb.len() &&
2879 ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y))
2880 }
2881
2882 (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
2884 self.unify(a, b)
2885 }
2886 (Type::Evidential { inner: a, .. }, b) => {
2887 self.unify(a, b)
2888 }
2889 (a, Type::Evidential { inner: b, .. }) => {
2890 self.unify(a, b)
2891 }
2892
2893 (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
2895
2896 (Type::Named { name, generics }, _) | (_, Type::Named { name, generics })
2900 if generics.is_empty() && Self::is_type_parameter(name) => {
2901 true
2902 }
2903
2904 _ => false,
2905 }
2906 }
2907
2908 fn is_type_parameter(name: &str) -> bool {
2910 if name.len() == 1 && name.chars().next().map(|c| c.is_ascii_uppercase()).unwrap_or(false) {
2912 return true;
2913 }
2914 matches!(name, "Item" | "Output" | "Error" | "Key" | "Value" | "Idx" | "Self")
2916 }
2917
2918 fn is_numeric_coercion(expected: &Type, actual: &Type) -> bool {
2920 match (expected, actual) {
2922 (Type::Float(_), Type::Int(_)) => true,
2923 (Type::Evidential { inner: exp, .. }, Type::Int(_)) => {
2925 matches!(exp.as_ref(), Type::Float(_))
2926 }
2927 (Type::Float(_), Type::Evidential { inner: act, .. }) => {
2928 matches!(act.as_ref(), Type::Int(_))
2929 }
2930 _ => false,
2931 }
2932 }
2933
2934 fn convert_type(&self, ty: &TypeExpr) -> Type {
2936 match ty {
2937 TypeExpr::Path(path) => {
2938 if path.segments.len() == 1 {
2939 let name = &path.segments[0].ident.name;
2940 match name.as_str() {
2941 "bool" => return Type::Bool,
2942 "char" => return Type::Char,
2943 "str" | "String" => return Type::Str,
2944 "i8" => return Type::Int(IntSize::I8),
2945 "i16" => return Type::Int(IntSize::I16),
2946 "i32" => return Type::Int(IntSize::I32),
2947 "i64" => return Type::Int(IntSize::I64),
2948 "i128" => return Type::Int(IntSize::I128),
2949 "isize" => return Type::Int(IntSize::ISize),
2950 "u8" => return Type::Int(IntSize::U8),
2951 "u16" => return Type::Int(IntSize::U16),
2952 "u32" => return Type::Int(IntSize::U32),
2953 "u64" => return Type::Int(IntSize::U64),
2954 "u128" => return Type::Int(IntSize::U128),
2955 "usize" => return Type::Int(IntSize::USize),
2956 "f32" => return Type::Float(FloatSize::F32),
2957 "f64" => return Type::Float(FloatSize::F64),
2958 "Self" => {
2960 if let Some(ref self_ty) = self.current_self_type {
2961 return Type::Named {
2962 name: self_ty.clone(),
2963 generics: vec![],
2964 };
2965 }
2966 }
2967 _ => {
2968 if let Some(ty) = self.current_generics.get(name) {
2970 return ty.clone();
2971 }
2972 }
2973 }
2974 }
2975
2976 let name = path
2977 .segments
2978 .iter()
2979 .map(|s| s.ident.name.clone())
2980 .collect::<Vec<_>>()
2981 .join("::");
2982
2983 let generics = path
2984 .segments
2985 .last()
2986 .and_then(|s| s.generics.as_ref())
2987 .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
2988 .unwrap_or_default();
2989
2990 Type::Named { name, generics }
2991 }
2992
2993 TypeExpr::Reference { lifetime, mutable, inner } => Type::Ref {
2994 lifetime: lifetime.clone(),
2995 mutable: *mutable,
2996 inner: Box::new(self.convert_type(inner)),
2997 },
2998
2999 TypeExpr::Pointer { mutable, inner } => Type::Ptr {
3000 mutable: *mutable,
3001 inner: Box::new(self.convert_type(inner)),
3002 },
3003
3004 TypeExpr::Array { element, size: _ } => {
3005 Type::Array {
3006 element: Box::new(self.convert_type(element)),
3007 size: None, }
3009 }
3010
3011 TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
3012
3013 TypeExpr::Tuple(elements) => {
3014 Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
3015 }
3016
3017 TypeExpr::Function {
3018 params,
3019 return_type,
3020 } => Type::Function {
3021 params: params.iter().map(|t| self.convert_type(t)).collect(),
3022 return_type: Box::new(
3023 return_type
3024 .as_ref()
3025 .map(|t| self.convert_type(t))
3026 .unwrap_or(Type::Unit),
3027 ),
3028 is_async: false,
3029 },
3030
3031 TypeExpr::Evidential {
3032 inner,
3033 evidentiality,
3034 error_type,
3035 } => {
3036 let _ = error_type; Type::Evidential {
3040 inner: Box::new(self.convert_type(inner)),
3041 evidence: EvidenceLevel::from_ast(*evidentiality),
3042 }
3043 }
3044
3045 TypeExpr::Cycle { modulus: _ } => {
3046 Type::Cycle { modulus: 12 } }
3048
3049 TypeExpr::Simd { element, lanes } => {
3050 let elem_ty = self.convert_type(element);
3051 Type::Simd {
3052 element: Box::new(elem_ty),
3053 lanes: *lanes,
3054 }
3055 }
3056
3057 TypeExpr::Atomic(inner) => {
3058 let inner_ty = self.convert_type(inner);
3059 Type::Atomic(Box::new(inner_ty))
3060 }
3061
3062 TypeExpr::Never => Type::Never,
3063 TypeExpr::Infer => Type::Var(TypeVar(0)), TypeExpr::Lifetime(name) => Type::Lifetime(name.clone()),
3065 TypeExpr::TraitObject(bounds) => {
3066 let converted: Vec<Type> = bounds.iter().map(|b| self.convert_type(b)).collect();
3067 Type::TraitObject(converted)
3068 }
3069 TypeExpr::Hrtb { lifetimes, bound } => Type::Hrtb {
3070 lifetimes: lifetimes.clone(),
3071 bound: Box::new(self.convert_type(bound)),
3072 },
3073 TypeExpr::InlineStruct { fields } => Type::InlineStruct {
3074 fields: fields
3075 .iter()
3076 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
3077 .collect(),
3078 },
3079 TypeExpr::ImplTrait(bounds) => {
3080 Type::ImplTrait(bounds.iter().map(|b| self.convert_type(b)).collect())
3081 }
3082 TypeExpr::InlineEnum { variants } => {
3083 Type::InlineEnum(variants.iter().map(|v| v.name.name.clone()).collect())
3084 }
3085 TypeExpr::AssocTypeBinding { name, ty } => Type::AssocTypeBinding {
3086 name: name.name.clone(),
3087 ty: Box::new(self.convert_type(ty)),
3088 },
3089 TypeExpr::ConstExpr(_) => {
3090 Type::Var(TypeVar(0))
3093 }
3094 TypeExpr::QualifiedPath { self_type, trait_path, item_path } => {
3095 let trait_part = trait_path.as_ref()
3098 .map(|tp| tp.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::"))
3099 .unwrap_or_default();
3100 let item_part = item_path.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::");
3101 let name = if trait_part.is_empty() {
3102 format!("<_>::{}", item_part)
3103 } else {
3104 format!("<_ as {}>::{}", trait_part, item_part)
3105 };
3106 Type::Named {
3107 name,
3108 generics: vec![self.convert_type(self_type)],
3109 }
3110 }
3111 }
3112 }
3113
3114 pub fn errors(&self) -> &[TypeError] {
3116 &self.errors
3117 }
3118}
3119
3120impl Default for TypeChecker {
3121 fn default() -> Self {
3122 Self::new()
3123 }
3124}
3125
3126trait PatternExt {
3128 fn evidentiality(&self) -> Option<Evidentiality>;
3129 fn binding_name(&self) -> Option<String>;
3130 fn binding_span(&self) -> Option<Span>;
3131}
3132
3133impl PatternExt for Pattern {
3134 fn evidentiality(&self) -> Option<Evidentiality> {
3135 match self {
3136 Pattern::Ident { evidentiality, .. } => *evidentiality,
3137 _ => None,
3138 }
3139 }
3140
3141 fn binding_name(&self) -> Option<String> {
3142 match self {
3143 Pattern::Ident { name, .. } => Some(name.name.clone()),
3144 _ => None,
3145 }
3146 }
3147
3148 fn binding_span(&self) -> Option<Span> {
3149 match self {
3150 Pattern::Ident { name, .. } => Some(name.span),
3151 _ => None,
3152 }
3153 }
3154}
3155
3156impl fmt::Display for Type {
3157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3158 match self {
3159 Type::Unit => write!(f, "()"),
3160 Type::Bool => write!(f, "bool"),
3161 Type::Int(size) => write!(f, "{:?}", size),
3162 Type::Float(size) => write!(f, "{:?}", size),
3163 Type::Char => write!(f, "char"),
3164 Type::Str => write!(f, "str"),
3165 Type::Array { element, size } => {
3166 if let Some(n) = size {
3167 write!(f, "[{}; {}]", element, n)
3168 } else {
3169 write!(f, "[{}]", element)
3170 }
3171 }
3172 Type::Slice(inner) => write!(f, "[{}]", inner),
3173 Type::Tuple(elems) => {
3174 write!(f, "(")?;
3175 for (i, e) in elems.iter().enumerate() {
3176 if i > 0 {
3177 write!(f, ", ")?;
3178 }
3179 write!(f, "{}", e)?;
3180 }
3181 write!(f, ")")
3182 }
3183 Type::Named { name, generics } => {
3184 write!(f, "{}", name)?;
3185 if !generics.is_empty() {
3186 write!(f, "<")?;
3187 for (i, g) in generics.iter().enumerate() {
3188 if i > 0 {
3189 write!(f, ", ")?;
3190 }
3191 write!(f, "{}", g)?;
3192 }
3193 write!(f, ">")?;
3194 }
3195 Ok(())
3196 }
3197 Type::Function {
3198 params,
3199 return_type,
3200 is_async,
3201 } => {
3202 if *is_async {
3203 write!(f, "async ")?;
3204 }
3205 write!(f, "fn(")?;
3206 for (i, p) in params.iter().enumerate() {
3207 if i > 0 {
3208 write!(f, ", ")?;
3209 }
3210 write!(f, "{}", p)?;
3211 }
3212 write!(f, ") -> {}", return_type)
3213 }
3214 Type::Ref { lifetime, mutable, inner } => {
3215 let lt = lifetime.as_ref().map(|l| format!("'{} ", l)).unwrap_or_default();
3216 write!(f, "&{}{}{}", lt, if *mutable { "mut " } else { "" }, inner)
3217 }
3218 Type::Ptr { mutable, inner } => {
3219 write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
3220 }
3221 Type::Evidential { inner, evidence } => {
3222 write!(f, "{}{}", inner, evidence.symbol())
3223 }
3224 Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
3225 Type::Var(v) => write!(f, "?{}", v.0),
3226 Type::Error => write!(f, "<error>"),
3227 Type::Never => write!(f, "!"),
3228 Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
3229 Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
3230 Type::Lifetime(name) => write!(f, "'{}", name),
3231 Type::TraitObject(bounds) => {
3232 write!(f, "dyn ")?;
3233 for (i, bound) in bounds.iter().enumerate() {
3234 if i > 0 {
3235 write!(f, " + ")?;
3236 }
3237 write!(f, "{}", bound)?;
3238 }
3239 Ok(())
3240 }
3241 Type::Hrtb { lifetimes, bound } => {
3242 write!(f, "for<")?;
3243 for (i, lt) in lifetimes.iter().enumerate() {
3244 if i > 0 {
3245 write!(f, ", ")?;
3246 }
3247 write!(f, "'{}", lt)?;
3248 }
3249 write!(f, "> {}", bound)
3250 }
3251 Type::InlineStruct { fields } => {
3252 write!(f, "struct {{ ")?;
3253 for (i, (name, ty)) in fields.iter().enumerate() {
3254 if i > 0 {
3255 write!(f, ", ")?;
3256 }
3257 write!(f, "{}: {}", name, ty)?;
3258 }
3259 write!(f, " }}")
3260 }
3261 Type::ImplTrait(bounds) => {
3262 write!(f, "impl ")?;
3263 for (i, bound) in bounds.iter().enumerate() {
3264 if i > 0 {
3265 write!(f, " + ")?;
3266 }
3267 write!(f, "{}", bound)?;
3268 }
3269 Ok(())
3270 }
3271 Type::InlineEnum(variants) => {
3272 write!(f, "enum {{ ")?;
3273 for (i, name) in variants.iter().enumerate() {
3274 if i > 0 {
3275 write!(f, ", ")?;
3276 }
3277 write!(f, "{}", name)?;
3278 }
3279 write!(f, " }}")
3280 }
3281 Type::AssocTypeBinding { name, ty } => {
3282 write!(f, "{} = {}", name, ty)
3283 }
3284 }
3285 }
3286}
3287
3288#[cfg(test)]
3289mod tests {
3290 use super::*;
3291 use crate::Parser;
3292
3293 fn check(source: &str) -> Result<(), Vec<TypeError>> {
3294 let mut parser = Parser::new(source);
3295 let file = parser.parse_file().expect("parse failed");
3296 let mut checker = TypeChecker::new();
3297 checker.check_file(&file)
3298 }
3299
3300 #[test]
3301 fn test_basic_types() {
3302 assert!(check("fn main() { let x: i64 = 42; }").is_ok());
3303 assert!(check("fn main() { let x: bool = true; }").is_ok());
3304 assert!(check("fn main() { let x: f64 = 3.14; }").is_ok());
3305 }
3306
3307 #[test]
3308 fn test_type_mismatch() {
3309 assert!(check("fn main() { let x: bool = 42; }").is_err());
3310 }
3311
3312 #[test]
3313 fn test_evidence_propagation() {
3314 assert!(check(
3316 r#"
3317 fn main() {
3318 let known: i64! = 42;
3319 let uncertain: i64? = 10;
3320 let result = known + uncertain;
3321 }
3322 "#
3323 )
3324 .is_ok());
3325 }
3326
3327 #[test]
3328 fn test_function_return() {
3329 let result = check(
3330 r#"
3331 fn add(a: i64, b: i64) -> i64 {
3332 return a + b;
3333 }
3334 fn main() {
3335 let x = add(1, 2);
3336 }
3337 "#,
3338 );
3339 if let Err(errors) = &result {
3340 for e in errors {
3341 eprintln!("Error: {}", e);
3342 }
3343 }
3344 assert!(result.is_ok());
3345 }
3346
3347 #[test]
3348 fn test_array_types() {
3349 assert!(check(
3350 r#"
3351 fn main() {
3352 let arr = [1, 2, 3];
3353 let x = arr[0];
3354 }
3355 "#
3356 )
3357 .is_ok());
3358 }
3359
3360 #[test]
3365 fn test_evidence_inference_from_initializer() {
3366 assert!(check(
3368 r#"
3369 fn main() {
3370 let reported_val: i64~ = 42;
3371 // x should inherit ~ evidence from reported_val
3372 let x = reported_val + 1;
3373 }
3374 "#
3375 )
3376 .is_ok());
3377 }
3378
3379 #[test]
3380 fn test_evidence_inference_explicit_override() {
3381 assert!(check(
3383 r#"
3384 fn main() {
3385 let reported_val: i64~ = 42;
3386 // Explicit ! annotation - this would fail if we checked evidence properly
3387 // but the type system allows it as an override
3388 let x! = 42;
3389 }
3390 "#
3391 )
3392 .is_ok());
3393 }
3394
3395 #[test]
3396 fn test_if_else_evidence_join() {
3397 assert!(check(
3399 r#"
3400 fn main() {
3401 let known_val: i64! = 1;
3402 let reported_val: i64~ = 2;
3403 let cond: bool = true;
3404 // Result should have ~ evidence (join of ! and ~)
3405 let result = if cond { known_val } else { reported_val };
3406 }
3407 "#
3408 )
3409 .is_ok());
3410 }
3411
3412 #[test]
3413 fn test_binary_op_evidence_propagation() {
3414 assert!(check(
3416 r#"
3417 fn main() {
3418 let known: i64! = 1;
3419 let reported: i64~ = 2;
3420 // Result should have ~ evidence (max of ! and ~)
3421 let result = known + reported;
3422 }
3423 "#
3424 )
3425 .is_ok());
3426 }
3427
3428 #[test]
3429 fn test_match_evidence_join() {
3430 assert!(check(
3433 r#"
3434 fn main() {
3435 let x: i64 = 1;
3436 }
3437 "#
3438 )
3439 .is_ok());
3440 }
3441}