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 mutable: bool,
49 inner: Box<Type>,
50 },
51 Ptr {
52 mutable: bool,
53 inner: Box<Type>,
54 },
55
56 Evidential {
58 inner: Box<Type>,
59 evidence: EvidenceLevel,
60 },
61
62 Cycle {
64 modulus: usize,
65 },
66
67 Simd {
69 element: Box<Type>,
70 lanes: u8,
71 },
72
73 Atomic(Box<Type>),
75
76 Var(TypeVar),
78
79 Error,
81
82 Never,
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum IntSize {
89 I8,
90 I16,
91 I32,
92 I64,
93 I128,
94 U8,
95 U16,
96 U32,
97 U64,
98 U128,
99 ISize,
100 USize,
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum FloatSize {
106 F32,
107 F64,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
118pub enum EvidenceLevel {
119 Known, Uncertain, Reported, Paradox, }
128
129impl EvidenceLevel {
130 pub fn join(self, other: Self) -> Self {
132 std::cmp::max(self, other)
133 }
134
135 pub fn meet(self, other: Self) -> Self {
137 std::cmp::min(self, other)
138 }
139
140 pub fn from_ast(e: Evidentiality) -> Self {
142 match e {
143 Evidentiality::Known => EvidenceLevel::Known,
144 Evidentiality::Uncertain => EvidenceLevel::Uncertain,
145 Evidentiality::Reported => EvidenceLevel::Reported,
146 Evidentiality::Paradox => EvidenceLevel::Paradox,
147 }
148 }
149
150 pub fn symbol(&self) -> &'static str {
152 match self {
153 EvidenceLevel::Known => "!",
154 EvidenceLevel::Uncertain => "?",
155 EvidenceLevel::Reported => "~",
156 EvidenceLevel::Paradox => "‽",
157 }
158 }
159
160 pub fn name(&self) -> &'static str {
162 match self {
163 EvidenceLevel::Known => "known",
164 EvidenceLevel::Uncertain => "uncertain",
165 EvidenceLevel::Reported => "reported",
166 EvidenceLevel::Paradox => "paradox",
167 }
168 }
169
170 pub fn satisfies(self, required: Self) -> bool {
178 self <= required
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
186pub struct TypeVar(pub u32);
187
188#[derive(Debug, Clone)]
190pub struct TypeError {
191 pub message: String,
192 pub span: Option<Span>,
193 pub notes: Vec<String>,
194}
195
196impl TypeError {
197 pub fn new(message: impl Into<String>) -> Self {
198 Self {
199 message: message.into(),
200 span: None,
201 notes: Vec::new(),
202 }
203 }
204
205 pub fn with_span(mut self, span: Span) -> Self {
206 self.span = Some(span);
207 self
208 }
209
210 pub fn with_note(mut self, note: impl Into<String>) -> Self {
211 self.notes.push(note.into());
212 self
213 }
214}
215
216impl fmt::Display for TypeError {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 write!(f, "{}", self.message)?;
219 if let Some(span) = self.span {
220 write!(f, " at {}", span)?;
221 }
222 for note in &self.notes {
223 write!(f, "\n note: {}", note)?;
224 }
225 Ok(())
226 }
227}
228
229#[derive(Debug, Clone)]
231pub struct TypeEnv {
232 bindings: HashMap<String, (Type, EvidenceLevel)>,
234 parent: Option<Rc<RefCell<TypeEnv>>>,
236}
237
238impl TypeEnv {
239 pub fn new() -> Self {
240 Self {
241 bindings: HashMap::new(),
242 parent: None,
243 }
244 }
245
246 pub fn with_parent(parent: Rc<RefCell<TypeEnv>>) -> Self {
247 Self {
248 bindings: HashMap::new(),
249 parent: Some(parent),
250 }
251 }
252
253 pub fn define(&mut self, name: String, ty: Type, evidence: EvidenceLevel) {
255 self.bindings.insert(name, (ty, evidence));
256 }
257
258 pub fn lookup(&self, name: &str) -> Option<(Type, EvidenceLevel)> {
260 if let Some(binding) = self.bindings.get(name) {
261 Some(binding.clone())
262 } else if let Some(ref parent) = self.parent {
263 parent.borrow().lookup(name)
264 } else {
265 None
266 }
267 }
268}
269
270impl Default for TypeEnv {
271 fn default() -> Self {
272 Self::new()
273 }
274}
275
276#[derive(Debug, Clone)]
278pub enum TypeDef {
279 Struct {
280 generics: Vec<String>,
281 fields: Vec<(String, Type)>,
282 },
283 Enum {
284 generics: Vec<String>,
285 variants: Vec<(String, Option<Vec<Type>>)>,
286 },
287 Alias {
288 generics: Vec<String>,
289 target: Type,
290 },
291}
292
293pub struct TypeChecker {
295 env: Rc<RefCell<TypeEnv>>,
297 types: HashMap<String, TypeDef>,
299 functions: HashMap<String, Type>,
301 next_var: u32,
303 substitutions: HashMap<TypeVar, Type>,
305 errors: Vec<TypeError>,
307}
308
309impl TypeChecker {
310 pub fn new() -> Self {
311 let mut checker = Self {
312 env: Rc::new(RefCell::new(TypeEnv::new())),
313 types: HashMap::new(),
314 functions: HashMap::new(),
315 next_var: 0,
316 substitutions: HashMap::new(),
317 errors: Vec::new(),
318 };
319
320 checker.register_builtins();
322 checker
323 }
324
325 fn register_builtins(&mut self) {
326 let func = |params: Vec<Type>, ret: Type| Type::Function {
328 params,
329 return_type: Box::new(ret),
330 is_async: false,
331 };
332
333 let any = Type::Var(TypeVar(9999)); self.functions
341 .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
342 self.functions
343 .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
344 self.functions
345 .insert("input".to_string(), func(vec![], Type::Str));
346 self.functions
347 .insert("input_line".to_string(), func(vec![], Type::Str));
348
349 self.functions
353 .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
354 self.functions.insert(
355 "len".to_string(),
356 func(vec![any.clone()], Type::Int(IntSize::USize)),
357 );
358
359 self.functions
363 .insert("str".to_string(), func(vec![any.clone()], Type::Str));
364 self.functions
365 .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
366 self.functions
367 .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
368 self.functions
369 .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
370 self.functions.insert(
371 "split".to_string(),
372 func(
373 vec![Type::Str, Type::Str],
374 Type::Array {
375 element: Box::new(Type::Str),
376 size: None,
377 },
378 ),
379 );
380 self.functions.insert(
381 "join".to_string(),
382 func(
383 vec![
384 Type::Array {
385 element: Box::new(Type::Str),
386 size: None,
387 },
388 Type::Str,
389 ],
390 Type::Str,
391 ),
392 );
393 self.functions.insert(
394 "contains".to_string(),
395 func(vec![Type::Str, Type::Str], Type::Bool),
396 );
397 self.functions.insert(
398 "starts_with".to_string(),
399 func(vec![Type::Str, Type::Str], Type::Bool),
400 );
401 self.functions.insert(
402 "ends_with".to_string(),
403 func(vec![Type::Str, Type::Str], Type::Bool),
404 );
405 self.functions.insert(
406 "replace".to_string(),
407 func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
408 );
409 self.functions.insert(
410 "char_at".to_string(),
411 func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
412 );
413 self.functions.insert(
414 "substring".to_string(),
415 func(
416 vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
417 Type::Str,
418 ),
419 );
420
421 let f64_ty = Type::Float(FloatSize::F64);
425 let i64_ty = Type::Int(IntSize::I64);
426
427 self.functions.insert(
428 "abs".to_string(),
429 func(vec![f64_ty.clone()], f64_ty.clone()),
430 );
431 self.functions.insert(
432 "sqrt".to_string(),
433 func(vec![f64_ty.clone()], f64_ty.clone()),
434 );
435 self.functions.insert(
436 "sin".to_string(),
437 func(vec![f64_ty.clone()], f64_ty.clone()),
438 );
439 self.functions.insert(
440 "cos".to_string(),
441 func(vec![f64_ty.clone()], f64_ty.clone()),
442 );
443 self.functions.insert(
444 "tan".to_string(),
445 func(vec![f64_ty.clone()], f64_ty.clone()),
446 );
447 self.functions.insert(
448 "floor".to_string(),
449 func(vec![f64_ty.clone()], f64_ty.clone()),
450 );
451 self.functions.insert(
452 "ceil".to_string(),
453 func(vec![f64_ty.clone()], f64_ty.clone()),
454 );
455 self.functions.insert(
456 "round".to_string(),
457 func(vec![f64_ty.clone()], f64_ty.clone()),
458 );
459 self.functions.insert(
460 "pow".to_string(),
461 func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
462 );
463 self.functions.insert(
464 "log".to_string(),
465 func(vec![f64_ty.clone()], f64_ty.clone()),
466 );
467 self.functions.insert(
468 "exp".to_string(),
469 func(vec![f64_ty.clone()], f64_ty.clone()),
470 );
471 self.functions.insert(
472 "min".to_string(),
473 func(vec![any.clone(), any.clone()], any.clone()),
474 );
475 self.functions.insert(
476 "max".to_string(),
477 func(vec![any.clone(), any.clone()], any.clone()),
478 );
479
480 self.functions
484 .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
485 self.functions
486 .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
487 self.functions.insert(
488 "push".to_string(),
489 func(vec![any.clone(), any.clone()], Type::Unit),
490 );
491 self.functions
492 .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
493 self.functions
494 .insert("first".to_string(), func(vec![any.clone()], any.clone()));
495 self.functions
496 .insert("last".to_string(), func(vec![any.clone()], any.clone()));
497 self.functions
498 .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
499 self.functions
500 .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
501 self.functions.insert(
502 "range".to_string(),
503 func(
504 vec![i64_ty.clone(), i64_ty.clone()],
505 Type::Array {
506 element: Box::new(i64_ty.clone()),
507 size: None,
508 },
509 ),
510 );
511
512 self.functions
516 .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
517 self.functions.insert(
518 "assert_eq".to_string(),
519 func(vec![any.clone(), any.clone()], Type::Unit),
520 );
521 self.functions.insert(
522 "assert_ne".to_string(),
523 func(vec![any.clone(), any.clone()], Type::Unit),
524 );
525 self.functions.insert(
526 "assert_lt".to_string(),
527 func(vec![any.clone(), any.clone()], Type::Unit),
528 );
529 self.functions.insert(
530 "assert_le".to_string(),
531 func(vec![any.clone(), any.clone()], Type::Unit),
532 );
533 self.functions.insert(
534 "assert_gt".to_string(),
535 func(vec![any.clone(), any.clone()], Type::Unit),
536 );
537 self.functions.insert(
538 "assert_ge".to_string(),
539 func(vec![any.clone(), any.clone()], Type::Unit),
540 );
541 self.functions.insert(
542 "assert_true".to_string(),
543 func(vec![Type::Bool], Type::Unit),
544 );
545 self.functions.insert(
546 "assert_false".to_string(),
547 func(vec![Type::Bool], Type::Unit),
548 );
549 self.functions.insert(
550 "assert_null".to_string(),
551 func(vec![any.clone()], Type::Unit),
552 );
553 self.functions.insert(
554 "assert_not_null".to_string(),
555 func(vec![any.clone()], Type::Unit),
556 );
557 self.functions.insert(
558 "assert_contains".to_string(),
559 func(vec![any.clone(), any.clone()], Type::Unit),
560 );
561 self.functions.insert(
562 "assert_len".to_string(),
563 func(vec![any.clone(), i64_ty.clone()], Type::Unit),
564 );
565
566 self.functions
570 .insert("random".to_string(), func(vec![], f64_ty.clone()));
571 self.functions.insert(
572 "random_int".to_string(),
573 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
574 );
575 self.functions
576 .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
577
578 self.functions
582 .insert("now".to_string(), func(vec![], f64_ty.clone()));
583 self.functions
584 .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
585
586 self.functions
590 .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
591 self.functions
592 .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
593 self.functions
594 .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
595
596 self.functions
600 .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
601 self.functions
602 .insert("todo".to_string(), func(vec![], Type::Never));
603 self.functions
604 .insert("unreachable".to_string(), func(vec![], Type::Never));
605
606 self.functions.insert(
611 "known".to_string(),
612 func(
613 vec![any.clone()],
614 Type::Evidential {
615 inner: Box::new(any.clone()),
616 evidence: EvidenceLevel::Known,
617 },
618 ),
619 );
620 self.functions.insert(
622 "uncertain".to_string(),
623 func(
624 vec![any.clone()],
625 Type::Evidential {
626 inner: Box::new(any.clone()),
627 evidence: EvidenceLevel::Uncertain,
628 },
629 ),
630 );
631 self.functions.insert(
633 "reported".to_string(),
634 func(
635 vec![any.clone()],
636 Type::Evidential {
637 inner: Box::new(any.clone()),
638 evidence: EvidenceLevel::Reported,
639 },
640 ),
641 );
642 self.functions.insert(
644 "evidence_of".to_string(),
645 func(vec![any.clone()], Type::Str),
646 );
647 self.functions.insert(
649 "validate".to_string(),
650 func(
651 vec![any.clone()],
652 Type::Evidential {
653 inner: Box::new(any.clone()),
654 evidence: EvidenceLevel::Uncertain,
655 },
656 ),
657 );
658 self.functions.insert(
660 "verify".to_string(),
661 func(
662 vec![any.clone()],
663 Type::Evidential {
664 inner: Box::new(any.clone()),
665 evidence: EvidenceLevel::Known,
666 },
667 ),
668 );
669
670 self.functions.insert(
675 "freq".to_string(),
676 func(vec![i64_ty.clone()], f64_ty.clone()),
677 );
678 self.functions.insert(
680 "octave".to_string(),
681 func(vec![i64_ty.clone()], i64_ty.clone()),
682 );
683 self.functions.insert(
685 "pitch_class".to_string(),
686 func(vec![i64_ty.clone()], i64_ty.clone()),
687 );
688 self.functions.insert(
690 "mod_cycle".to_string(),
691 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
692 );
693 }
694
695 fn fresh_var(&mut self) -> Type {
697 let var = TypeVar(self.next_var);
698 self.next_var += 1;
699 Type::Var(var)
700 }
701
702 fn freshen(&mut self, ty: &Type) -> Type {
705 let mut mapping = std::collections::HashMap::new();
706 self.freshen_inner(ty, &mut mapping)
707 }
708
709 fn freshen_inner(
710 &mut self,
711 ty: &Type,
712 mapping: &mut std::collections::HashMap<u32, Type>,
713 ) -> Type {
714 match ty {
715 Type::Var(TypeVar(id)) => {
716 if let Some(fresh) = mapping.get(id) {
717 fresh.clone()
718 } else {
719 let fresh = self.fresh_var();
720 mapping.insert(*id, fresh.clone());
721 fresh
722 }
723 }
724 Type::Array { element, size } => Type::Array {
725 element: Box::new(self.freshen_inner(element, mapping)),
726 size: *size,
727 },
728 Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
729 Type::Ref { mutable, inner } => Type::Ref {
730 mutable: *mutable,
731 inner: Box::new(self.freshen_inner(inner, mapping)),
732 },
733 Type::Tuple(elems) => Type::Tuple(
734 elems
735 .iter()
736 .map(|e| self.freshen_inner(e, mapping))
737 .collect(),
738 ),
739 Type::Function {
740 params,
741 return_type,
742 is_async,
743 } => Type::Function {
744 params: params
745 .iter()
746 .map(|p| self.freshen_inner(p, mapping))
747 .collect(),
748 return_type: Box::new(self.freshen_inner(return_type, mapping)),
749 is_async: *is_async,
750 },
751 Type::Evidential { inner, evidence } => Type::Evidential {
752 inner: Box::new(self.freshen_inner(inner, mapping)),
753 evidence: *evidence,
754 },
755 Type::Named { name, generics } => Type::Named {
756 name: name.clone(),
757 generics: generics
758 .iter()
759 .map(|g| self.freshen_inner(g, mapping))
760 .collect(),
761 },
762 _ => ty.clone(),
764 }
765 }
766
767 fn push_scope(&mut self) {
769 let new_env = TypeEnv::with_parent(self.env.clone());
770 self.env = Rc::new(RefCell::new(new_env));
771 }
772
773 fn pop_scope(&mut self) {
775 let parent = self.env.borrow().parent.clone();
776 if let Some(p) = parent {
777 self.env = p;
778 }
779 }
780
781 fn error(&mut self, err: TypeError) {
783 self.errors.push(err);
784 }
785
786 fn check_evidence(
789 &mut self,
790 expected: EvidenceLevel,
791 actual: EvidenceLevel,
792 context: &str,
793 ) -> bool {
794 if actual.satisfies(expected) {
795 true
796 } else {
797 let mut err = TypeError::new(format!(
798 "evidence mismatch {}: expected {} ({}), found {} ({})",
799 context,
800 expected.name(),
801 expected.symbol(),
802 actual.name(),
803 actual.symbol(),
804 ));
805
806 match (expected, actual) {
808 (EvidenceLevel::Known, EvidenceLevel::Reported) => {
809 err = err.with_note(
810 "reported data (~) cannot be used where known data (!) is required",
811 );
812 err = err.with_note(
813 "help: use |validate!{...} to verify and promote evidence level",
814 );
815 }
816 (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
817 err = err.with_note(
818 "uncertain data (?) cannot be used where known data (!) is required",
819 );
820 err = err.with_note(
821 "help: use pattern matching or unwrap to handle the uncertainty",
822 );
823 }
824 (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
825 err = err.with_note(
826 "reported data (~) cannot be used where uncertain data (?) is required",
827 );
828 err = err.with_note("help: use |validate?{...} to verify external data");
829 }
830 _ => {
831 err = err.with_note(format!(
832 "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
833 ));
834 }
835 }
836
837 self.error(err);
838 false
839 }
840 }
841
842 fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
844 match ty {
845 Type::Evidential { evidence, .. } => *evidence,
846 _ => EvidenceLevel::Known,
847 }
848 }
849
850 pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
852 for item in &file.items {
854 self.collect_type_def(&item.node);
855 }
856
857 for item in &file.items {
859 self.collect_fn_sig(&item.node);
860 }
861
862 for item in &file.items {
864 self.check_item(&item.node);
865 }
866
867 if self.errors.is_empty() {
868 Ok(())
869 } else {
870 Err(std::mem::take(&mut self.errors))
871 }
872 }
873
874 fn collect_type_def(&mut self, item: &Item) {
876 match item {
877 Item::Struct(s) => {
878 let generics = s
879 .generics
880 .as_ref()
881 .map(|g| {
882 g.params
883 .iter()
884 .filter_map(|p| {
885 if let GenericParam::Type { name, .. } = p {
886 Some(name.name.clone())
887 } else {
888 None
889 }
890 })
891 .collect()
892 })
893 .unwrap_or_default();
894
895 let fields = match &s.fields {
896 StructFields::Named(fs) => fs
897 .iter()
898 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
899 .collect(),
900 StructFields::Tuple(ts) => ts
901 .iter()
902 .enumerate()
903 .map(|(i, t)| (i.to_string(), self.convert_type(t)))
904 .collect(),
905 StructFields::Unit => vec![],
906 };
907
908 self.types
909 .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
910 }
911 Item::Enum(e) => {
912 let generics = e
913 .generics
914 .as_ref()
915 .map(|g| {
916 g.params
917 .iter()
918 .filter_map(|p| {
919 if let GenericParam::Type { name, .. } = p {
920 Some(name.name.clone())
921 } else {
922 None
923 }
924 })
925 .collect()
926 })
927 .unwrap_or_default();
928
929 let variants = e
930 .variants
931 .iter()
932 .map(|v| {
933 let fields = match &v.fields {
934 StructFields::Tuple(ts) => {
935 Some(ts.iter().map(|t| self.convert_type(t)).collect())
936 }
937 StructFields::Named(fs) => {
938 Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
939 }
940 StructFields::Unit => None,
941 };
942 (v.name.name.clone(), fields)
943 })
944 .collect();
945
946 self.types
947 .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
948 }
949 Item::TypeAlias(t) => {
950 let generics = t
951 .generics
952 .as_ref()
953 .map(|g| {
954 g.params
955 .iter()
956 .filter_map(|p| {
957 if let GenericParam::Type { name, .. } = p {
958 Some(name.name.clone())
959 } else {
960 None
961 }
962 })
963 .collect()
964 })
965 .unwrap_or_default();
966
967 let target = self.convert_type(&t.ty);
968 self.types
969 .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
970 }
971 _ => {}
972 }
973 }
974
975 fn collect_fn_sig(&mut self, item: &Item) {
977 if let Item::Function(f) = item {
978 let params: Vec<Type> = f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
979
980 let return_type = f
981 .return_type
982 .as_ref()
983 .map(|t| self.convert_type(t))
984 .unwrap_or(Type::Unit);
985
986 let fn_type = Type::Function {
987 params,
988 return_type: Box::new(return_type),
989 is_async: f.is_async,
990 };
991
992 self.functions.insert(f.name.name.clone(), fn_type);
993 }
994 }
995
996 fn check_item(&mut self, item: &Item) {
998 match item {
999 Item::Function(f) => self.check_function(f),
1000 Item::Const(c) => {
1001 let declared = self.convert_type(&c.ty);
1002 let inferred = self.infer_expr(&c.value);
1003 if !self.unify(&declared, &inferred) {
1004 self.error(
1005 TypeError::new(format!(
1006 "type mismatch in const '{}': expected {:?}, found {:?}",
1007 c.name.name, declared, inferred
1008 ))
1009 .with_span(c.name.span),
1010 );
1011 }
1012 }
1013 Item::Static(s) => {
1014 let declared = self.convert_type(&s.ty);
1015 let inferred = self.infer_expr(&s.value);
1016 if !self.unify(&declared, &inferred) {
1017 self.error(
1018 TypeError::new(format!(
1019 "type mismatch in static '{}': expected {:?}, found {:?}",
1020 s.name.name, declared, inferred
1021 ))
1022 .with_span(s.name.span),
1023 );
1024 }
1025 }
1026 _ => {}
1027 }
1028 }
1029
1030 fn check_function(&mut self, func: &Function) {
1032 self.push_scope();
1033
1034 for param in &func.params {
1036 let ty = self.convert_type(¶m.ty);
1037 let type_evidence = self.get_evidence(&ty);
1040 let evidence = param
1041 .pattern
1042 .evidentiality()
1043 .map(EvidenceLevel::from_ast)
1044 .unwrap_or(type_evidence);
1045
1046 if let Some(name) = param.pattern.binding_name() {
1047 self.env.borrow_mut().define(name, ty, evidence);
1048 }
1049 }
1050
1051 if let Some(ref body) = func.body {
1053 let body_type = self.check_block(body);
1054
1055 let expected_return = func
1057 .return_type
1058 .as_ref()
1059 .map(|t| self.convert_type(t))
1060 .unwrap_or(Type::Unit);
1061
1062 if !self.unify(&expected_return, &body_type) {
1064 self.error(
1065 TypeError::new(format!(
1066 "return type mismatch in '{}': expected {:?}, found {:?}",
1067 func.name.name, expected_return, body_type
1068 ))
1069 .with_span(func.name.span),
1070 );
1071 }
1072
1073 let has_explicit_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1078 let actual_evidence = self.get_evidence(&body_type);
1079
1080 if has_explicit_evidence {
1081 let expected_evidence = self.get_evidence(&expected_return);
1083 self.check_evidence(
1084 expected_evidence,
1085 actual_evidence,
1086 &format!("in return type of '{}'", func.name.name),
1087 );
1088 } else {
1089 if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1092 self.error(
1093 TypeError::new(format!(
1094 "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1095 func.name.name,
1096 actual_evidence.name(),
1097 actual_evidence.symbol(),
1098 ))
1099 .with_span(func.name.span)
1100 .with_note("help: add explicit evidence annotation to the return type")
1101 .with_note(format!(
1102 "example: fn {}(...) -> {}{} {{ ... }}",
1103 func.name.name,
1104 expected_return,
1105 actual_evidence.symbol()
1106 )),
1107 );
1108 }
1109 }
1111 }
1112
1113 self.pop_scope();
1114 }
1115
1116 fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1118 match ty {
1119 Some(TypeExpr::Evidential { .. }) => true,
1120 Some(TypeExpr::Reference { inner, .. })
1121 | Some(TypeExpr::Pointer { inner, .. })
1122 | Some(TypeExpr::Slice(inner))
1123 | Some(TypeExpr::Array { element: inner, .. }) => {
1124 self.type_has_explicit_evidence(Some(inner.as_ref()))
1125 }
1126 Some(TypeExpr::Tuple(elements)) => elements
1127 .iter()
1128 .any(|e| self.type_has_explicit_evidence(Some(e))),
1129 _ => false,
1130 }
1131 }
1132
1133 fn check_block(&mut self, block: &Block) -> Type {
1135 self.push_scope();
1136
1137 let mut diverges = false;
1138 for stmt in &block.stmts {
1139 let stmt_ty = self.check_stmt(stmt);
1140 if matches!(stmt_ty, Type::Never) {
1141 diverges = true;
1142 }
1143 }
1144
1145 let result = if let Some(ref expr) = block.expr {
1146 self.infer_expr(expr)
1147 } else if diverges {
1148 Type::Never
1149 } else {
1150 Type::Unit
1151 };
1152
1153 self.pop_scope();
1154 result
1155 }
1156
1157 fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1159 match stmt {
1160 Stmt::Let { pattern, ty, init } => {
1161 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1162 let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1163
1164 let final_ty = match (&declared_ty, &init_ty) {
1165 (Some(d), Some(i)) => {
1166 if !self.unify(d, i) {
1167 self.error(TypeError::new(format!(
1168 "type mismatch in let binding: expected {:?}, found {:?}",
1169 d, i
1170 )));
1171 }
1172 d.clone()
1173 }
1174 (Some(d), None) => d.clone(),
1175 (None, Some(i)) => i.clone(),
1176 (None, None) => self.fresh_var(),
1177 };
1178
1179 let evidence = pattern
1185 .evidentiality()
1186 .map(EvidenceLevel::from_ast)
1187 .unwrap_or_else(|| {
1188 init_ty
1190 .as_ref()
1191 .map(|ty| self.get_evidence(ty))
1192 .unwrap_or(EvidenceLevel::Known)
1193 });
1194
1195 if let Some(name) = pattern.binding_name() {
1196 self.env.borrow_mut().define(name, final_ty, evidence);
1197 }
1198 Type::Unit
1199 }
1200 Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1201 Stmt::Item(item) => {
1202 self.check_item(item);
1203 Type::Unit
1204 }
1205 }
1206 }
1207
1208 pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1210 match expr {
1211 Expr::Literal(lit) => self.infer_literal(lit),
1212
1213 Expr::Path(path) => {
1214 if path.segments.len() == 1 {
1215 let name = &path.segments[0].ident.name;
1216 if let Some((ty, _)) = self.env.borrow().lookup(name) {
1217 return ty;
1218 }
1219 if let Some(ty) = self.functions.get(name).cloned() {
1220 return self.freshen(&ty);
1222 }
1223 }
1224 self.error(TypeError::new(format!("undefined: {:?}", path)));
1225 Type::Error
1226 }
1227
1228 Expr::Binary { left, op, right } => {
1229 let lt = self.infer_expr(left);
1230 let rt = self.infer_expr(right);
1231 self.infer_binary_op(op, <, &rt)
1232 }
1233
1234 Expr::Unary { op, expr } => {
1235 let inner = self.infer_expr(expr);
1236 self.infer_unary_op(op, &inner)
1237 }
1238
1239 Expr::Call { func, args } => {
1240 let fn_type = self.infer_expr(func);
1241 let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1242
1243 if let Type::Function {
1244 params,
1245 return_type,
1246 ..
1247 } = fn_type
1248 {
1249 if params.len() != arg_types.len() {
1251 self.error(TypeError::new(format!(
1252 "expected {} arguments, found {}",
1253 params.len(),
1254 arg_types.len()
1255 )));
1256 }
1257
1258 for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1260 if !self.unify(param, arg) {
1262 self.error(TypeError::new(format!(
1263 "argument type mismatch: expected {:?}, found {:?}",
1264 param, arg
1265 )));
1266 }
1267
1268 if !matches!(param, Type::Var(_)) {
1272 let expected_evidence = self.get_evidence(param);
1273 let actual_evidence = self.get_evidence(arg);
1274 self.check_evidence(
1275 expected_evidence,
1276 actual_evidence,
1277 &format!("in argument {}", i + 1),
1278 );
1279 }
1280 }
1281
1282 *return_type
1283 } else {
1284 self.error(TypeError::new("cannot call non-function"));
1285 Type::Error
1286 }
1287 }
1288
1289 Expr::Array(elements) => {
1290 if elements.is_empty() {
1291 Type::Array {
1292 element: Box::new(self.fresh_var()),
1293 size: Some(0),
1294 }
1295 } else {
1296 let elem_ty = self.infer_expr(&elements[0]);
1297 for elem in &elements[1..] {
1298 let t = self.infer_expr(elem);
1299 if !self.unify(&elem_ty, &t) {
1300 self.error(TypeError::new("array elements must have same type"));
1301 }
1302 }
1303 Type::Array {
1304 element: Box::new(elem_ty),
1305 size: Some(elements.len()),
1306 }
1307 }
1308 }
1309
1310 Expr::Tuple(elements) => {
1311 Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1312 }
1313
1314 Expr::Block(block) => self.check_block(block),
1315
1316 Expr::If {
1317 condition,
1318 then_branch,
1319 else_branch,
1320 } => {
1321 let cond_ty = self.infer_expr(condition);
1322 if !self.unify(&Type::Bool, &cond_ty) {
1323 self.error(TypeError::new("if condition must be bool"));
1324 }
1325
1326 let then_ty = self.check_block(then_branch);
1327
1328 if let Some(else_expr) = else_branch {
1329 let else_ty = match else_expr.as_ref() {
1331 Expr::Block(block) => self.check_block(block),
1332 other => self.infer_expr(other),
1333 };
1334 if !self.unify(&then_ty, &else_ty) {
1335 self.error(TypeError::new("if branches must have same type"));
1336 }
1337
1338 let then_ev = self.get_evidence(&then_ty);
1343 let else_ev = self.get_evidence(&else_ty);
1344 let joined_ev = then_ev.join(else_ev);
1345
1346 let (inner_ty, _) = self.strip_evidence(&then_ty);
1347 if joined_ev > EvidenceLevel::Known {
1348 Type::Evidential {
1349 inner: Box::new(inner_ty),
1350 evidence: joined_ev,
1351 }
1352 } else {
1353 inner_ty
1354 }
1355 } else {
1356 Type::Unit
1357 }
1358 }
1359
1360 Expr::Pipe { expr, operations } => {
1361 let mut current = self.infer_expr(expr);
1362
1363 for op in operations {
1364 current = self.infer_pipe_op(op, ¤t);
1365 }
1366
1367 current
1368 }
1369
1370 Expr::Index { expr, index } => {
1371 let coll_ty = self.infer_expr(expr);
1372 let idx_ty = self.infer_expr(index);
1373
1374 match coll_ty {
1375 Type::Array { element, .. } | Type::Slice(element) => {
1376 if !matches!(idx_ty, Type::Int(_)) {
1377 self.error(TypeError::new("index must be integer"));
1378 }
1379 *element
1380 }
1381 _ => {
1382 self.error(TypeError::new("cannot index non-array"));
1383 Type::Error
1384 }
1385 }
1386 }
1387
1388 Expr::Return(val) => {
1389 if let Some(e) = val {
1390 self.infer_expr(e);
1391 }
1392 Type::Never
1393 }
1394
1395 Expr::Evidential {
1397 expr,
1398 evidentiality,
1399 } => {
1400 let inner = self.infer_expr(expr);
1401 Type::Evidential {
1402 inner: Box::new(inner),
1403 evidence: EvidenceLevel::from_ast(*evidentiality),
1404 }
1405 }
1406
1407 Expr::Match { expr, arms } => {
1409 let scrutinee = self.infer_expr(expr);
1410 let scrutinee_ev = self.get_evidence(&scrutinee);
1411
1412 if arms.is_empty() {
1413 return Type::Never; }
1415
1416 let mut arm_types: Vec<Type> = Vec::new();
1418 let mut max_evidence = EvidenceLevel::Known;
1419
1420 for arm in arms {
1421 self.push_scope();
1422
1423 self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
1426
1427 if let Some(ref guard) = arm.guard {
1429 let guard_ty = self.infer_expr(guard);
1430 if !self.unify(&Type::Bool, &guard_ty) {
1431 self.error(TypeError::new("match guard must be bool"));
1432 }
1433 }
1434
1435 let body_ty = self.infer_expr(&arm.body);
1437 let body_ev = self.get_evidence(&body_ty);
1438
1439 max_evidence = max_evidence.join(body_ev);
1441 arm_types.push(body_ty);
1442
1443 self.pop_scope();
1444 }
1445
1446 let first_ty = &arm_types[0];
1448 for (i, ty) in arm_types.iter().enumerate().skip(1) {
1449 if !self.unify(first_ty, ty) {
1450 self.error(TypeError::new(format!(
1451 "match arm {} has incompatible type",
1452 i + 1
1453 )));
1454 }
1455 }
1456
1457 let (inner_ty, _) = self.strip_evidence(first_ty);
1459 if max_evidence > EvidenceLevel::Known {
1460 Type::Evidential {
1461 inner: Box::new(inner_ty),
1462 evidence: max_evidence,
1463 }
1464 } else {
1465 inner_ty
1466 }
1467 }
1468
1469 _ => {
1470 self.fresh_var()
1472 }
1473 }
1474 }
1475
1476 fn infer_literal(&self, lit: &Literal) -> Type {
1478 match lit {
1479 Literal::Int { .. } => Type::Int(IntSize::I64),
1480 Literal::Float { .. } => Type::Float(FloatSize::F64),
1481 Literal::Bool(_) => Type::Bool,
1482 Literal::Char(_) => Type::Char,
1483 Literal::String(_) => Type::Str,
1484 Literal::MultiLineString(_) => Type::Str,
1485 Literal::RawString(_) => Type::Str,
1486 Literal::ByteString(bytes) => Type::Array {
1487 element: Box::new(Type::Int(IntSize::U8)),
1488 size: Some(bytes.len()),
1489 },
1490 Literal::InterpolatedString { .. } => Type::Str,
1491 Literal::SigilStringSql(_) => Type::Str,
1492 Literal::SigilStringRoute(_) => Type::Str,
1493 Literal::Null => Type::Unit, Literal::Empty => Type::Unit,
1495 Literal::Infinity => Type::Float(FloatSize::F64),
1496 Literal::Circle => Type::Float(FloatSize::F64),
1497 }
1498 }
1499
1500 fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
1502 let (left_inner, left_ev) = self.strip_evidence(left);
1504 let (right_inner, right_ev) = self.strip_evidence(right);
1505
1506 let result_ty = match op {
1507 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
1509 if !self.unify(&left_inner, &right_inner) {
1510 self.error(TypeError::new("arithmetic operands must have same type"));
1511 }
1512 left_inner
1513 }
1514
1515 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
1517 if !self.unify(&left_inner, &right_inner) {
1518 self.error(TypeError::new("comparison operands must have same type"));
1519 }
1520 Type::Bool
1521 }
1522
1523 BinOp::And | BinOp::Or => {
1525 if !self.unify(&Type::Bool, &left_inner) {
1526 self.error(TypeError::new("logical operand must be bool"));
1527 }
1528 if !self.unify(&Type::Bool, &right_inner) {
1529 self.error(TypeError::new("logical operand must be bool"));
1530 }
1531 Type::Bool
1532 }
1533
1534 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
1536
1537 BinOp::Concat => {
1539 if !self.unify(&Type::Str, &left_inner) {
1540 self.error(TypeError::new("concat operand must be string"));
1541 }
1542 Type::Str
1543 }
1544 };
1545
1546 let combined_ev = left_ev.join(right_ev);
1548
1549 if combined_ev > EvidenceLevel::Known {
1551 Type::Evidential {
1552 inner: Box::new(result_ty),
1553 evidence: combined_ev,
1554 }
1555 } else {
1556 result_ty
1557 }
1558 }
1559
1560 fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
1562 let (inner_ty, evidence) = self.strip_evidence(inner);
1563
1564 let result = match op {
1565 UnaryOp::Neg => inner_ty,
1566 UnaryOp::Not => {
1567 if !self.unify(&Type::Bool, &inner_ty) {
1568 self.error(TypeError::new("! operand must be bool"));
1569 }
1570 Type::Bool
1571 }
1572 UnaryOp::Ref => Type::Ref {
1573 mutable: false,
1574 inner: Box::new(inner_ty),
1575 },
1576 UnaryOp::RefMut => Type::Ref {
1577 mutable: true,
1578 inner: Box::new(inner_ty),
1579 },
1580 UnaryOp::Deref => {
1581 if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
1582 *inner
1583 } else {
1584 self.error(TypeError::new("cannot dereference non-pointer"));
1585 Type::Error
1586 }
1587 }
1588 };
1589
1590 if evidence > EvidenceLevel::Known {
1592 Type::Evidential {
1593 inner: Box::new(result),
1594 evidence,
1595 }
1596 } else {
1597 result
1598 }
1599 }
1600
1601 fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
1603 let (inner, evidence) = self.strip_evidence(input);
1604
1605 let result = match op {
1606 PipeOp::Transform(_body) => {
1608 if let Type::Array { element, size } = inner {
1609 Type::Array { element, size }
1610 } else if let Type::Slice(element) = inner {
1611 Type::Slice(element)
1612 } else {
1613 self.error(TypeError::new("transform requires array or slice"));
1614 Type::Error
1615 }
1616 }
1617
1618 PipeOp::Filter(_pred) => inner,
1620
1621 PipeOp::Sort(_) => inner,
1623
1624 PipeOp::Reduce(_) => {
1626 if let Type::Array { element, .. } | Type::Slice(element) = inner {
1627 *element
1628 } else {
1629 self.error(TypeError::new("reduce requires array or slice"));
1630 Type::Error
1631 }
1632 }
1633 PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
1634 if let Type::Array { element, .. } | Type::Slice(element) = inner {
1636 match element.as_ref() {
1637 Type::Int(_) | Type::Float(_) => *element,
1638 _ => {
1639 self.error(TypeError::new("numeric reduction requires numeric array"));
1640 Type::Error
1641 }
1642 }
1643 } else {
1644 self.error(TypeError::new("reduction requires array or slice"));
1645 Type::Error
1646 }
1647 }
1648 PipeOp::ReduceConcat => {
1649 if let Type::Array { element, .. } | Type::Slice(element) = inner {
1651 match element.as_ref() {
1652 Type::Str => Type::Str,
1653 Type::Array { .. } => *element,
1654 _ => {
1655 self.error(TypeError::new(
1656 "concat reduction requires array of strings or arrays",
1657 ));
1658 Type::Error
1659 }
1660 }
1661 } else {
1662 self.error(TypeError::new("concat reduction requires array or slice"));
1663 Type::Error
1664 }
1665 }
1666 PipeOp::ReduceAll | PipeOp::ReduceAny => {
1667 if let Type::Array { element, .. } | Type::Slice(element) = inner {
1669 match element.as_ref() {
1670 Type::Bool => Type::Bool,
1671 _ => {
1672 self.error(TypeError::new(
1673 "boolean reduction requires array of booleans",
1674 ));
1675 Type::Error
1676 }
1677 }
1678 } else {
1679 self.error(TypeError::new("boolean reduction requires array or slice"));
1680 Type::Error
1681 }
1682 }
1683
1684 PipeOp::Match(arms) => {
1686 if arms.is_empty() {
1688 self.error(TypeError::new("match expression has no arms"));
1689 Type::Error
1690 } else {
1691 let result_type = self.infer_expr(&arms[0].body);
1693 for arm in arms.iter().skip(1) {
1694 let arm_type = self.infer_expr(&arm.body);
1695 self.unify(&result_type, &arm_type);
1696 }
1697 result_type
1698 }
1699 }
1700
1701 PipeOp::TryMap(_) => {
1703 self.fresh_var()
1707 }
1708
1709 PipeOp::Method { name, args: _ } => {
1711 if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
1713 let fresh_ty = self.freshen(&fn_ty);
1715 if let Type::Function { return_type, .. } = fresh_ty {
1716 *return_type
1717 } else {
1718 Type::Error
1719 }
1720 } else {
1721 self.fresh_var()
1723 }
1724 }
1725
1726 PipeOp::Named { prefix, body: _ } => {
1728 if let Some(first) = prefix.first() {
1730 match first.name.as_str() {
1731 "sum" | "product" => {
1732 if let Type::Array { element, .. } | Type::Slice(element) = inner {
1733 *element
1734 } else {
1735 self.error(TypeError::new("sum/product requires array"));
1736 Type::Error
1737 }
1738 }
1739 _ => self.fresh_var(),
1740 }
1741 } else {
1742 self.fresh_var()
1743 }
1744 }
1745
1746 PipeOp::Await => {
1748 inner
1750 }
1751
1752 PipeOp::First
1754 | PipeOp::Last
1755 | PipeOp::Middle
1756 | PipeOp::Choice
1757 | PipeOp::Nth(_)
1758 | PipeOp::Next => {
1759 if let Type::Array { element, .. } | Type::Slice(element) = inner {
1760 *element
1761 } else if let Type::Tuple(elements) = inner {
1762 if let Some(first) = elements.first() {
1764 first.clone()
1765 } else {
1766 Type::Unit
1767 }
1768 } else {
1769 self.error(TypeError::new(
1770 "access morpheme requires array, slice, or tuple",
1771 ));
1772 Type::Error
1773 }
1774 }
1775
1776 PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
1779
1780 PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
1783
1784 PipeOp::Send(_) => {
1791 Type::Evidential {
1793 inner: Box::new(self.fresh_var()),
1794 evidence: EvidenceLevel::Reported,
1795 }
1796 }
1797
1798 PipeOp::Recv => {
1800 Type::Evidential {
1802 inner: Box::new(self.fresh_var()),
1803 evidence: EvidenceLevel::Reported,
1804 }
1805 }
1806
1807 PipeOp::Stream(_) => {
1809 self.fresh_var()
1811 }
1812
1813 PipeOp::Connect(_) => {
1815 self.fresh_var()
1817 }
1818
1819 PipeOp::Close => Type::Unit,
1821
1822 PipeOp::Header { .. } => inner,
1824
1825 PipeOp::Body(_) => inner,
1827
1828 PipeOp::Timeout(_) => inner,
1830
1831 PipeOp::Retry { .. } => inner,
1833
1834 PipeOp::Validate {
1840 predicate: _,
1841 target_evidence,
1842 } => {
1843 let target_ev = EvidenceLevel::from_ast(*target_evidence);
1847
1848 if evidence < target_ev {
1850 self.error(
1851 TypeError::new(format!(
1852 "cannot demote evidence from {} ({}) to {} ({}) using validate",
1853 evidence.name(),
1854 evidence.symbol(),
1855 target_ev.name(),
1856 target_ev.symbol()
1857 ))
1858 .with_note("validate! can only promote evidence to a more certain level"),
1859 );
1860 }
1861
1862 return Type::Evidential {
1864 inner: Box::new(inner.clone()),
1865 evidence: target_ev,
1866 };
1867 }
1868
1869 PipeOp::Assume {
1871 reason: _,
1872 target_evidence,
1873 } => {
1874 let target_ev = EvidenceLevel::from_ast(*target_evidence);
1875
1876 if evidence < target_ev {
1880 self.error(
1881 TypeError::new(format!(
1882 "assume! cannot demote evidence from {} ({}) to {} ({})",
1883 evidence.name(),
1884 evidence.symbol(),
1885 target_ev.name(),
1886 target_ev.symbol()
1887 ))
1888 .with_note("assume! is for promoting evidence, not demoting"),
1889 );
1890 }
1891
1892 return Type::Evidential {
1894 inner: Box::new(inner.clone()),
1895 evidence: target_ev,
1896 };
1897 }
1898
1899 PipeOp::AssertEvidence(expected_ast) => {
1901 let expected = EvidenceLevel::from_ast(*expected_ast);
1902
1903 if !evidence.satisfies(expected) {
1904 self.error(
1905 TypeError::new(format!(
1906 "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
1907 expected.name(), expected.symbol(),
1908 evidence.name(), evidence.symbol()
1909 ))
1910 .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
1911 );
1912 }
1913
1914 return input.clone();
1916 }
1917
1918 PipeOp::Also(_) => {
1925 return input.clone();
1928 }
1929
1930 PipeOp::Apply(_) => {
1933 return input.clone();
1936 }
1937
1938 PipeOp::TakeIf(_) => {
1941 return Type::Named {
1944 name: "Option".to_string(),
1945 generics: vec![input.clone()],
1946 };
1947 }
1948
1949 PipeOp::TakeUnless(_) => {
1952 return Type::Named {
1955 name: "Option".to_string(),
1956 generics: vec![input.clone()],
1957 };
1958 }
1959
1960 PipeOp::Let(func) => {
1963 let _ = self.infer_expr(func);
1965 self.fresh_var() }
1967
1968 PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
1970 PipeOp::Compose(f) => {
1971 let _ = self.infer_expr(f);
1972 self.fresh_var()
1973 }
1974 PipeOp::Zip(other) => {
1975 let _ = self.infer_expr(other);
1976 self.fresh_var() }
1978 PipeOp::Scan(f) => {
1979 let _ = self.infer_expr(f);
1980 self.fresh_var() }
1982 PipeOp::Diff => self.fresh_var(), PipeOp::Gradient(var) => {
1984 let _ = self.infer_expr(var);
1985 self.fresh_var() }
1987 PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
1988 inner.clone() }
1990 PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
1991 let _ = self.infer_expr(n);
1992 self.fresh_var() }
1994 PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
1995 PipeOp::Enumerate => self.fresh_var(), };
1997
1998 if evidence > EvidenceLevel::Known {
2000 Type::Evidential {
2001 inner: Box::new(result),
2002 evidence,
2003 }
2004 } else {
2005 result
2006 }
2007 }
2008
2009 fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
2011 match ty {
2012 Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
2013 _ => (ty.clone(), EvidenceLevel::Known),
2014 }
2015 }
2016
2017 fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
2020 let (inner_ty, ty_ev) = self.strip_evidence(ty);
2021 let final_ev = evidence.join(ty_ev);
2023
2024 match pattern {
2025 Pattern::Ident {
2026 name,
2027 evidentiality,
2028 ..
2029 } => {
2030 let ev = evidentiality
2032 .map(EvidenceLevel::from_ast)
2033 .unwrap_or(final_ev);
2034 self.env
2035 .borrow_mut()
2036 .define(name.name.clone(), inner_ty, ev);
2037 }
2038 Pattern::Tuple(patterns) => {
2039 if let Type::Tuple(types) = &inner_ty {
2040 for (pat, ty) in patterns.iter().zip(types.iter()) {
2041 self.bind_pattern(pat, ty, final_ev);
2042 }
2043 }
2044 }
2045 Pattern::Struct { fields, .. } => {
2046 for field in fields {
2049 let fresh = self.fresh_var();
2050 if let Some(ref pat) = field.pattern {
2051 self.bind_pattern(pat, &fresh, final_ev);
2052 } else {
2053 self.env
2054 .borrow_mut()
2055 .define(field.name.name.clone(), fresh, final_ev);
2056 }
2057 }
2058 }
2059 Pattern::TupleStruct { fields, .. } => {
2060 for pat in fields {
2061 let fresh = self.fresh_var();
2062 self.bind_pattern(pat, &fresh, final_ev);
2063 }
2064 }
2065 Pattern::Slice(patterns) => {
2066 let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
2067 {
2068 *element.clone()
2069 } else {
2070 self.fresh_var()
2071 };
2072 for pat in patterns {
2073 self.bind_pattern(pat, &elem_ty, final_ev);
2074 }
2075 }
2076 Pattern::Or(patterns) => {
2077 if let Some(first) = patterns.first() {
2080 self.bind_pattern(first, ty, evidence);
2081 }
2082 }
2083 Pattern::Wildcard | Pattern::Rest | Pattern::Literal(_) | Pattern::Range { .. } => {
2084 }
2086 }
2087 }
2088
2089 fn unify(&mut self, a: &Type, b: &Type) -> bool {
2091 match (a, b) {
2092 (Type::Unit, Type::Unit) |
2094 (Type::Bool, Type::Bool) |
2095 (Type::Char, Type::Char) |
2096 (Type::Str, Type::Str) |
2097 (Type::Never, Type::Never) |
2098 (Type::Error, _) |
2099 (_, Type::Error) |
2100 (Type::Never, _) |
2102 (_, Type::Never) => true,
2103
2104 (Type::Int(a), Type::Int(b)) => a == b,
2105 (Type::Float(a), Type::Float(b)) => a == b,
2106
2107 (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
2109 (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
2110 }
2111
2112 (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
2114
2115 (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
2117 a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
2118 }
2119
2120 (Type::Ref { mutable: ma, inner: a }, Type::Ref { mutable: mb, inner: b }) => {
2122 ma == mb && self.unify(a, b)
2123 }
2124
2125 (Type::Function { params: pa, return_type: ra, is_async: aa },
2127 Type::Function { params: pb, return_type: rb, is_async: ab }) => {
2128 aa == ab && pa.len() == pb.len() &&
2129 pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
2130 self.unify(ra, rb)
2131 }
2132
2133 (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
2135 na == nb && ga.len() == gb.len() &&
2136 ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y))
2137 }
2138
2139 (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
2141 self.unify(a, b)
2142 }
2143 (Type::Evidential { inner: a, .. }, b) => {
2144 self.unify(a, b)
2145 }
2146 (a, Type::Evidential { inner: b, .. }) => {
2147 self.unify(a, b)
2148 }
2149
2150 (Type::Var(v), t) => {
2152 if let Some(resolved) = self.substitutions.get(v) {
2153 let resolved = resolved.clone();
2154 self.unify(&resolved, t)
2155 } else {
2156 self.substitutions.insert(*v, t.clone());
2157 true
2158 }
2159 }
2160 (t, Type::Var(v)) => {
2161 if let Some(resolved) = self.substitutions.get(v) {
2162 let resolved = resolved.clone();
2163 self.unify(t, &resolved)
2164 } else {
2165 self.substitutions.insert(*v, t.clone());
2166 true
2167 }
2168 }
2169
2170 (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
2172
2173 _ => false,
2174 }
2175 }
2176
2177 fn convert_type(&self, ty: &TypeExpr) -> Type {
2179 match ty {
2180 TypeExpr::Path(path) => {
2181 if path.segments.len() == 1 {
2182 let name = &path.segments[0].ident.name;
2183 match name.as_str() {
2184 "bool" => return Type::Bool,
2185 "char" => return Type::Char,
2186 "str" | "String" => return Type::Str,
2187 "i8" => return Type::Int(IntSize::I8),
2188 "i16" => return Type::Int(IntSize::I16),
2189 "i32" => return Type::Int(IntSize::I32),
2190 "i64" => return Type::Int(IntSize::I64),
2191 "i128" => return Type::Int(IntSize::I128),
2192 "isize" => return Type::Int(IntSize::ISize),
2193 "u8" => return Type::Int(IntSize::U8),
2194 "u16" => return Type::Int(IntSize::U16),
2195 "u32" => return Type::Int(IntSize::U32),
2196 "u64" => return Type::Int(IntSize::U64),
2197 "u128" => return Type::Int(IntSize::U128),
2198 "usize" => return Type::Int(IntSize::USize),
2199 "f32" => return Type::Float(FloatSize::F32),
2200 "f64" => return Type::Float(FloatSize::F64),
2201 _ => {}
2202 }
2203 }
2204
2205 let name = path
2206 .segments
2207 .iter()
2208 .map(|s| s.ident.name.clone())
2209 .collect::<Vec<_>>()
2210 .join("::");
2211
2212 let generics = path
2213 .segments
2214 .last()
2215 .and_then(|s| s.generics.as_ref())
2216 .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
2217 .unwrap_or_default();
2218
2219 Type::Named { name, generics }
2220 }
2221
2222 TypeExpr::Reference { mutable, inner } => Type::Ref {
2223 mutable: *mutable,
2224 inner: Box::new(self.convert_type(inner)),
2225 },
2226
2227 TypeExpr::Pointer { mutable, inner } => Type::Ptr {
2228 mutable: *mutable,
2229 inner: Box::new(self.convert_type(inner)),
2230 },
2231
2232 TypeExpr::Array { element, size: _ } => {
2233 Type::Array {
2234 element: Box::new(self.convert_type(element)),
2235 size: None, }
2237 }
2238
2239 TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
2240
2241 TypeExpr::Tuple(elements) => {
2242 Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
2243 }
2244
2245 TypeExpr::Function {
2246 params,
2247 return_type,
2248 } => Type::Function {
2249 params: params.iter().map(|t| self.convert_type(t)).collect(),
2250 return_type: Box::new(
2251 return_type
2252 .as_ref()
2253 .map(|t| self.convert_type(t))
2254 .unwrap_or(Type::Unit),
2255 ),
2256 is_async: false,
2257 },
2258
2259 TypeExpr::Evidential {
2260 inner,
2261 evidentiality,
2262 error_type,
2263 } => {
2264 let _ = error_type; Type::Evidential {
2268 inner: Box::new(self.convert_type(inner)),
2269 evidence: EvidenceLevel::from_ast(*evidentiality),
2270 }
2271 }
2272
2273 TypeExpr::Cycle { modulus: _ } => {
2274 Type::Cycle { modulus: 12 } }
2276
2277 TypeExpr::Simd { element, lanes } => {
2278 let elem_ty = self.convert_type(element);
2279 Type::Simd {
2280 element: Box::new(elem_ty),
2281 lanes: *lanes,
2282 }
2283 }
2284
2285 TypeExpr::Atomic(inner) => {
2286 let inner_ty = self.convert_type(inner);
2287 Type::Atomic(Box::new(inner_ty))
2288 }
2289
2290 TypeExpr::Never => Type::Never,
2291 TypeExpr::Infer => Type::Var(TypeVar(0)), }
2293 }
2294
2295 pub fn errors(&self) -> &[TypeError] {
2297 &self.errors
2298 }
2299}
2300
2301impl Default for TypeChecker {
2302 fn default() -> Self {
2303 Self::new()
2304 }
2305}
2306
2307trait PatternExt {
2309 fn evidentiality(&self) -> Option<Evidentiality>;
2310 fn binding_name(&self) -> Option<String>;
2311}
2312
2313impl PatternExt for Pattern {
2314 fn evidentiality(&self) -> Option<Evidentiality> {
2315 match self {
2316 Pattern::Ident { evidentiality, .. } => *evidentiality,
2317 _ => None,
2318 }
2319 }
2320
2321 fn binding_name(&self) -> Option<String> {
2322 match self {
2323 Pattern::Ident { name, .. } => Some(name.name.clone()),
2324 _ => None,
2325 }
2326 }
2327}
2328
2329impl fmt::Display for Type {
2330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2331 match self {
2332 Type::Unit => write!(f, "()"),
2333 Type::Bool => write!(f, "bool"),
2334 Type::Int(size) => write!(f, "{:?}", size),
2335 Type::Float(size) => write!(f, "{:?}", size),
2336 Type::Char => write!(f, "char"),
2337 Type::Str => write!(f, "str"),
2338 Type::Array { element, size } => {
2339 if let Some(n) = size {
2340 write!(f, "[{}; {}]", element, n)
2341 } else {
2342 write!(f, "[{}]", element)
2343 }
2344 }
2345 Type::Slice(inner) => write!(f, "[{}]", inner),
2346 Type::Tuple(elems) => {
2347 write!(f, "(")?;
2348 for (i, e) in elems.iter().enumerate() {
2349 if i > 0 {
2350 write!(f, ", ")?;
2351 }
2352 write!(f, "{}", e)?;
2353 }
2354 write!(f, ")")
2355 }
2356 Type::Named { name, generics } => {
2357 write!(f, "{}", name)?;
2358 if !generics.is_empty() {
2359 write!(f, "<")?;
2360 for (i, g) in generics.iter().enumerate() {
2361 if i > 0 {
2362 write!(f, ", ")?;
2363 }
2364 write!(f, "{}", g)?;
2365 }
2366 write!(f, ">")?;
2367 }
2368 Ok(())
2369 }
2370 Type::Function {
2371 params,
2372 return_type,
2373 is_async,
2374 } => {
2375 if *is_async {
2376 write!(f, "async ")?;
2377 }
2378 write!(f, "fn(")?;
2379 for (i, p) in params.iter().enumerate() {
2380 if i > 0 {
2381 write!(f, ", ")?;
2382 }
2383 write!(f, "{}", p)?;
2384 }
2385 write!(f, ") -> {}", return_type)
2386 }
2387 Type::Ref { mutable, inner } => {
2388 write!(f, "&{}{}", if *mutable { "mut " } else { "" }, inner)
2389 }
2390 Type::Ptr { mutable, inner } => {
2391 write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
2392 }
2393 Type::Evidential { inner, evidence } => {
2394 write!(f, "{}{}", inner, evidence.symbol())
2395 }
2396 Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
2397 Type::Var(v) => write!(f, "?{}", v.0),
2398 Type::Error => write!(f, "<error>"),
2399 Type::Never => write!(f, "!"),
2400 Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
2401 Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
2402 }
2403 }
2404}
2405
2406#[cfg(test)]
2407mod tests {
2408 use super::*;
2409 use crate::Parser;
2410
2411 fn check(source: &str) -> Result<(), Vec<TypeError>> {
2412 let mut parser = Parser::new(source);
2413 let file = parser.parse_file().expect("parse failed");
2414 let mut checker = TypeChecker::new();
2415 checker.check_file(&file)
2416 }
2417
2418 #[test]
2419 fn test_basic_types() {
2420 assert!(check("fn main() { let x: i64 = 42; }").is_ok());
2421 assert!(check("fn main() { let x: bool = true; }").is_ok());
2422 assert!(check("fn main() { let x: f64 = 3.14; }").is_ok());
2423 }
2424
2425 #[test]
2426 fn test_type_mismatch() {
2427 assert!(check("fn main() { let x: bool = 42; }").is_err());
2428 }
2429
2430 #[test]
2431 fn test_evidence_propagation() {
2432 assert!(check(
2434 r#"
2435 fn main() {
2436 let known: i64! = 42;
2437 let uncertain: i64? = 10;
2438 let result = known + uncertain;
2439 }
2440 "#
2441 )
2442 .is_ok());
2443 }
2444
2445 #[test]
2446 fn test_function_return() {
2447 let result = check(
2448 r#"
2449 fn add(a: i64, b: i64) -> i64 {
2450 return a + b;
2451 }
2452 fn main() {
2453 let x = add(1, 2);
2454 }
2455 "#,
2456 );
2457 if let Err(errors) = &result {
2458 for e in errors {
2459 eprintln!("Error: {}", e);
2460 }
2461 }
2462 assert!(result.is_ok());
2463 }
2464
2465 #[test]
2466 fn test_array_types() {
2467 assert!(check(
2468 r#"
2469 fn main() {
2470 let arr = [1, 2, 3];
2471 let x = arr[0];
2472 }
2473 "#
2474 )
2475 .is_ok());
2476 }
2477
2478 #[test]
2483 fn test_evidence_inference_from_initializer() {
2484 assert!(check(
2486 r#"
2487 fn main() {
2488 let reported_val: i64~ = 42;
2489 // x should inherit ~ evidence from reported_val
2490 let x = reported_val + 1;
2491 }
2492 "#
2493 )
2494 .is_ok());
2495 }
2496
2497 #[test]
2498 fn test_evidence_inference_explicit_override() {
2499 assert!(check(
2501 r#"
2502 fn main() {
2503 let reported_val: i64~ = 42;
2504 // Explicit ! annotation - this would fail if we checked evidence properly
2505 // but the type system allows it as an override
2506 let x! = 42;
2507 }
2508 "#
2509 )
2510 .is_ok());
2511 }
2512
2513 #[test]
2514 fn test_if_else_evidence_join() {
2515 assert!(check(
2517 r#"
2518 fn main() {
2519 let known_val: i64! = 1;
2520 let reported_val: i64~ = 2;
2521 let cond: bool = true;
2522 // Result should have ~ evidence (join of ! and ~)
2523 let result = if cond { known_val } else { reported_val };
2524 }
2525 "#
2526 )
2527 .is_ok());
2528 }
2529
2530 #[test]
2531 fn test_binary_op_evidence_propagation() {
2532 assert!(check(
2534 r#"
2535 fn main() {
2536 let known: i64! = 1;
2537 let reported: i64~ = 2;
2538 // Result should have ~ evidence (max of ! and ~)
2539 let result = known + reported;
2540 }
2541 "#
2542 )
2543 .is_ok());
2544 }
2545
2546 #[test]
2547 fn test_match_evidence_join() {
2548 assert!(check(
2551 r#"
2552 fn main() {
2553 let x: i64 = 1;
2554 }
2555 "#
2556 )
2557 .is_ok());
2558 }
2559}