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 Linear(Box<Type>),
79
80 Var(TypeVar),
82
83 Error,
85
86 Never,
88
89 Lifetime(String),
91
92 TraitObject(Vec<Type>),
94
95 Hrtb {
97 lifetimes: Vec<String>,
98 bound: Box<Type>,
99 },
100 InlineStruct {
102 fields: Vec<(String, Type)>,
103 },
104 ImplTrait(Vec<Type>),
106 InlineEnum(Vec<String>),
108 AssocTypeBinding {
110 name: String,
111 ty: Box<Type>,
112 },
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum IntSize {
118 I8,
119 I16,
120 I32,
121 I64,
122 I128,
123 U8,
124 U16,
125 U32,
126 U64,
127 U128,
128 ISize,
129 USize,
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub enum FloatSize {
135 F32,
136 F64,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
147pub enum EvidenceLevel {
148 Known, Uncertain, Reported, Paradox, }
157
158impl EvidenceLevel {
159 pub fn join(self, other: Self) -> Self {
161 std::cmp::max(self, other)
162 }
163
164 pub fn meet(self, other: Self) -> Self {
166 std::cmp::min(self, other)
167 }
168
169 pub fn from_ast(e: Evidentiality) -> Self {
171 match e {
172 Evidentiality::Known => EvidenceLevel::Known,
173 Evidentiality::Uncertain | Evidentiality::Predicted => EvidenceLevel::Uncertain,
174 Evidentiality::Reported => EvidenceLevel::Reported,
175 Evidentiality::Paradox => EvidenceLevel::Paradox,
176 }
177 }
178
179 pub fn symbol(&self) -> &'static str {
181 match self {
182 EvidenceLevel::Known => "!",
183 EvidenceLevel::Uncertain => "?",
184 EvidenceLevel::Reported => "~",
185 EvidenceLevel::Paradox => "‽",
186 }
187 }
188
189 pub fn name(&self) -> &'static str {
191 match self {
192 EvidenceLevel::Known => "known",
193 EvidenceLevel::Uncertain => "uncertain",
194 EvidenceLevel::Reported => "reported",
195 EvidenceLevel::Paradox => "paradox",
196 }
197 }
198
199 pub fn satisfies(self, required: Self) -> bool {
207 self <= required
210 }
211}
212
213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
215pub struct TypeVar(pub u32);
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219pub enum TypeErrorCode {
220 TypeMismatch,
222 UndefinedName,
224 BorrowError,
226 EvidentialityError,
228 NonBoolCondition,
230 HeterogeneousArray,
232 InvalidIndex,
234 InvalidOperand,
236 MissingMatchArm,
238 InvalidReduction,
240 Generic,
242}
243
244impl TypeErrorCode {
245 pub fn code(&self) -> &'static str {
246 match self {
247 TypeErrorCode::TypeMismatch => "E0308",
248 TypeErrorCode::UndefinedName => "E0425",
249 TypeErrorCode::BorrowError => "E0382",
250 TypeErrorCode::EvidentialityError => "E0600",
251 TypeErrorCode::NonBoolCondition => "E0601",
252 TypeErrorCode::HeterogeneousArray => "E0602",
253 TypeErrorCode::InvalidIndex => "E0603",
254 TypeErrorCode::InvalidOperand => "E0604",
255 TypeErrorCode::MissingMatchArm => "E0605",
256 TypeErrorCode::InvalidReduction => "E0606",
257 TypeErrorCode::Generic => "E0300",
258 }
259 }
260}
261
262#[derive(Debug, Clone)]
264pub struct TypeError {
265 pub message: String,
266 pub span: Option<Span>,
267 pub notes: Vec<String>,
268 pub code: TypeErrorCode,
269}
270
271impl TypeError {
272 pub fn new(message: impl Into<String>) -> Self {
273 Self {
274 message: message.into(),
275 span: None,
276 notes: Vec::new(),
277 code: TypeErrorCode::Generic,
278 }
279 }
280
281 pub fn with_span(mut self, span: Span) -> Self {
282 self.span = Some(span);
283 self
284 }
285
286 pub fn with_note(mut self, note: impl Into<String>) -> Self {
287 self.notes.push(note.into());
288 self
289 }
290
291 pub fn with_code(mut self, code: TypeErrorCode) -> Self {
292 self.code = code;
293 self
294 }
295
296 pub fn type_mismatch(expected: &str, found: &str) -> Self {
300 Self::new(format!("type mismatch: expected `{}`, found `{}`", expected, found))
301 .with_code(TypeErrorCode::TypeMismatch)
302 }
303
304 pub fn undefined(kind: &str, name: &str) -> Self {
306 Self::new(format!("{} `{}` not found in this scope", kind, name))
307 .with_code(TypeErrorCode::UndefinedName)
308 }
309
310 pub fn non_bool_condition(context: &str, found: &str) -> Self {
312 Self::new(format!("{} condition must be `bool`, found `{}`", context, found))
313 .with_code(TypeErrorCode::NonBoolCondition)
314 }
315
316 pub fn heterogeneous_array(first_type: &str, found_type: &str) -> Self {
318 Self::new(format!(
319 "array elements must have the same type: expected `{}`, found `{}`",
320 first_type, found_type
321 ))
322 .with_code(TypeErrorCode::HeterogeneousArray)
323 }
324
325 pub fn invalid_index(found: &str) -> Self {
327 Self::new(format!("array index must be an integer, found `{}`", found))
328 .with_code(TypeErrorCode::InvalidIndex)
329 }
330
331 pub fn invalid_operand(op: &str, found: &str) -> Self {
333 Self::new(format!("invalid operand type `{}` for `{}`", found, op))
334 .with_code(TypeErrorCode::InvalidOperand)
335 }
336
337 pub fn missing_match_arm() -> Self {
339 Self::new("match expression has no arms")
340 .with_code(TypeErrorCode::MissingMatchArm)
341 }
342
343 pub fn invalid_reduction(op: &str, found: &str) -> Self {
345 Self::new(format!("`{}` requires array or slice, found `{}`", op, found))
346 .with_code(TypeErrorCode::InvalidReduction)
347 }
348}
349
350impl fmt::Display for TypeError {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 write!(f, "{}", self.message)?;
353 if let Some(span) = self.span {
354 write!(f, " at {}", span)?;
355 }
356 for note in &self.notes {
357 write!(f, "\n note: {}", note)?;
358 }
359 Ok(())
360 }
361}
362
363#[derive(Debug, Clone)]
365pub struct TypeEnv {
366 bindings: HashMap<String, (Type, EvidenceLevel)>,
368 parent: Option<Rc<RefCell<TypeEnv>>>,
370}
371
372impl TypeEnv {
373 pub fn new() -> Self {
374 Self {
375 bindings: HashMap::new(),
376 parent: None,
377 }
378 }
379
380 pub fn with_parent(parent: Rc<RefCell<TypeEnv>>) -> Self {
381 Self {
382 bindings: HashMap::new(),
383 parent: Some(parent),
384 }
385 }
386
387 pub fn define(&mut self, name: String, ty: Type, evidence: EvidenceLevel) {
389 self.bindings.insert(name, (ty, evidence));
390 }
391
392 pub fn lookup(&self, name: &str) -> Option<(Type, EvidenceLevel)> {
394 if let Some(binding) = self.bindings.get(name) {
395 Some(binding.clone())
396 } else if let Some(ref parent) = self.parent {
397 parent.borrow().lookup(name)
398 } else {
399 None
400 }
401 }
402}
403
404impl Default for TypeEnv {
405 fn default() -> Self {
406 Self::new()
407 }
408}
409
410#[derive(Debug, Clone)]
412pub enum TypeDef {
413 Struct {
414 generics: Vec<String>,
415 fields: Vec<(String, Type)>,
416 },
417 Enum {
418 generics: Vec<String>,
419 variants: Vec<(String, Option<Vec<Type>>)>,
420 },
421 Alias {
422 generics: Vec<String>,
423 target: Type,
424 },
425}
426
427pub struct TypeChecker {
429 env: Rc<RefCell<TypeEnv>>,
431 types: HashMap<String, TypeDef>,
433 functions: HashMap<String, Type>,
435 impl_methods: HashMap<String, HashMap<String, Type>>,
437 current_self_type: Option<String>,
439 current_generics: HashMap<String, Type>,
441 expected_return_type: Option<Type>,
443 next_var: u32,
445 substitutions: HashMap<TypeVar, Type>,
447 errors: Vec<TypeError>,
449}
450
451impl TypeChecker {
452 pub fn new() -> Self {
453 let mut checker = Self {
454 env: Rc::new(RefCell::new(TypeEnv::new())),
455 types: HashMap::new(),
456 functions: HashMap::new(),
457 impl_methods: HashMap::new(),
458 current_self_type: None,
459 current_generics: HashMap::new(),
460 expected_return_type: None,
461 next_var: 0,
462 substitutions: HashMap::new(),
463 errors: Vec::new(),
464 };
465
466 checker.register_builtins();
468 checker
469 }
470
471 fn register_builtins(&mut self) {
472 let func = |params: Vec<Type>, ret: Type| Type::Function {
474 params,
475 return_type: Box::new(ret),
476 is_async: false,
477 };
478
479 let any = Type::Var(TypeVar(9999)); self.functions
487 .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
488 self.functions
489 .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
490 self.functions
491 .insert("input".to_string(), func(vec![], Type::Str));
492 self.functions
493 .insert("input_line".to_string(), func(vec![], Type::Str));
494
495 self.functions
499 .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
500 self.functions.insert(
501 "len".to_string(),
502 func(vec![any.clone()], Type::Int(IntSize::USize)),
503 );
504
505 self.functions
509 .insert("str".to_string(), func(vec![any.clone()], Type::Str));
510 self.functions
511 .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
512 self.functions
513 .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
514 self.functions
515 .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
516 self.functions.insert(
517 "split".to_string(),
518 func(
519 vec![Type::Str, Type::Str],
520 Type::Array {
521 element: Box::new(Type::Str),
522 size: None,
523 },
524 ),
525 );
526 self.functions.insert(
527 "join".to_string(),
528 func(
529 vec![
530 Type::Array {
531 element: Box::new(Type::Str),
532 size: None,
533 },
534 Type::Str,
535 ],
536 Type::Str,
537 ),
538 );
539 self.functions.insert(
540 "contains".to_string(),
541 func(vec![Type::Str, Type::Str], Type::Bool),
542 );
543 self.functions.insert(
544 "starts_with".to_string(),
545 func(vec![Type::Str, Type::Str], Type::Bool),
546 );
547 self.functions.insert(
548 "ends_with".to_string(),
549 func(vec![Type::Str, Type::Str], Type::Bool),
550 );
551 self.functions.insert(
552 "replace".to_string(),
553 func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
554 );
555 self.functions.insert(
556 "char_at".to_string(),
557 func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
558 );
559 self.functions.insert(
560 "substring".to_string(),
561 func(
562 vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
563 Type::Str,
564 ),
565 );
566
567 let f64_ty = Type::Float(FloatSize::F64);
571 let i64_ty = Type::Int(IntSize::I64);
572
573 self.functions.insert(
574 "abs".to_string(),
575 func(vec![f64_ty.clone()], f64_ty.clone()),
576 );
577 self.functions.insert(
578 "sqrt".to_string(),
579 func(vec![f64_ty.clone()], f64_ty.clone()),
580 );
581 self.functions.insert(
582 "sin".to_string(),
583 func(vec![f64_ty.clone()], f64_ty.clone()),
584 );
585 self.functions.insert(
586 "cos".to_string(),
587 func(vec![f64_ty.clone()], f64_ty.clone()),
588 );
589 self.functions.insert(
590 "tan".to_string(),
591 func(vec![f64_ty.clone()], f64_ty.clone()),
592 );
593 self.functions.insert(
594 "floor".to_string(),
595 func(vec![f64_ty.clone()], f64_ty.clone()),
596 );
597 self.functions.insert(
598 "ceil".to_string(),
599 func(vec![f64_ty.clone()], f64_ty.clone()),
600 );
601 self.functions.insert(
602 "round".to_string(),
603 func(vec![f64_ty.clone()], f64_ty.clone()),
604 );
605 self.functions.insert(
606 "pow".to_string(),
607 func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
608 );
609 self.functions.insert(
610 "log".to_string(),
611 func(vec![f64_ty.clone()], f64_ty.clone()),
612 );
613 self.functions.insert(
614 "exp".to_string(),
615 func(vec![f64_ty.clone()], f64_ty.clone()),
616 );
617 self.functions.insert(
618 "min".to_string(),
619 func(vec![any.clone(), any.clone()], any.clone()),
620 );
621 self.functions.insert(
622 "max".to_string(),
623 func(vec![any.clone(), any.clone()], any.clone()),
624 );
625
626 self.functions
630 .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
631 self.functions
632 .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
633 self.functions.insert(
634 "push".to_string(),
635 func(vec![any.clone(), any.clone()], Type::Unit),
636 );
637 self.functions
638 .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
639 self.functions
640 .insert("first".to_string(), func(vec![any.clone()], any.clone()));
641 self.functions
642 .insert("last".to_string(), func(vec![any.clone()], any.clone()));
643 self.functions
644 .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
645 self.functions
646 .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
647 self.functions.insert(
648 "range".to_string(),
649 func(
650 vec![i64_ty.clone(), i64_ty.clone()],
651 Type::Array {
652 element: Box::new(i64_ty.clone()),
653 size: None,
654 },
655 ),
656 );
657
658 self.functions
662 .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
663 self.functions.insert(
664 "assert_eq".to_string(),
665 func(vec![any.clone(), any.clone()], Type::Unit),
666 );
667 self.functions.insert(
668 "assert_ne".to_string(),
669 func(vec![any.clone(), any.clone()], Type::Unit),
670 );
671 self.functions.insert(
672 "assert_lt".to_string(),
673 func(vec![any.clone(), any.clone()], Type::Unit),
674 );
675 self.functions.insert(
676 "assert_le".to_string(),
677 func(vec![any.clone(), any.clone()], Type::Unit),
678 );
679 self.functions.insert(
680 "assert_gt".to_string(),
681 func(vec![any.clone(), any.clone()], Type::Unit),
682 );
683 self.functions.insert(
684 "assert_ge".to_string(),
685 func(vec![any.clone(), any.clone()], Type::Unit),
686 );
687 self.functions.insert(
688 "assert_true".to_string(),
689 func(vec![Type::Bool], Type::Unit),
690 );
691 self.functions.insert(
692 "assert_false".to_string(),
693 func(vec![Type::Bool], Type::Unit),
694 );
695 self.functions.insert(
696 "assert_null".to_string(),
697 func(vec![any.clone()], Type::Unit),
698 );
699 self.functions.insert(
700 "assert_not_null".to_string(),
701 func(vec![any.clone()], Type::Unit),
702 );
703 self.functions.insert(
704 "assert_contains".to_string(),
705 func(vec![any.clone(), any.clone()], Type::Unit),
706 );
707 self.functions.insert(
708 "assert_len".to_string(),
709 func(vec![any.clone(), i64_ty.clone()], Type::Unit),
710 );
711
712 self.functions
716 .insert("random".to_string(), func(vec![], f64_ty.clone()));
717 self.functions.insert(
718 "random_int".to_string(),
719 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
720 );
721 self.functions
722 .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
723
724 self.functions
728 .insert("now".to_string(), func(vec![], f64_ty.clone()));
729 self.functions
730 .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
731
732 self.functions
736 .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
737 self.functions
738 .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
739 self.functions
740 .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
741
742 self.functions
746 .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
747 self.functions
748 .insert("todo".to_string(), func(vec![], Type::Never));
749 self.functions
750 .insert("unreachable".to_string(), func(vec![], Type::Never));
751
752 self.functions.insert(
757 "known".to_string(),
758 func(
759 vec![any.clone()],
760 Type::Evidential {
761 inner: Box::new(any.clone()),
762 evidence: EvidenceLevel::Known,
763 },
764 ),
765 );
766 self.functions.insert(
768 "uncertain".to_string(),
769 func(
770 vec![any.clone()],
771 Type::Evidential {
772 inner: Box::new(any.clone()),
773 evidence: EvidenceLevel::Uncertain,
774 },
775 ),
776 );
777 self.functions.insert(
779 "reported".to_string(),
780 func(
781 vec![any.clone()],
782 Type::Evidential {
783 inner: Box::new(any.clone()),
784 evidence: EvidenceLevel::Reported,
785 },
786 ),
787 );
788 self.functions.insert(
790 "evidence_of".to_string(),
791 func(vec![any.clone()], Type::Str),
792 );
793 self.functions.insert(
795 "validate".to_string(),
796 func(
797 vec![any.clone()],
798 Type::Evidential {
799 inner: Box::new(any.clone()),
800 evidence: EvidenceLevel::Uncertain,
801 },
802 ),
803 );
804 self.functions.insert(
806 "verify".to_string(),
807 func(
808 vec![any.clone()],
809 Type::Evidential {
810 inner: Box::new(any.clone()),
811 evidence: EvidenceLevel::Known,
812 },
813 ),
814 );
815
816 self.functions.insert(
821 "freq".to_string(),
822 func(vec![i64_ty.clone()], f64_ty.clone()),
823 );
824 self.functions.insert(
826 "octave".to_string(),
827 func(vec![i64_ty.clone()], i64_ty.clone()),
828 );
829 self.functions.insert(
831 "pitch_class".to_string(),
832 func(vec![i64_ty.clone()], i64_ty.clone()),
833 );
834 self.functions.insert(
836 "mod_cycle".to_string(),
837 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
838 );
839 }
840
841 fn fresh_var(&mut self) -> Type {
843 let var = TypeVar(self.next_var);
844 self.next_var += 1;
845 Type::Var(var)
846 }
847
848 fn type_contains_var(&self, ty: &Type) -> bool {
850 match ty {
851 Type::Var(v) => !self.substitutions.contains_key(v),
852 Type::Array { element, .. } => self.type_contains_var(element.as_ref()),
853 Type::Slice(inner) => self.type_contains_var(inner.as_ref()),
854 Type::Tuple(elems) => elems.iter().any(|e| self.type_contains_var(e)),
855 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => {
856 self.type_contains_var(inner.as_ref())
857 }
858 Type::Function {
859 params,
860 return_type,
861 ..
862 } => {
863 params.iter().any(|p| self.type_contains_var(p))
864 || self.type_contains_var(return_type.as_ref())
865 }
866 Type::Named { generics, .. } => generics.iter().any(|g| self.type_contains_var(g)),
867 Type::Evidential { inner, .. } => self.type_contains_var(inner.as_ref()),
868 Type::Atomic(inner) => self.type_contains_var(inner.as_ref()),
869 Type::Simd { element, .. } => self.type_contains_var(element.as_ref()),
870 _ => false,
871 }
872 }
873
874 fn occurs_in(&self, v: &TypeVar, t: &Type) -> bool {
877 match t {
878 Type::Var(w) => {
879 if v == w {
880 return true;
881 }
882 if let Some(resolved) = self.substitutions.get(w) {
883 self.occurs_in(v, resolved)
884 } else {
885 false
886 }
887 }
888 Type::Array { element, .. } => self.occurs_in(v, element),
889 Type::Slice(inner) => self.occurs_in(v, inner),
890 Type::Tuple(elems) => elems.iter().any(|e| self.occurs_in(v, e)),
891 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.occurs_in(v, inner),
892 Type::Function {
893 params,
894 return_type,
895 ..
896 } => params.iter().any(|p| self.occurs_in(v, p)) || self.occurs_in(v, return_type),
897 Type::Named { generics, .. } => generics.iter().any(|g| self.occurs_in(v, g)),
898 Type::Evidential { inner, .. } => self.occurs_in(v, inner),
899 Type::Atomic(inner) => self.occurs_in(v, inner),
900 Type::Simd { element, .. } => self.occurs_in(v, element),
901 _ => false,
902 }
903 }
904
905 fn freshen(&mut self, ty: &Type) -> Type {
908 let mut mapping = std::collections::HashMap::new();
909 self.freshen_inner(ty, &mut mapping)
910 }
911
912 fn freshen_inner(
913 &mut self,
914 ty: &Type,
915 mapping: &mut std::collections::HashMap<u32, Type>,
916 ) -> Type {
917 match ty {
918 Type::Var(TypeVar(id)) => {
919 if let Some(fresh) = mapping.get(id) {
920 fresh.clone()
921 } else {
922 let fresh = self.fresh_var();
923 mapping.insert(*id, fresh.clone());
924 fresh
925 }
926 }
927 Type::Array { element, size } => Type::Array {
928 element: Box::new(self.freshen_inner(element, mapping)),
929 size: *size,
930 },
931 Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
932 Type::Ref {
933 lifetime,
934 mutable,
935 inner,
936 } => Type::Ref {
937 lifetime: lifetime.clone(),
938 mutable: *mutable,
939 inner: Box::new(self.freshen_inner(inner, mapping)),
940 },
941 Type::Tuple(elems) => Type::Tuple(
942 elems
943 .iter()
944 .map(|e| self.freshen_inner(e, mapping))
945 .collect(),
946 ),
947 Type::Function {
948 params,
949 return_type,
950 is_async,
951 } => Type::Function {
952 params: params
953 .iter()
954 .map(|p| self.freshen_inner(p, mapping))
955 .collect(),
956 return_type: Box::new(self.freshen_inner(return_type, mapping)),
957 is_async: *is_async,
958 },
959 Type::Evidential { inner, evidence } => Type::Evidential {
960 inner: Box::new(self.freshen_inner(inner, mapping)),
961 evidence: *evidence,
962 },
963 Type::Named { name, generics } => Type::Named {
964 name: name.clone(),
965 generics: generics
966 .iter()
967 .map(|g| self.freshen_inner(g, mapping))
968 .collect(),
969 },
970 _ => ty.clone(),
972 }
973 }
974
975 fn push_scope(&mut self) {
977 let new_env = TypeEnv::with_parent(self.env.clone());
978 self.env = Rc::new(RefCell::new(new_env));
979 }
980
981 fn pop_scope(&mut self) {
983 let parent = self.env.borrow().parent.clone();
984 if let Some(p) = parent {
985 self.env = p;
986 }
987 }
988
989 fn error(&mut self, err: TypeError) {
991 self.errors.push(err);
992 }
993
994 fn check_evidence(
997 &mut self,
998 expected: EvidenceLevel,
999 actual: EvidenceLevel,
1000 context: &str,
1001 ) -> bool {
1002 if actual.satisfies(expected) {
1003 true
1004 } else {
1005 let mut err = TypeError::new(format!(
1006 "evidence mismatch {}: expected {} ({}), found {} ({})",
1007 context,
1008 expected.name(),
1009 expected.symbol(),
1010 actual.name(),
1011 actual.symbol(),
1012 ));
1013
1014 match (expected, actual) {
1016 (EvidenceLevel::Known, EvidenceLevel::Reported) => {
1017 err = err.with_note(
1018 "reported data (~) cannot be used where known data (!) is required",
1019 );
1020 err = err.with_note(
1021 "help: use |validate!{...} to verify and promote evidence level",
1022 );
1023 }
1024 (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
1025 err = err.with_note(
1026 "uncertain data (?) cannot be used where known data (!) is required",
1027 );
1028 err = err.with_note(
1029 "help: use pattern matching or unwrap to handle the uncertainty",
1030 );
1031 }
1032 (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
1033 err = err.with_note(
1034 "reported data (~) cannot be used where uncertain data (?) is required",
1035 );
1036 err = err.with_note("help: use |validate?{...} to verify external data");
1037 }
1038 _ => {
1039 err = err.with_note(format!(
1040 "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
1041 ));
1042 }
1043 }
1044
1045 self.error(err);
1046 false
1047 }
1048 }
1049
1050 fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
1052 match ty {
1053 Type::Evidential { evidence, .. } => *evidence,
1054 _ => EvidenceLevel::Known,
1055 }
1056 }
1057
1058 pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
1060 for item in &file.items {
1062 self.collect_type_def(&item.node);
1063 }
1064
1065 for item in &file.items {
1067 self.collect_fn_sig(&item.node);
1068 }
1069
1070 for item in &file.items {
1072 self.check_item(&item.node);
1073 }
1074
1075 if self.errors.is_empty() {
1076 Ok(())
1077 } else {
1078 Err(std::mem::take(&mut self.errors))
1079 }
1080 }
1081
1082 fn collect_type_def(&mut self, item: &Item) {
1084 match item {
1085 Item::Struct(s) => {
1086 let generics = s
1087 .generics
1088 .as_ref()
1089 .map(|g| {
1090 g.params
1091 .iter()
1092 .filter_map(|p| {
1093 if let GenericParam::Type { name, .. } = p {
1094 Some(name.name.clone())
1095 } else {
1096 None
1097 }
1098 })
1099 .collect()
1100 })
1101 .unwrap_or_default();
1102
1103 let fields = match &s.fields {
1104 StructFields::Named(fs) => fs
1105 .iter()
1106 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
1107 .collect(),
1108 StructFields::Tuple(ts) => ts
1109 .iter()
1110 .enumerate()
1111 .map(|(i, t)| (i.to_string(), self.convert_type(t)))
1112 .collect(),
1113 StructFields::Unit => vec![],
1114 };
1115
1116 if self.types.contains_key(&s.name.name) {
1118 self.error(TypeError::new(format!(
1119 "duplicate type definition: '{}'",
1120 s.name.name
1121 )));
1122 }
1123 self.types
1124 .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
1125 }
1126 Item::Enum(e) => {
1127 let generics = e
1128 .generics
1129 .as_ref()
1130 .map(|g| {
1131 g.params
1132 .iter()
1133 .filter_map(|p| {
1134 if let GenericParam::Type { name, .. } = p {
1135 Some(name.name.clone())
1136 } else {
1137 None
1138 }
1139 })
1140 .collect()
1141 })
1142 .unwrap_or_default();
1143
1144 let variants = e
1145 .variants
1146 .iter()
1147 .map(|v| {
1148 let fields = match &v.fields {
1149 StructFields::Tuple(ts) => {
1150 Some(ts.iter().map(|t| self.convert_type(t)).collect())
1151 }
1152 StructFields::Named(fs) => {
1153 Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
1154 }
1155 StructFields::Unit => None,
1156 };
1157 (v.name.name.clone(), fields)
1158 })
1159 .collect();
1160
1161 self.types
1162 .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
1163 }
1164 Item::TypeAlias(t) => {
1165 let generics = t
1166 .generics
1167 .as_ref()
1168 .map(|g| {
1169 g.params
1170 .iter()
1171 .filter_map(|p| {
1172 if let GenericParam::Type { name, .. } = p {
1173 Some(name.name.clone())
1174 } else {
1175 None
1176 }
1177 })
1178 .collect()
1179 })
1180 .unwrap_or_default();
1181
1182 let target = self.convert_type(&t.ty);
1183 self.types
1184 .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
1185 }
1186 _ => {}
1187 }
1188 }
1189
1190 fn collect_fn_sig(&mut self, item: &Item) {
1192 match item {
1193 Item::Function(f) => {
1194 let params: Vec<Type> = f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1195
1196 let return_type = f
1197 .return_type
1198 .as_ref()
1199 .map(|t| self.convert_type(t))
1200 .unwrap_or(Type::Unit);
1201
1202 let fn_type = Type::Function {
1203 params,
1204 return_type: Box::new(return_type),
1205 is_async: f.is_async,
1206 };
1207
1208 if self.functions.contains_key(&f.name.name) {
1210 self.error(TypeError::new(format!(
1211 "duplicate function definition: '{}'",
1212 f.name.name
1213 )));
1214 }
1215 self.functions.insert(f.name.name.clone(), fn_type);
1216 }
1217 Item::Impl(impl_block) => {
1218 let type_name = self.type_path_to_name(&impl_block.self_ty);
1220
1221 self.current_self_type = Some(type_name.clone());
1223
1224 if let Some(ref generics) = impl_block.generics {
1226 for param in &generics.params {
1227 if let crate::ast::GenericParam::Type { name, .. } = param {
1228 let type_var = self.fresh_var();
1229 self.current_generics.insert(name.name.clone(), type_var);
1230 }
1231 }
1232 }
1233
1234 for impl_item in &impl_block.items {
1236 if let crate::ast::ImplItem::Function(f) = impl_item {
1237 let params: Vec<Type> =
1238 f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1239
1240 let return_type = f
1241 .return_type
1242 .as_ref()
1243 .map(|t| self.convert_type(t))
1244 .unwrap_or(Type::Unit);
1245
1246 let fn_type = Type::Function {
1247 params,
1248 return_type: Box::new(return_type),
1249 is_async: f.is_async,
1250 };
1251
1252 self.impl_methods
1254 .entry(type_name.clone())
1255 .or_insert_with(HashMap::new)
1256 .insert(f.name.name.clone(), fn_type);
1257 }
1258 }
1259
1260 self.current_self_type = None;
1262 self.current_generics.clear();
1263 }
1264 _ => {}
1265 }
1266 }
1267
1268 fn type_path_to_name(&self, ty: &crate::ast::TypeExpr) -> String {
1270 match ty {
1271 crate::ast::TypeExpr::Path(path) => path
1272 .segments
1273 .iter()
1274 .map(|s| s.ident.name.clone())
1275 .collect::<Vec<_>>()
1276 .join("::"),
1277 _ => "Unknown".to_string(),
1278 }
1279 }
1280
1281 fn check_item(&mut self, item: &Item) {
1283 match item {
1284 Item::Function(f) => self.check_function(f),
1285 Item::Const(c) => {
1286 let declared = self.convert_type(&c.ty);
1287 let inferred = self.infer_expr(&c.value);
1288 if !self.unify(&declared, &inferred) {
1289 self.error(
1290 TypeError::new(format!(
1291 "type mismatch in const '{}': expected {:?}, found {:?}",
1292 c.name.name, declared, inferred
1293 ))
1294 .with_span(c.name.span),
1295 );
1296 }
1297 }
1298 Item::Static(s) => {
1299 let declared = self.convert_type(&s.ty);
1300 let inferred = self.infer_expr(&s.value);
1301 if !self.unify(&declared, &inferred) {
1302 self.error(
1303 TypeError::new(format!(
1304 "type mismatch in static '{}': expected {:?}, found {:?}",
1305 s.name.name, declared, inferred
1306 ))
1307 .with_span(s.name.span),
1308 );
1309 }
1310 }
1311 Item::Impl(impl_block) => {
1312 let type_name = self.type_path_to_name(&impl_block.self_ty);
1314 self.current_self_type = Some(type_name);
1315
1316 if let Some(ref generics) = impl_block.generics {
1318 for param in &generics.params {
1319 if let crate::ast::GenericParam::Type { name, .. } = param {
1320 let type_var = self.fresh_var();
1321 self.current_generics.insert(name.name.clone(), type_var);
1322 }
1323 }
1324 }
1325
1326 for impl_item in &impl_block.items {
1328 if let crate::ast::ImplItem::Function(f) = impl_item {
1329 self.check_function(f);
1330 }
1331 }
1332
1333 self.current_self_type = None;
1335 self.current_generics.clear();
1336 }
1337 _ => {}
1338 }
1339 }
1340
1341 fn check_function(&mut self, func: &Function) {
1343 self.push_scope();
1344
1345 for param in &func.params {
1347 let ty = self.convert_type(¶m.ty);
1348 let type_evidence = self.get_evidence(&ty);
1351 let evidence = param
1352 .pattern
1353 .evidentiality()
1354 .map(EvidenceLevel::from_ast)
1355 .unwrap_or(type_evidence);
1356
1357 if let Some(name) = param.pattern.binding_name() {
1358 self.env.borrow_mut().define(name, ty, evidence);
1359 }
1360 }
1361
1362 let expected_return = func
1364 .return_type
1365 .as_ref()
1366 .map(|t| self.convert_type(t))
1367 .unwrap_or(Type::Unit);
1368 let old_return_type = self.expected_return_type.clone();
1369 self.expected_return_type = Some(expected_return.clone());
1370
1371 if let Some(ref body) = func.body {
1373 let body_type = self.check_block(body);
1374
1375 self.expected_return_type = old_return_type;
1377
1378 let expected_return = func
1380 .return_type
1381 .as_ref()
1382 .map(|t| self.convert_type(t))
1383 .unwrap_or(Type::Unit);
1384
1385 let _ = self.unify(&expected_return, &body_type);
1389
1390 let type_has_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1396 let name_evidence = func
1398 .name
1399 .evidentiality
1400 .as_ref()
1401 .map(|e| EvidenceLevel::from_ast(*e));
1402 let has_explicit_evidence = type_has_evidence || name_evidence.is_some();
1403 let actual_evidence = self.get_evidence(&body_type);
1404
1405 if has_explicit_evidence {
1406 if name_evidence.is_none() {
1410 let expected_evidence = self.get_evidence(&expected_return);
1411 self.check_evidence(
1412 expected_evidence,
1413 actual_evidence,
1414 &format!("in return type of '{}'", func.name.name),
1415 );
1416 }
1417 } else {
1419 if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1422 self.error(
1423 TypeError::new(format!(
1424 "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1425 func.name.name,
1426 actual_evidence.name(),
1427 actual_evidence.symbol(),
1428 ))
1429 .with_span(func.name.span)
1430 .with_note("help: add explicit evidence annotation to the return type")
1431 .with_note(format!(
1432 "example: fn {}(...) -> {}{} {{ ... }}",
1433 func.name.name,
1434 expected_return,
1435 actual_evidence.symbol()
1436 )),
1437 );
1438 }
1439 }
1441 }
1442
1443 self.pop_scope();
1444 }
1445
1446 fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1448 match ty {
1449 Some(TypeExpr::Evidential { .. }) => true,
1450 Some(TypeExpr::Reference { inner, .. })
1451 | Some(TypeExpr::Pointer { inner, .. })
1452 | Some(TypeExpr::Slice(inner))
1453 | Some(TypeExpr::Array { element: inner, .. }) => {
1454 self.type_has_explicit_evidence(Some(inner.as_ref()))
1455 }
1456 Some(TypeExpr::Tuple(elements)) => elements
1457 .iter()
1458 .any(|e| self.type_has_explicit_evidence(Some(e))),
1459 _ => false,
1460 }
1461 }
1462
1463 fn check_block(&mut self, block: &Block) -> Type {
1465 self.push_scope();
1466
1467 let mut diverges = false;
1468 for stmt in &block.stmts {
1469 let stmt_ty = self.check_stmt(stmt);
1470 if matches!(stmt_ty, Type::Never) {
1471 diverges = true;
1472 }
1473 }
1474
1475 let result = if let Some(ref expr) = block.expr {
1476 self.infer_expr(expr)
1477 } else if diverges {
1478 Type::Never
1479 } else {
1480 Type::Unit
1481 };
1482
1483 self.pop_scope();
1484 result
1485 }
1486
1487 fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1489 match stmt {
1490 Stmt::Let { pattern, ty, init } => {
1491 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1492 let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1493
1494 let final_ty = match (&declared_ty, &init_ty) {
1495 (Some(d), Some(i)) => {
1496 if !self.unify(d, i) {
1497 let binding_name = pattern
1499 .binding_name()
1500 .unwrap_or_else(|| "<pattern>".to_string());
1501 let mut err = TypeError::new(format!(
1502 "type mismatch in let binding '{}': expected {:?}, found {:?}",
1503 binding_name, d, i
1504 ));
1505 if let Some(span) = pattern.binding_span() {
1506 err = err.with_span(span);
1507 }
1508 self.error(err);
1509 }
1510 d.clone()
1511 }
1512 (Some(d), None) => d.clone(),
1513 (None, Some(i)) => i.clone(),
1514 (None, None) => self.fresh_var(),
1515 };
1516
1517 let evidence = pattern
1523 .evidentiality()
1524 .map(EvidenceLevel::from_ast)
1525 .unwrap_or_else(|| {
1526 init_ty
1528 .as_ref()
1529 .map(|ty| self.get_evidence(ty))
1530 .unwrap_or(EvidenceLevel::Known)
1531 });
1532
1533 if let Some(name) = pattern.binding_name() {
1534 self.env.borrow_mut().define(name, final_ty, evidence);
1535 }
1536 Type::Unit
1537 }
1538 Stmt::LetElse {
1539 pattern,
1540 ty,
1541 init,
1542 else_branch,
1543 } => {
1544 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1546 let init_ty = self.infer_expr(init);
1547 let evidence = pattern
1549 .evidentiality()
1550 .map(EvidenceLevel::from_ast)
1551 .unwrap_or_else(|| self.get_evidence(&init_ty));
1552 let final_ty = declared_ty.unwrap_or(init_ty);
1553 self.infer_expr(else_branch);
1555 if let Some(name) = pattern.binding_name() {
1556 self.env.borrow_mut().define(name, final_ty, evidence);
1557 }
1558 Type::Unit
1559 }
1560 Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1561 Stmt::Item(item) => {
1562 self.check_item(item);
1563 Type::Unit
1564 }
1565 }
1566 }
1567
1568 pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1570 match expr {
1571 Expr::Literal(lit) => self.infer_literal(lit),
1572
1573 Expr::Path(path) => {
1574 if path.segments.len() == 1 {
1575 let name = &path.segments[0].ident.name;
1576 if let Some((ty, _)) = self.env.borrow().lookup(name) {
1577 return ty;
1578 }
1579 if let Some(ty) = self.functions.get(name).cloned() {
1580 return self.freshen(&ty);
1582 }
1583 } else if path.segments.len() == 2 {
1584 let type_name = &path.segments[0].ident.name;
1586 let method_name = &path.segments[1].ident.name;
1587
1588 if let Some(methods) = self.impl_methods.get(type_name) {
1590 if let Some(ty) = methods.get(method_name) {
1591 let ty_cloned = ty.clone();
1592 return self.freshen(&ty_cloned);
1593 }
1594 }
1595
1596 if let Some(TypeDef::Enum { variants, .. }) = self.types.get(type_name) {
1598 for (variant_name, _variant_fields) in variants {
1599 if variant_name == method_name {
1600 return Type::Named {
1602 name: type_name.clone(),
1603 generics: vec![],
1604 };
1605 }
1606 }
1607 }
1608 }
1609 self.fresh_var()
1613 }
1614
1615 Expr::Binary { left, op, right } => {
1616 let lt = self.infer_expr(left);
1617 let rt = self.infer_expr(right);
1618 self.infer_binary_op(op, <, &rt)
1619 }
1620
1621 Expr::Unary { op, expr } => {
1622 let inner = self.infer_expr(expr);
1623 self.infer_unary_op(op, &inner)
1624 }
1625
1626 Expr::Call { func, args } => {
1627 let fn_type = self.infer_expr(func);
1628 let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1629
1630 if let Type::Function {
1631 params,
1632 return_type,
1633 ..
1634 } = fn_type
1635 {
1636 if params.len() != arg_types.len() {
1638 self.error(TypeError::new(format!(
1639 "expected {} arguments, found {}",
1640 params.len(),
1641 arg_types.len()
1642 )));
1643 }
1644
1645 for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1647 if !self.unify(param, arg) {
1649 let is_coercible = Self::is_coercible(param, arg);
1651 if !matches!(param, Type::Var(_))
1653 && !matches!(arg, Type::Var(_))
1654 && !is_coercible
1655 {
1656 self.error(TypeError::new(format!(
1657 "type mismatch in argument {}: expected {}, found {}",
1658 i + 1,
1659 param,
1660 arg
1661 )));
1662 }
1663 }
1664
1665 if !matches!(param, Type::Var(_)) {
1669 let expected_evidence = self.get_evidence(param);
1670 let actual_evidence = self.get_evidence(arg);
1671 self.check_evidence(
1672 expected_evidence,
1673 actual_evidence,
1674 &format!("in argument {}", i + 1),
1675 );
1676 }
1677 }
1678
1679 *return_type
1680 } else if let Type::Var(_) = &fn_type {
1681 let result_ty = self.fresh_var();
1684 let inferred_fn = Type::Function {
1685 params: arg_types,
1686 return_type: Box::new(result_ty.clone()),
1687 is_async: false,
1688 };
1689 self.unify(&fn_type, &inferred_fn);
1690 result_ty
1691 } else {
1692 self.fresh_var()
1694 }
1695 }
1696
1697 Expr::Array(elements) => {
1698 if elements.is_empty() {
1699 Type::Array {
1700 element: Box::new(self.fresh_var()),
1701 size: Some(0),
1702 }
1703 } else {
1704 let elem_ty = self.infer_expr(&elements[0]);
1705 for elem in &elements[1..] {
1706 let t = self.infer_expr(elem);
1707 if !self.unify(&elem_ty, &t) {
1708 self.error(TypeError::heterogeneous_array(&format!("{}", elem_ty), &format!("{}", t)));
1709 }
1710 }
1711 Type::Array {
1712 element: Box::new(elem_ty),
1713 size: Some(elements.len()),
1714 }
1715 }
1716 }
1717
1718 Expr::Tuple(elements) => {
1719 Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1720 }
1721
1722 Expr::Block(block) => self.check_block(block),
1723
1724 Expr::If {
1725 condition,
1726 then_branch,
1727 else_branch,
1728 } => {
1729 let cond_ty = self.infer_expr(condition);
1730 if !self.unify(&Type::Bool, &cond_ty) {
1731 self.error(TypeError::non_bool_condition("if", &format!("{}", cond_ty)));
1732 }
1733
1734 let then_ty = self.check_block(then_branch);
1735
1736 if let Some(else_expr) = else_branch {
1737 let else_ty = match else_expr.as_ref() {
1739 Expr::Block(block) => self.check_block(block),
1740 other => self.infer_expr(other),
1741 };
1742 let _ = self.unify(&then_ty, &else_ty);
1745
1746 let then_ev = self.get_evidence(&then_ty);
1751 let else_ev = self.get_evidence(&else_ty);
1752 let joined_ev = then_ev.join(else_ev);
1753
1754 let (inner_ty, _) = self.strip_evidence(&then_ty);
1755 if joined_ev > EvidenceLevel::Known {
1756 Type::Evidential {
1757 inner: Box::new(inner_ty),
1758 evidence: joined_ev,
1759 }
1760 } else {
1761 inner_ty
1762 }
1763 } else {
1764 Type::Unit
1765 }
1766 }
1767
1768 Expr::While {
1769 condition, body, ..
1770 } => {
1771 let cond_ty = self.infer_expr(condition);
1772 if !self.unify(&Type::Bool, &cond_ty) {
1773 self.error(TypeError::non_bool_condition("while", &format!("{}", cond_ty)));
1774 }
1775 self.check_block(body);
1776 Type::Unit
1777 }
1778
1779 Expr::Loop { body, .. } => {
1780 self.check_block(body);
1781 Type::Unit
1782 }
1783
1784 Expr::For {
1785 pattern: _,
1786 iter,
1787 body,
1788 ..
1789 } => {
1790 let _ = self.infer_expr(iter);
1792 self.check_block(body);
1793 Type::Unit
1794 }
1795
1796 Expr::Pipe { expr, operations } => {
1797 let mut current = self.infer_expr(expr);
1798
1799 for op in operations {
1800 current = self.infer_pipe_op(op, ¤t);
1801 }
1802
1803 current
1804 }
1805
1806 Expr::Index { expr, index } => {
1807 let coll_ty = self.infer_expr(expr);
1808 let idx_ty = self.infer_expr(index);
1809
1810 match coll_ty {
1811 Type::Array { element, .. } | Type::Slice(element) => {
1812 if !matches!(idx_ty, Type::Int(_)) {
1813 self.error(TypeError::invalid_index(&format!("{}", idx_ty)));
1814 }
1815 *element
1816 }
1817 _ => {
1818 self.fresh_var()
1820 }
1821 }
1822 }
1823
1824 Expr::Return(val) => {
1825 let actual_type = if let Some(e) = val {
1826 self.infer_expr(e)
1827 } else {
1828 Type::Unit
1829 };
1830
1831 if let Some(expected) = self.expected_return_type.clone() {
1833 if !self.unify(&expected, &actual_type) {
1834 self.error(TypeError::new(format!(
1835 "type mismatch in return: expected {}, found {}",
1836 expected, actual_type
1837 )));
1838 }
1839 }
1840
1841 Type::Never
1842 }
1843
1844 Expr::Evidential {
1846 expr,
1847 evidentiality,
1848 } => {
1849 let inner = self.infer_expr(expr);
1850 Type::Evidential {
1851 inner: Box::new(inner),
1852 evidence: EvidenceLevel::from_ast(*evidentiality),
1853 }
1854 }
1855
1856 Expr::Match { expr, arms } => {
1858 let scrutinee = self.infer_expr(expr);
1859 let scrutinee_ev = self.get_evidence(&scrutinee);
1860
1861 if arms.is_empty() {
1862 return Type::Never; }
1864
1865 let mut arm_types: Vec<Type> = Vec::new();
1867 let mut max_evidence = EvidenceLevel::Known;
1868
1869 for arm in arms {
1870 self.push_scope();
1871
1872 self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
1875
1876 if let Some(ref guard) = arm.guard {
1878 let guard_ty = self.infer_expr(guard);
1879 if !self.unify(&Type::Bool, &guard_ty) {
1880 self.error(TypeError::non_bool_condition("match guard", &format!("{}", guard_ty)));
1881 }
1882 }
1883
1884 let body_ty = self.infer_expr(&arm.body);
1886 let body_ev = self.get_evidence(&body_ty);
1887
1888 max_evidence = max_evidence.join(body_ev);
1890 arm_types.push(body_ty);
1891
1892 self.pop_scope();
1893 }
1894
1895 let first_ty = &arm_types[0];
1898 for (_i, ty) in arm_types.iter().enumerate().skip(1) {
1899 let _ = self.unify(first_ty, ty);
1900 }
1901
1902 let (inner_ty, _) = self.strip_evidence(first_ty);
1904 if max_evidence > EvidenceLevel::Known {
1905 Type::Evidential {
1906 inner: Box::new(inner_ty),
1907 evidence: max_evidence,
1908 }
1909 } else {
1910 inner_ty
1911 }
1912 }
1913
1914 Expr::MethodCall {
1915 receiver,
1916 method,
1917 args,
1918 ..
1919 } => {
1920 let recv_ty = self.infer_expr(receiver);
1921 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
1922 let _arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1923
1924 let result_ty = match method.name.as_str() {
1926 "len" | "count" | "size" => Type::Int(IntSize::USize),
1928
1929 "is_empty" | "contains" | "starts_with" | "ends_with" | "is_some"
1931 | "is_none" | "is_ok" | "is_err" | "is_ascii" | "is_alphabetic"
1932 | "is_numeric" | "is_alphanumeric" | "is_whitespace" | "is_uppercase"
1933 | "is_lowercase" | "exists" | "is_file" | "is_dir" | "is_match" | "matches"
1934 | "eq" | "ne" | "lt" | "le" | "gt" | "ge" => Type::Bool,
1935
1936 "to_string" | "to_lowercase" | "to_uppercase" | "trim" | "trim_start"
1938 | "trim_end" | "to_owned" | "replace" | "replacen" | "repeat"
1939 | "to_string_lossy" => Type::Named {
1940 name: "String".to_string(),
1941 generics: vec![],
1942 },
1943
1944 "as_str" | "trim_matches" | "trim_start_matches" | "trim_end_matches"
1946 | "strip_prefix" | "strip_suffix" => Type::Ref {
1947 lifetime: None,
1948 mutable: false,
1949 inner: Box::new(Type::Str),
1950 },
1951
1952 "clone" | "cloned" | "copied" => recv_inner.clone(),
1954
1955 "unwrap" | "unwrap_or" | "unwrap_or_default" | "unwrap_or_else" | "expect"
1957 | "ok" | "err" => {
1958 if let Type::Named { name, generics } = &recv_inner {
1959 if (name == "Option" || name == "Result") && !generics.is_empty() {
1960 generics[0].clone()
1961 } else {
1962 self.fresh_var()
1963 }
1964 } else {
1965 self.fresh_var()
1966 }
1967 }
1968
1969 "collect" => self.fresh_var(),
1971
1972 "iter" | "into_iter" | "iter_mut" | "rev" | "skip" | "take" | "filter"
1974 | "map" | "filter_map" | "flat_map" | "enumerate" | "zip" | "chain"
1975 | "flatten" | "reverse" | "sorted" | "dedup" | "unique" | "peekable"
1976 | "fuse" | "cycle" | "step_by" | "take_while" | "skip_while" | "scan"
1977 | "inspect" => recv_inner.clone(),
1978
1979 "split"
1981 | "rsplit"
1982 | "splitn"
1983 | "rsplitn"
1984 | "split_whitespace"
1985 | "split_ascii_whitespace"
1986 | "lines"
1987 | "chars"
1988 | "bytes"
1989 | "char_indices"
1990 | "split_terminator"
1991 | "rsplit_terminator"
1992 | "split_inclusive"
1993 | "matches_iter" => self.fresh_var(),
1994
1995 "keys" | "values" | "values_mut" | "into_keys" | "into_values" | "entry"
1997 | "drain" => self.fresh_var(),
1998
1999 "first" | "last" | "get" | "get_mut" | "pop" | "pop_front" | "pop_back"
2001 | "find" | "find_map" | "position" | "rposition" | "next" | "next_back"
2002 | "peek" | "nth" | "last_mut" | "binary_search" | "parent" | "file_name"
2003 | "file_stem" | "extension" => Type::Named {
2004 name: "Option".to_string(),
2005 generics: vec![self.fresh_var()],
2006 },
2007
2008 "parse" | "try_into" | "try_from" => Type::Named {
2010 name: "Result".to_string(),
2011 generics: vec![self.fresh_var(), self.fresh_var()],
2012 },
2013
2014 "push" | "push_str" | "push_front" | "push_back" | "insert" | "remove"
2016 | "clear" | "sort" | "sort_by" | "sort_by_key" | "sort_unstable"
2017 | "truncate" | "resize" | "extend" | "append" | "retain" | "swap"
2018 | "swap_remove" => Type::Unit,
2019
2020 "abs" | "floor" | "ceil" | "round" | "trunc" | "fract" | "sqrt" | "cbrt"
2022 | "sin" | "cos" | "tan" | "asin" | "acos" | "atan" | "sinh" | "cosh"
2023 | "tanh" | "exp" | "exp2" | "ln" | "log" | "log2" | "log10" | "pow"
2024 | "powi" | "powf" | "min" | "max" | "clamp" | "signum" | "copysign"
2025 | "saturating_add" | "saturating_sub" | "saturating_mul" | "wrapping_add"
2026 | "wrapping_sub" | "wrapping_mul" | "checked_add" | "checked_sub"
2027 | "checked_mul" | "checked_div" => recv_inner.clone(),
2028
2029 "to_digit" | "to_lowercase_char" | "to_uppercase_char" => Type::Named {
2031 name: "Option".to_string(),
2032 generics: vec![Type::Int(IntSize::U32)],
2033 },
2034
2035 "duration_since" | "elapsed" | "as_secs" | "as_millis" | "as_micros"
2037 | "as_nanos" | "from_secs" | "from_millis" => recv_inner.clone(),
2038
2039 "to_path_buf" | "join" | "with_extension" | "with_file_name" => Type::Named {
2041 name: "PathBuf".to_string(),
2042 generics: vec![],
2043 },
2044
2045 "to_str" => Type::Named {
2047 name: "Option".to_string(),
2048 generics: vec![Type::Ref {
2049 lifetime: None,
2050 mutable: false,
2051 inner: Box::new(Type::Str),
2052 }],
2053 },
2054
2055 "fmt" | "write_str" | "write_fmt" => Type::Named {
2057 name: "Result".to_string(),
2058 generics: vec![Type::Unit, self.fresh_var()],
2059 },
2060
2061 "read" | "write" | "flush" | "read_to_string" | "read_to_end" | "read_line"
2063 | "write_all" => Type::Named {
2064 name: "Result".to_string(),
2065 generics: vec![self.fresh_var(), self.fresh_var()],
2066 },
2067
2068 "metadata" | "modified" | "created" | "accessed" | "len_file"
2070 | "is_readonly" | "permissions" => Type::Named {
2071 name: "Result".to_string(),
2072 generics: vec![self.fresh_var(), self.fresh_var()],
2073 },
2074
2075 "map_err" | "and_then" | "or_else" => recv_inner.clone(),
2077
2078 "and" | "or" => recv_inner.clone(),
2080
2081 _ => self.fresh_var(),
2083 };
2084
2085 if recv_ev > EvidenceLevel::Known {
2087 Type::Evidential {
2088 inner: Box::new(result_ty),
2089 evidence: recv_ev,
2090 }
2091 } else {
2092 result_ty
2093 }
2094 }
2095
2096 Expr::Field { expr, field } => {
2097 let recv_ty = self.infer_expr(expr);
2098 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
2099
2100 let field_ty = if let Type::Named { name, .. } = &recv_inner {
2102 if let Some(struct_def) = self.types.get(name) {
2104 if let TypeDef::Struct { fields, .. } = struct_def {
2105 fields
2106 .iter()
2107 .find(|(n, _)| n == &field.name)
2108 .map(|(_, ty)| ty.clone())
2109 .unwrap_or_else(|| self.fresh_var())
2110 } else {
2111 self.fresh_var()
2112 }
2113 } else {
2114 self.fresh_var()
2115 }
2116 } else {
2117 self.fresh_var()
2118 };
2119
2120 if recv_ev > EvidenceLevel::Known {
2122 Type::Evidential {
2123 inner: Box::new(field_ty),
2124 evidence: recv_ev,
2125 }
2126 } else {
2127 field_ty
2128 }
2129 }
2130
2131 Expr::Index { expr, index, .. } => {
2132 let arr_ty = self.infer_expr(expr);
2133 let idx_ty = self.infer_expr(index);
2134 let (arr_inner, arr_ev) = self.strip_evidence(&arr_ty);
2135
2136 let _ = self.unify(&idx_ty, &Type::Int(IntSize::USize));
2138
2139 let elem_ty = match arr_inner {
2141 Type::Array { element, .. } => *element,
2142 Type::Slice(element) => *element,
2143 Type::Named { name, generics } if name == "Vec" && !generics.is_empty() => {
2144 generics[0].clone()
2145 }
2146 _ => self.fresh_var(),
2147 };
2148
2149 if arr_ev > EvidenceLevel::Known {
2151 Type::Evidential {
2152 inner: Box::new(elem_ty),
2153 evidence: arr_ev,
2154 }
2155 } else {
2156 elem_ty
2157 }
2158 }
2159
2160 _ => {
2161 self.fresh_var()
2163 }
2164 }
2165 }
2166
2167 fn infer_literal(&self, lit: &Literal) -> Type {
2169 match lit {
2170 Literal::Int { .. } => Type::Int(IntSize::I64),
2171 Literal::Float { suffix, .. } => {
2172 match suffix.as_ref().map(|s| s.as_str()) {
2173 Some("f32") => Type::Float(FloatSize::F32),
2174 Some("f64") => Type::Float(FloatSize::F64),
2175 None | Some(_) => Type::Float(FloatSize::F64),
2177 }
2178 }
2179 Literal::Bool(_) => Type::Bool,
2180 Literal::Char(_) => Type::Char,
2181 Literal::ByteChar(_) => Type::Int(IntSize::U8),
2182 Literal::String(_) => Type::Ref {
2184 lifetime: None,
2185 mutable: false,
2186 inner: Box::new(Type::Str),
2187 },
2188 Literal::MultiLineString(_) => Type::Ref {
2189 lifetime: None,
2190 mutable: false,
2191 inner: Box::new(Type::Str),
2192 },
2193 Literal::RawString(_) => Type::Ref {
2194 lifetime: None,
2195 mutable: false,
2196 inner: Box::new(Type::Str),
2197 },
2198 Literal::ByteString(bytes) => Type::Ref {
2199 lifetime: None,
2200 mutable: false,
2201 inner: Box::new(Type::Array {
2202 element: Box::new(Type::Int(IntSize::U8)),
2203 size: Some(bytes.len()),
2204 }),
2205 },
2206 Literal::InterpolatedString { .. } => Type::Str,
2207 Literal::SigilStringSql(_) => Type::Str,
2208 Literal::SigilStringRoute(_) => Type::Str,
2209 Literal::Null => Type::Unit, Literal::Empty => Type::Unit,
2211 Literal::Infinity => Type::Float(FloatSize::F64),
2212 Literal::Circle => Type::Float(FloatSize::F64),
2213 }
2214 }
2215
2216 fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
2218 let (left_inner, left_ev) = self.strip_evidence(left);
2220 let (right_inner, right_ev) = self.strip_evidence(right);
2221
2222 let is_var_or_fn = |ty: &Type| matches!(ty, Type::Var(_) | Type::Function { .. });
2224
2225 let result_ty = match op {
2226 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
2228 match (&left_inner, &right_inner) {
2230 (Type::Float(l), Type::Float(r)) => {
2232 Type::Float(if matches!(l, FloatSize::F64) || matches!(r, FloatSize::F64) {
2233 FloatSize::F64
2234 } else {
2235 *l
2236 })
2237 }
2238 (Type::Float(f), Type::Int(_)) | (Type::Int(_), Type::Float(f)) => {
2240 Type::Float(*f)
2241 }
2242 _ => {
2244 let _ = self.unify(&left_inner, &right_inner);
2245 left_inner
2246 }
2247 }
2248 }
2249
2250 BinOp::MatMul | BinOp::Hadamard | BinOp::TensorProd | BinOp::Convolve => {
2255 self.fresh_var()
2257 }
2258
2259 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
2261 if !self.unify(&left_inner, &right_inner)
2264 && !is_var_or_fn(&left_inner)
2265 && !is_var_or_fn(&right_inner)
2266 {
2267 self.error(TypeError::new(format!(
2268 "comparison operands must have same type: left={:?}, right={:?}",
2269 left_inner, right_inner
2270 )));
2271 }
2272 Type::Bool
2273 }
2274
2275 BinOp::And | BinOp::Or => {
2277 if !self.unify(&Type::Bool, &left_inner) {
2278 self.error(TypeError::invalid_operand("&&/||", &format!("{}", left_inner))
2279 .with_note("logical operators require boolean operands"));
2280 }
2281 if !self.unify(&Type::Bool, &right_inner) {
2282 self.error(TypeError::invalid_operand("&&/||", &format!("{}", right_inner))
2283 .with_note("logical operators require boolean operands"));
2284 }
2285 Type::Bool
2286 }
2287
2288 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
2290
2291 BinOp::Concat => {
2293 if !self.unify(&Type::Str, &left_inner) {
2294 self.error(TypeError::invalid_operand("++", &format!("{}", left_inner))
2295 .with_note("string concatenation requires string operands"));
2296 }
2297 Type::Str
2298 }
2299 };
2300
2301 let combined_ev = left_ev.join(right_ev);
2303
2304 if combined_ev > EvidenceLevel::Known {
2306 Type::Evidential {
2307 inner: Box::new(result_ty),
2308 evidence: combined_ev,
2309 }
2310 } else {
2311 result_ty
2312 }
2313 }
2314
2315 fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
2317 let (inner_ty, evidence) = self.strip_evidence(inner);
2318
2319 let result = match op {
2320 UnaryOp::Neg => inner_ty,
2321 UnaryOp::Not => {
2322 if !self.unify(&Type::Bool, &inner_ty) {
2324 self.error(TypeError::new(format!(
2325 "type mismatch: '!' requires bool, found {}",
2326 inner_ty
2327 )));
2328 }
2329 Type::Bool
2330 }
2331 UnaryOp::Ref => Type::Ref {
2332 lifetime: None,
2333 mutable: false,
2334 inner: Box::new(inner_ty),
2335 },
2336 UnaryOp::RefMut => Type::Ref {
2337 lifetime: None,
2338 mutable: true,
2339 inner: Box::new(inner_ty),
2340 },
2341 UnaryOp::Deref => {
2342 if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
2343 *inner
2344 } else {
2345 self.fresh_var()
2347 }
2348 }
2349 };
2350
2351 if evidence > EvidenceLevel::Known {
2353 Type::Evidential {
2354 inner: Box::new(result),
2355 evidence,
2356 }
2357 } else {
2358 result
2359 }
2360 }
2361
2362 fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
2364 let (inner_ev_stripped, evidence) = self.strip_evidence(input);
2365
2366 let inner = match inner_ev_stripped {
2369 Type::Ref {
2370 inner: ref_inner, ..
2371 } => (*ref_inner).clone(),
2372 other => other,
2373 };
2374
2375 let result = match op {
2376 PipeOp::Transform(_body) => {
2378 if let Type::Array { element, size } = inner {
2379 Type::Array { element, size }
2380 } else if let Type::Slice(element) = inner {
2381 Type::Slice(element)
2382 } else {
2383 self.fresh_var()
2385 }
2386 }
2387
2388 PipeOp::Filter(_pred) => inner,
2390
2391 PipeOp::Sort(_) => inner,
2393
2394 PipeOp::Reduce(_) => {
2396 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2397 *element
2398 } else if let Type::Named { name, generics } = &inner {
2399 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2401 && !generics.is_empty()
2402 {
2403 generics[0].clone()
2404 } else {
2405 self.fresh_var()
2406 }
2407 } else if let Type::Var(_) = inner {
2408 self.fresh_var()
2410 } else {
2411 self.error(TypeError::invalid_reduction("reduce", &format!("{}", inner)));
2412 Type::Error
2413 }
2414 }
2415 PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
2416 let element = if let Type::Array { element, .. } | Type::Slice(element) = &inner {
2418 Some(element.clone())
2419 } else if let Type::Named { name, generics } = &inner {
2420 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2422 && !generics.is_empty()
2423 {
2424 Some(Box::new(generics[0].clone()))
2425 } else {
2426 None
2427 }
2428 } else {
2429 None
2430 };
2431 if let Some(element) = element {
2432 match element.as_ref() {
2433 Type::Int(_) | Type::Float(_) => *element,
2434 Type::Var(_) => *element, _ => {
2436 self.error(TypeError::invalid_operand("numeric reduction", &format!("{}", element)));
2437 Type::Error
2438 }
2439 }
2440 } else if let Type::Var(_) = inner {
2441 self.fresh_var()
2443 } else {
2444 self.error(TypeError::invalid_reduction("numeric reduction", &format!("{}", inner)));
2445 Type::Error
2446 }
2447 }
2448 PipeOp::ReduceConcat => {
2449 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2451 match element.as_ref() {
2452 Type::Str => Type::Str,
2453 Type::Array { .. } => *element,
2454 Type::Var(_) => self.fresh_var(), _ => {
2456 self.error(TypeError::invalid_operand("concat reduction", &format!("{}", element))
2457 .with_note("concat requires strings or arrays"));
2458 Type::Error
2459 }
2460 }
2461 } else if let Type::Var(_) = inner {
2462 self.fresh_var()
2464 } else {
2465 self.error(TypeError::invalid_reduction("concat reduction", &format!("{}", inner)));
2466 Type::Error
2467 }
2468 }
2469 PipeOp::ReduceAll | PipeOp::ReduceAny => {
2470 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2472 match element.as_ref() {
2473 Type::Bool => Type::Bool,
2474 Type::Var(_) => Type::Bool, _ => {
2476 self.error(TypeError::invalid_operand("boolean reduction", &format!("{}", element))
2477 .with_note("all/any requires array of booleans"));
2478 Type::Error
2479 }
2480 }
2481 } else if let Type::Var(_) = inner {
2482 Type::Bool
2484 } else {
2485 self.error(TypeError::invalid_reduction("boolean reduction", &format!("{}", inner)));
2486 Type::Error
2487 }
2488 }
2489
2490 PipeOp::Match(arms) => {
2492 if arms.is_empty() {
2494 self.error(TypeError::missing_match_arm());
2495 Type::Error
2496 } else {
2497 let result_type = self.infer_expr(&arms[0].body);
2499 for arm in arms.iter().skip(1) {
2500 let arm_type = self.infer_expr(&arm.body);
2501 self.unify(&result_type, &arm_type);
2502 }
2503 result_type
2504 }
2505 }
2506
2507 PipeOp::TryMap(_) => {
2509 self.fresh_var()
2513 }
2514
2515 PipeOp::Call(callee) => {
2517 let callee_ty = self.infer_expr(callee);
2519 if let Type::Function { return_type, .. } = callee_ty {
2520 *return_type
2521 } else {
2522 self.fresh_var()
2524 }
2525 }
2526
2527 PipeOp::Method {
2529 name,
2530 type_args: _,
2531 args: _,
2532 } => {
2533 if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
2535 let fresh_ty = self.freshen(&fn_ty);
2537 if let Type::Function { return_type, .. } = fresh_ty {
2538 *return_type
2539 } else {
2540 Type::Error
2541 }
2542 } else {
2543 self.fresh_var()
2545 }
2546 }
2547
2548 PipeOp::Named { prefix, body: _ } => {
2550 if let Some(first) = prefix.first() {
2552 match first.name.as_str() {
2553 "sum" | "product" => {
2554 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2555 *element
2556 } else {
2557 self.error(TypeError::new("sum/product requires array"));
2558 Type::Error
2559 }
2560 }
2561 _ => self.fresh_var(),
2562 }
2563 } else {
2564 self.fresh_var()
2565 }
2566 }
2567
2568 PipeOp::Await => {
2570 inner
2572 }
2573
2574 PipeOp::First
2576 | PipeOp::Last
2577 | PipeOp::Middle
2578 | PipeOp::Choice
2579 | PipeOp::Nth(_)
2580 | PipeOp::Next => {
2581 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2582 *element
2583 } else if let Type::Named { name, generics } = &inner {
2584 if (name == "Vec" || name == "VecDeque" || name == "LinkedList")
2586 && !generics.is_empty()
2587 {
2588 generics[0].clone()
2589 } else {
2590 self.fresh_var()
2591 }
2592 } else if let Type::Tuple(elements) = inner {
2593 if let Some(first) = elements.first() {
2595 first.clone()
2596 } else {
2597 Type::Unit
2598 }
2599 } else if let Type::Var(_) = inner {
2600 self.fresh_var()
2602 } else {
2603 self.fresh_var()
2605 }
2606 }
2607
2608 PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
2611
2612 PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
2615
2616 PipeOp::Send(_) => {
2623 Type::Evidential {
2625 inner: Box::new(self.fresh_var()),
2626 evidence: EvidenceLevel::Reported,
2627 }
2628 }
2629
2630 PipeOp::Recv => {
2632 Type::Evidential {
2634 inner: Box::new(self.fresh_var()),
2635 evidence: EvidenceLevel::Reported,
2636 }
2637 }
2638
2639 PipeOp::Stream(_) => {
2641 self.fresh_var()
2643 }
2644
2645 PipeOp::Connect(_) => {
2647 self.fresh_var()
2649 }
2650
2651 PipeOp::Close => Type::Unit,
2653
2654 PipeOp::Header { .. } => inner,
2656
2657 PipeOp::Body(_) => inner,
2659
2660 PipeOp::Timeout(_) => inner,
2662
2663 PipeOp::Retry { .. } => inner,
2665
2666 PipeOp::Validate {
2672 predicate: _,
2673 target_evidence,
2674 } => {
2675 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2679
2680 if evidence < target_ev {
2682 self.error(
2683 TypeError::new(format!(
2684 "cannot demote evidence from {} ({}) to {} ({}) using validate",
2685 evidence.name(),
2686 evidence.symbol(),
2687 target_ev.name(),
2688 target_ev.symbol()
2689 ))
2690 .with_note("validate! can only promote evidence to a more certain level"),
2691 );
2692 }
2693
2694 return Type::Evidential {
2696 inner: Box::new(inner.clone()),
2697 evidence: target_ev,
2698 };
2699 }
2700
2701 PipeOp::Assume {
2703 reason: _,
2704 target_evidence,
2705 } => {
2706 let target_ev = EvidenceLevel::from_ast(*target_evidence);
2707
2708 if evidence < target_ev {
2712 self.error(
2713 TypeError::new(format!(
2714 "assume! cannot demote evidence from {} ({}) to {} ({})",
2715 evidence.name(),
2716 evidence.symbol(),
2717 target_ev.name(),
2718 target_ev.symbol()
2719 ))
2720 .with_note("assume! is for promoting evidence, not demoting"),
2721 );
2722 }
2723
2724 return Type::Evidential {
2726 inner: Box::new(inner.clone()),
2727 evidence: target_ev,
2728 };
2729 }
2730
2731 PipeOp::AssertEvidence(expected_ast) => {
2733 let expected = EvidenceLevel::from_ast(*expected_ast);
2734
2735 if !evidence.satisfies(expected) {
2736 self.error(
2737 TypeError::new(format!(
2738 "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
2739 expected.name(), expected.symbol(),
2740 evidence.name(), evidence.symbol()
2741 ))
2742 .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
2743 );
2744 }
2745
2746 return input.clone();
2748 }
2749
2750 PipeOp::Also(_) => {
2757 return input.clone();
2760 }
2761
2762 PipeOp::Apply(_) => {
2765 return input.clone();
2768 }
2769
2770 PipeOp::TakeIf(_) => {
2773 return Type::Named {
2776 name: "Option".to_string(),
2777 generics: vec![input.clone()],
2778 };
2779 }
2780
2781 PipeOp::TakeUnless(_) => {
2784 return Type::Named {
2787 name: "Option".to_string(),
2788 generics: vec![input.clone()],
2789 };
2790 }
2791
2792 PipeOp::Let(func) => {
2795 let _ = self.infer_expr(func);
2797 self.fresh_var() }
2799
2800 PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
2802 PipeOp::Compose(f) => {
2803 let _ = self.infer_expr(f);
2804 self.fresh_var()
2805 }
2806 PipeOp::Zip(other) => {
2807 let _ = self.infer_expr(other);
2808 self.fresh_var() }
2810 PipeOp::Scan(f) => {
2811 let _ = self.infer_expr(f);
2812 self.fresh_var() }
2814 PipeOp::Diff => self.fresh_var(), PipeOp::Gradient(var) => {
2816 let _ = self.infer_expr(var);
2817 self.fresh_var() }
2819 PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
2820 inner.clone() }
2822 PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
2823 let _ = self.infer_expr(n);
2824 self.fresh_var() }
2826 PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
2827 PipeOp::Enumerate => self.fresh_var(), PipeOp::Universal => self.fresh_var(), PipeOp::Possibility => self.fresh_var(), PipeOp::Necessity => Type::Evidential {
2833 inner: Box::new(self.fresh_var()),
2834 evidence: EvidenceLevel::Known,
2835 },
2836 PipeOp::PossibilityMethod { args, .. } => {
2837 for arg in args {
2839 let _ = self.infer_expr(arg);
2840 }
2841 self.fresh_var() }
2843 PipeOp::NecessityMethod { args, .. } => {
2844 for arg in args {
2846 let _ = self.infer_expr(arg);
2847 }
2848 Type::Evidential {
2849 inner: Box::new(self.fresh_var()),
2850 evidence: EvidenceLevel::Known,
2851 }
2852 }
2853 };
2854
2855 if evidence > EvidenceLevel::Known {
2857 Type::Evidential {
2858 inner: Box::new(result),
2859 evidence,
2860 }
2861 } else {
2862 result
2863 }
2864 }
2865
2866 fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
2868 match ty {
2869 Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
2870 _ => (ty.clone(), EvidenceLevel::Known),
2871 }
2872 }
2873
2874 fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
2877 let (inner_ty, ty_ev) = self.strip_evidence(ty);
2878 let final_ev = evidence.join(ty_ev);
2880
2881 match pattern {
2882 Pattern::Ident {
2883 name,
2884 evidentiality,
2885 ..
2886 } => {
2887 let ev = evidentiality
2889 .map(EvidenceLevel::from_ast)
2890 .unwrap_or(final_ev);
2891 self.env
2892 .borrow_mut()
2893 .define(name.name.clone(), inner_ty, ev);
2894 }
2895 Pattern::Tuple(patterns) => {
2896 if let Type::Tuple(types) = &inner_ty {
2897 for (pat, ty) in patterns.iter().zip(types.iter()) {
2898 self.bind_pattern(pat, ty, final_ev);
2899 }
2900 }
2901 }
2902 Pattern::Struct { fields, .. } => {
2903 for field in fields {
2906 let fresh = self.fresh_var();
2907 if let Some(ref pat) = field.pattern {
2908 self.bind_pattern(pat, &fresh, final_ev);
2909 } else {
2910 self.env
2911 .borrow_mut()
2912 .define(field.name.name.clone(), fresh, final_ev);
2913 }
2914 }
2915 }
2916 Pattern::TupleStruct { fields, .. } => {
2917 for pat in fields {
2918 let fresh = self.fresh_var();
2919 self.bind_pattern(pat, &fresh, final_ev);
2920 }
2921 }
2922 Pattern::Slice(patterns) => {
2923 let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
2924 {
2925 *element.clone()
2926 } else {
2927 self.fresh_var()
2928 };
2929 for pat in patterns {
2930 self.bind_pattern(pat, &elem_ty, final_ev);
2931 }
2932 }
2933 Pattern::Or(patterns) => {
2934 if let Some(first) = patterns.first() {
2937 self.bind_pattern(first, ty, evidence);
2938 }
2939 }
2940 Pattern::Wildcard
2941 | Pattern::Rest
2942 | Pattern::Literal(_)
2943 | Pattern::Range { .. }
2944 | Pattern::Path(_) => {
2945 }
2947 Pattern::Ref { pattern, .. } => {
2948 let inner_ty = self.fresh_var();
2951 self.bind_pattern(pattern, &inner_ty, final_ev);
2952 }
2953 Pattern::RefBinding {
2954 name,
2955 evidentiality,
2956 ..
2957 } => {
2958 let ev = evidentiality
2960 .map(EvidenceLevel::from_ast)
2961 .unwrap_or(final_ev);
2962 self.env
2963 .borrow_mut()
2964 .define(name.name.clone(), inner_ty, ev);
2965 }
2966 }
2967 }
2968
2969 fn resolve_alias(&self, ty: &Type) -> Type {
2971 if let Type::Named { name, generics } = ty {
2972 if generics.is_empty() {
2973 if let Some(TypeDef::Alias { target, .. }) = self.types.get(name) {
2974 return target.clone();
2975 }
2976 }
2977 }
2978 ty.clone()
2979 }
2980
2981 fn unify(&mut self, a: &Type, b: &Type) -> bool {
2983 let a = self.resolve_alias(a);
2985 let b = self.resolve_alias(b);
2986
2987 match (&a, &b) {
2988 (Type::Var(v), t) => {
2990 if let Some(resolved) = self.substitutions.get(v) {
2991 let resolved = resolved.clone();
2992 self.unify(&resolved, t)
2993 } else if !self.occurs_in(v, t) {
2994 self.substitutions.insert(*v, t.clone());
2995 true
2996 } else {
2997 true
2999 }
3000 }
3001 (t, Type::Var(v)) => {
3002 if let Some(resolved) = self.substitutions.get(v) {
3003 let resolved = resolved.clone();
3004 self.unify(t, &resolved)
3005 } else if !self.occurs_in(v, t) {
3006 self.substitutions.insert(*v, t.clone());
3007 true
3008 } else {
3009 true
3011 }
3012 }
3013
3014 (Type::Unit, Type::Unit) |
3016 (Type::Bool, Type::Bool) |
3017 (Type::Char, Type::Char) |
3018 (Type::Str, Type::Str) |
3019 (Type::Never, Type::Never) |
3020 (Type::Error, _) |
3021 (_, Type::Error) |
3022 (Type::Never, _) |
3024 (_, Type::Never) => true,
3025
3026 (Type::Int(_), Type::Int(_)) => true,
3029 (Type::Float(_), Type::Float(_)) => true,
3032
3033 (Type::Ref { mutable: false, inner: a, .. }, Type::Str) if matches!(a.as_ref(), Type::Str) => true,
3035 (Type::Str, Type::Ref { mutable: false, inner: b, .. }) if matches!(b.as_ref(), Type::Str) => true,
3036
3037 (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
3039 (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
3040 }
3041
3042 (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
3044
3045 (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
3047 a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
3048 }
3049
3050 (Type::Ref { mutable: ma, inner: a, .. }, Type::Ref { mutable: mb, inner: b, .. }) => {
3052 match (a.as_ref(), b.as_ref()) {
3054 (Type::Array { element: ea, .. }, Type::Slice(es)) => {
3055 ma == mb && self.unify(ea, es)
3056 }
3057 (Type::Slice(es), Type::Array { element: ea, .. }) => {
3058 ma == mb && self.unify(es, ea)
3059 }
3060 _ => ma == mb && self.unify(a, b)
3061 }
3062 }
3063
3064 (Type::Function { params: pa, return_type: ra, is_async: aa },
3066 Type::Function { params: pb, return_type: rb, is_async: ab }) => {
3067 aa == ab && pa.len() == pb.len() &&
3068 pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
3069 self.unify(ra, rb)
3070 }
3071
3072 (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
3074 na == nb && ga.len() == gb.len() &&
3075 ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y))
3076 }
3077
3078 (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
3080 self.unify(a, b)
3081 }
3082 (Type::Evidential { inner: a, .. }, b) => {
3083 self.unify(a, b)
3084 }
3085 (a, Type::Evidential { inner: b, .. }) => {
3086 self.unify(a, b)
3087 }
3088
3089 (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
3091
3092 (Type::Linear(a), Type::Linear(b)) => self.unify(a, b),
3094 (Type::Linear(a), b) => self.unify(a, b),
3096 (a, Type::Linear(b)) => self.unify(a, b),
3097
3098 (Type::Named { name, generics }, _) | (_, Type::Named { name, generics })
3102 if generics.is_empty() && Self::is_type_parameter(name) => {
3103 true
3104 }
3105
3106 _ => false,
3107 }
3108 }
3109
3110 fn is_type_parameter(name: &str) -> bool {
3112 if name.len() == 1
3114 && name
3115 .chars()
3116 .next()
3117 .map(|c| c.is_ascii_uppercase())
3118 .unwrap_or(false)
3119 {
3120 return true;
3121 }
3122 matches!(
3124 name,
3125 "Item" | "Output" | "Error" | "Key" | "Value" | "Idx" | "Self"
3126 )
3127 }
3128
3129 fn is_numeric_coercion(expected: &Type, actual: &Type) -> bool {
3131 match (expected, actual) {
3133 (Type::Float(_), Type::Int(_)) => true,
3134 (Type::Evidential { inner: exp, .. }, Type::Int(_)) => {
3136 matches!(exp.as_ref(), Type::Float(_))
3137 }
3138 (Type::Float(_), Type::Evidential { inner: act, .. }) => {
3139 matches!(act.as_ref(), Type::Int(_))
3140 }
3141 _ => false,
3142 }
3143 }
3144
3145 fn types_match(a: &Type, b: &Type) -> bool {
3147 let a_inner = match a {
3149 Type::Evidential { inner, .. } => inner.as_ref(),
3150 other => other,
3151 };
3152 let b_inner = match b {
3153 Type::Evidential { inner, .. } => inner.as_ref(),
3154 other => other,
3155 };
3156 if a_inner != a || b_inner != b {
3158 return Self::types_match(a_inner, b_inner);
3159 }
3160 a == b
3162 }
3163
3164 fn is_reference_coercion(expected: &Type, actual: &Type) -> bool {
3166 match (expected, actual) {
3167 (Type::Ref { inner: exp_inner, mutable: false, .. },
3169 Type::Ref { inner: act_inner, mutable: true, .. }) => {
3170 Self::types_match(exp_inner.as_ref(), act_inner.as_ref())
3172 }
3173 (Type::Evidential { inner: exp, .. }, actual) => {
3175 Self::is_reference_coercion(exp.as_ref(), actual)
3176 }
3177 (expected, Type::Evidential { inner: act, .. }) => {
3178 Self::is_reference_coercion(expected, act.as_ref())
3179 }
3180 _ => false,
3181 }
3182 }
3183
3184 fn is_deref_coercion(expected: &Type, actual: &Type) -> bool {
3187 match (expected, actual) {
3188 (Type::Ref { inner: exp_inner, mutable: exp_mut, .. },
3190 Type::Ref { inner: act_inner, mutable: act_mut, .. }) => {
3191 if *act_mut && !*exp_mut {
3195 return false;
3197 }
3198
3199 if let Type::Named { name, generics } = act_inner.as_ref() {
3200 if name == "Box" && generics.len() == 1 {
3202 return Self::types_match(exp_inner.as_ref(), &generics[0]);
3203 }
3204 if name == "Vec" && generics.len() == 1 {
3206 if let Type::Slice(slice_elem) = exp_inner.as_ref() {
3207 return Self::types_match(slice_elem.as_ref(), &generics[0]);
3208 }
3209 }
3210 if name == "String" && generics.is_empty() {
3212 if matches!(exp_inner.as_ref(), Type::Str) {
3213 return true;
3214 }
3215 }
3216 }
3217 false
3218 }
3219 (Type::Evidential { inner: exp, .. }, actual) => {
3221 Self::is_deref_coercion(exp.as_ref(), actual)
3222 }
3223 (expected, Type::Evidential { inner: act, .. }) => {
3224 Self::is_deref_coercion(expected, act.as_ref())
3225 }
3226 _ => false,
3227 }
3228 }
3229
3230 fn is_coercible(expected: &Type, actual: &Type) -> bool {
3232 Self::is_numeric_coercion(expected, actual)
3233 || Self::is_reference_coercion(expected, actual)
3234 || Self::is_deref_coercion(expected, actual)
3235 }
3236
3237 fn convert_type(&self, ty: &TypeExpr) -> Type {
3239 match ty {
3240 TypeExpr::Path(path) => {
3241 if path.segments.len() == 1 {
3242 let name = &path.segments[0].ident.name;
3243 match name.as_str() {
3244 "bool" => return Type::Bool,
3245 "char" => return Type::Char,
3246 "str" | "String" => return Type::Str,
3247 "i8" => return Type::Int(IntSize::I8),
3248 "i16" => return Type::Int(IntSize::I16),
3249 "i32" => return Type::Int(IntSize::I32),
3250 "i64" => return Type::Int(IntSize::I64),
3251 "i128" => return Type::Int(IntSize::I128),
3252 "isize" => return Type::Int(IntSize::ISize),
3253 "u8" => return Type::Int(IntSize::U8),
3254 "u16" => return Type::Int(IntSize::U16),
3255 "u32" => return Type::Int(IntSize::U32),
3256 "u64" => return Type::Int(IntSize::U64),
3257 "u128" => return Type::Int(IntSize::U128),
3258 "usize" => return Type::Int(IntSize::USize),
3259 "f32" => return Type::Float(FloatSize::F32),
3260 "f64" => return Type::Float(FloatSize::F64),
3261 "Self" => {
3263 if let Some(ref self_ty) = self.current_self_type {
3264 return Type::Named {
3265 name: self_ty.clone(),
3266 generics: vec![],
3267 };
3268 }
3269 }
3270 _ => {
3271 if let Some(ty) = self.current_generics.get(name) {
3273 return ty.clone();
3274 }
3275 }
3276 }
3277 }
3278
3279 let name = path
3280 .segments
3281 .iter()
3282 .map(|s| s.ident.name.clone())
3283 .collect::<Vec<_>>()
3284 .join("::");
3285
3286 let generics = path
3287 .segments
3288 .last()
3289 .and_then(|s| s.generics.as_ref())
3290 .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
3291 .unwrap_or_default();
3292
3293 Type::Named { name, generics }
3294 }
3295
3296 TypeExpr::Reference {
3297 lifetime,
3298 mutable,
3299 inner,
3300 } => Type::Ref {
3301 lifetime: lifetime.clone(),
3302 mutable: *mutable,
3303 inner: Box::new(self.convert_type(inner)),
3304 },
3305
3306 TypeExpr::Pointer { mutable, inner } => Type::Ptr {
3307 mutable: *mutable,
3308 inner: Box::new(self.convert_type(inner)),
3309 },
3310
3311 TypeExpr::Array { element, size: _ } => {
3312 Type::Array {
3313 element: Box::new(self.convert_type(element)),
3314 size: None, }
3316 }
3317
3318 TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
3319
3320 TypeExpr::Tuple(elements) => {
3321 Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
3322 }
3323
3324 TypeExpr::Function {
3325 params,
3326 return_type,
3327 } => Type::Function {
3328 params: params.iter().map(|t| self.convert_type(t)).collect(),
3329 return_type: Box::new(
3330 return_type
3331 .as_ref()
3332 .map(|t| self.convert_type(t))
3333 .unwrap_or(Type::Unit),
3334 ),
3335 is_async: false,
3336 },
3337
3338 TypeExpr::Evidential {
3339 inner,
3340 evidentiality,
3341 error_type,
3342 } => {
3343 let _ = error_type; Type::Evidential {
3347 inner: Box::new(self.convert_type(inner)),
3348 evidence: EvidenceLevel::from_ast(*evidentiality),
3349 }
3350 }
3351
3352 TypeExpr::Cycle { modulus: _ } => {
3353 Type::Cycle { modulus: 12 } }
3355
3356 TypeExpr::Simd { element, lanes } => {
3357 let elem_ty = self.convert_type(element);
3358 Type::Simd {
3359 element: Box::new(elem_ty),
3360 lanes: *lanes,
3361 }
3362 }
3363
3364 TypeExpr::Atomic(inner) => {
3365 let inner_ty = self.convert_type(inner);
3366 Type::Atomic(Box::new(inner_ty))
3367 }
3368
3369 TypeExpr::Linear(inner) => {
3370 let inner_ty = self.convert_type(inner);
3371 Type::Linear(Box::new(inner_ty))
3372 }
3373
3374 TypeExpr::Never => Type::Never,
3375 TypeExpr::Infer => Type::Var(TypeVar(0)), TypeExpr::Lifetime(name) => Type::Lifetime(name.clone()),
3377 TypeExpr::TraitObject(bounds) => {
3378 let converted: Vec<Type> = bounds.iter().map(|b| self.convert_type(b)).collect();
3379 Type::TraitObject(converted)
3380 }
3381 TypeExpr::Hrtb { lifetimes, bound } => Type::Hrtb {
3382 lifetimes: lifetimes.clone(),
3383 bound: Box::new(self.convert_type(bound)),
3384 },
3385 TypeExpr::InlineStruct { fields } => Type::InlineStruct {
3386 fields: fields
3387 .iter()
3388 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
3389 .collect(),
3390 },
3391 TypeExpr::ImplTrait(bounds) => {
3392 Type::ImplTrait(bounds.iter().map(|b| self.convert_type(b)).collect())
3393 }
3394 TypeExpr::InlineEnum { variants } => {
3395 Type::InlineEnum(variants.iter().map(|v| v.name.name.clone()).collect())
3396 }
3397 TypeExpr::AssocTypeBinding { name, ty } => Type::AssocTypeBinding {
3398 name: name.name.clone(),
3399 ty: Box::new(self.convert_type(ty)),
3400 },
3401 TypeExpr::ConstExpr(_) => {
3402 Type::Var(TypeVar(0))
3405 }
3406 TypeExpr::QualifiedPath {
3407 self_type,
3408 trait_path,
3409 item_path,
3410 } => {
3411 let trait_part = trait_path
3414 .as_ref()
3415 .map(|tp| {
3416 tp.segments
3417 .iter()
3418 .map(|s| s.ident.name.clone())
3419 .collect::<Vec<_>>()
3420 .join("::")
3421 })
3422 .unwrap_or_default();
3423 let item_part = item_path
3424 .segments
3425 .iter()
3426 .map(|s| s.ident.name.clone())
3427 .collect::<Vec<_>>()
3428 .join("::");
3429 let name = if trait_part.is_empty() {
3430 format!("<_>::{}", item_part)
3431 } else {
3432 format!("<_ as {}>::{}", trait_part, item_part)
3433 };
3434 Type::Named {
3435 name,
3436 generics: vec![self.convert_type(self_type)],
3437 }
3438 }
3439 }
3440 }
3441
3442 pub fn errors(&self) -> &[TypeError] {
3444 &self.errors
3445 }
3446}
3447
3448impl Default for TypeChecker {
3449 fn default() -> Self {
3450 Self::new()
3451 }
3452}
3453
3454trait PatternExt {
3456 fn evidentiality(&self) -> Option<Evidentiality>;
3457 fn binding_name(&self) -> Option<String>;
3458 fn binding_span(&self) -> Option<Span>;
3459}
3460
3461impl PatternExt for Pattern {
3462 fn evidentiality(&self) -> Option<Evidentiality> {
3463 match self {
3464 Pattern::Ident { evidentiality, .. } => *evidentiality,
3465 _ => None,
3466 }
3467 }
3468
3469 fn binding_name(&self) -> Option<String> {
3470 match self {
3471 Pattern::Ident { name, .. } => Some(name.name.clone()),
3472 _ => None,
3473 }
3474 }
3475
3476 fn binding_span(&self) -> Option<Span> {
3477 match self {
3478 Pattern::Ident { name, .. } => Some(name.span),
3479 _ => None,
3480 }
3481 }
3482}
3483
3484impl fmt::Display for Type {
3485 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3486 match self {
3487 Type::Unit => write!(f, "()"),
3488 Type::Bool => write!(f, "bool"),
3489 Type::Int(size) => write!(f, "{:?}", size),
3490 Type::Float(size) => write!(f, "{:?}", size),
3491 Type::Char => write!(f, "char"),
3492 Type::Str => write!(f, "str"),
3493 Type::Array { element, size } => {
3494 if let Some(n) = size {
3495 write!(f, "[{}; {}]", element, n)
3496 } else {
3497 write!(f, "[{}]", element)
3498 }
3499 }
3500 Type::Slice(inner) => write!(f, "[{}]", inner),
3501 Type::Tuple(elems) => {
3502 write!(f, "(")?;
3503 for (i, e) in elems.iter().enumerate() {
3504 if i > 0 {
3505 write!(f, ", ")?;
3506 }
3507 write!(f, "{}", e)?;
3508 }
3509 write!(f, ")")
3510 }
3511 Type::Named { name, generics } => {
3512 write!(f, "{}", name)?;
3513 if !generics.is_empty() {
3514 write!(f, "<")?;
3515 for (i, g) in generics.iter().enumerate() {
3516 if i > 0 {
3517 write!(f, ", ")?;
3518 }
3519 write!(f, "{}", g)?;
3520 }
3521 write!(f, ">")?;
3522 }
3523 Ok(())
3524 }
3525 Type::Function {
3526 params,
3527 return_type,
3528 is_async,
3529 } => {
3530 if *is_async {
3531 write!(f, "async ")?;
3532 }
3533 write!(f, "fn(")?;
3534 for (i, p) in params.iter().enumerate() {
3535 if i > 0 {
3536 write!(f, ", ")?;
3537 }
3538 write!(f, "{}", p)?;
3539 }
3540 write!(f, ") -> {}", return_type)
3541 }
3542 Type::Ref {
3543 lifetime,
3544 mutable,
3545 inner,
3546 } => {
3547 let lt = lifetime
3548 .as_ref()
3549 .map(|l| format!("'{} ", l))
3550 .unwrap_or_default();
3551 write!(f, "&{}{}{}", lt, if *mutable { "mut " } else { "" }, inner)
3552 }
3553 Type::Ptr { mutable, inner } => {
3554 write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
3555 }
3556 Type::Evidential { inner, evidence } => {
3557 write!(f, "{}{}", inner, evidence.symbol())
3558 }
3559 Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
3560 Type::Var(v) => write!(f, "?{}", v.0),
3561 Type::Error => write!(f, "<error>"),
3562 Type::Never => write!(f, "!"),
3563 Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
3564 Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
3565 Type::Linear(inner) => write!(f, "linear {}", inner),
3566 Type::Lifetime(name) => write!(f, "'{}", name),
3567 Type::TraitObject(bounds) => {
3568 write!(f, "dyn ")?;
3569 for (i, bound) in bounds.iter().enumerate() {
3570 if i > 0 {
3571 write!(f, " + ")?;
3572 }
3573 write!(f, "{}", bound)?;
3574 }
3575 Ok(())
3576 }
3577 Type::Hrtb { lifetimes, bound } => {
3578 write!(f, "for<")?;
3579 for (i, lt) in lifetimes.iter().enumerate() {
3580 if i > 0 {
3581 write!(f, ", ")?;
3582 }
3583 write!(f, "'{}", lt)?;
3584 }
3585 write!(f, "> {}", bound)
3586 }
3587 Type::InlineStruct { fields } => {
3588 write!(f, "struct {{ ")?;
3589 for (i, (name, ty)) in fields.iter().enumerate() {
3590 if i > 0 {
3591 write!(f, ", ")?;
3592 }
3593 write!(f, "{}: {}", name, ty)?;
3594 }
3595 write!(f, " }}")
3596 }
3597 Type::ImplTrait(bounds) => {
3598 write!(f, "impl ")?;
3599 for (i, bound) in bounds.iter().enumerate() {
3600 if i > 0 {
3601 write!(f, " + ")?;
3602 }
3603 write!(f, "{}", bound)?;
3604 }
3605 Ok(())
3606 }
3607 Type::InlineEnum(variants) => {
3608 write!(f, "enum {{ ")?;
3609 for (i, name) in variants.iter().enumerate() {
3610 if i > 0 {
3611 write!(f, ", ")?;
3612 }
3613 write!(f, "{}", name)?;
3614 }
3615 write!(f, " }}")
3616 }
3617 Type::AssocTypeBinding { name, ty } => {
3618 write!(f, "{} = {}", name, ty)
3619 }
3620 }
3621 }
3622}
3623
3624#[cfg(test)]
3625mod tests {
3626 use super::*;
3627 use crate::Parser;
3628
3629 fn check(source: &str) -> Result<(), Vec<TypeError>> {
3630 let mut parser = Parser::new(source);
3631 let file = parser.parse_file().expect("parse failed");
3632 let mut checker = TypeChecker::new();
3633 checker.check_file(&file)
3634 }
3635
3636 #[test]
3637 fn test_basic_types() {
3638 assert!(check("fn main() { let x: i64 = 42; }").is_ok());
3639 assert!(check("fn main() { let x: bool = true; }").is_ok());
3640 assert!(check("fn main() { let x: f64 = 3.14; }").is_ok());
3641 }
3642
3643 #[test]
3644 fn test_type_mismatch() {
3645 assert!(check("fn main() { let x: bool = 42; }").is_err());
3646 }
3647
3648 #[test]
3649 fn test_evidence_propagation() {
3650 assert!(check(
3652 r#"
3653 fn main() {
3654 let known: i64! = 42;
3655 let uncertain: i64? = 10;
3656 let result = known + uncertain;
3657 }
3658 "#
3659 )
3660 .is_ok());
3661 }
3662
3663 #[test]
3664 fn test_function_return() {
3665 let result = check(
3666 r#"
3667 fn add(a: i64, b: i64) -> i64 {
3668 return a + b;
3669 }
3670 fn main() {
3671 let x = add(1, 2);
3672 }
3673 "#,
3674 );
3675 if let Err(errors) = &result {
3676 for e in errors {
3677 eprintln!("Error: {}", e);
3678 }
3679 }
3680 assert!(result.is_ok());
3681 }
3682
3683 #[test]
3684 fn test_array_types() {
3685 assert!(check(
3686 r#"
3687 fn main() {
3688 let arr = [1, 2, 3];
3689 let x = arr[0];
3690 }
3691 "#
3692 )
3693 .is_ok());
3694 }
3695
3696 #[test]
3701 fn test_evidence_inference_from_initializer() {
3702 assert!(check(
3704 r#"
3705 fn main() {
3706 let reported_val: i64~ = 42;
3707 // x should inherit ~ evidence from reported_val
3708 let x = reported_val + 1;
3709 }
3710 "#
3711 )
3712 .is_ok());
3713 }
3714
3715 #[test]
3716 fn test_evidence_inference_explicit_override() {
3717 assert!(check(
3719 r#"
3720 fn main() {
3721 let reported_val: i64~ = 42;
3722 // Explicit ! annotation - this would fail if we checked evidence properly
3723 // but the type system allows it as an override
3724 let x! = 42;
3725 }
3726 "#
3727 )
3728 .is_ok());
3729 }
3730
3731 #[test]
3732 fn test_if_else_evidence_join() {
3733 assert!(check(
3735 r#"
3736 fn main() {
3737 let known_val: i64! = 1;
3738 let reported_val: i64~ = 2;
3739 let cond: bool = true;
3740 // Result should have ~ evidence (join of ! and ~)
3741 let result = if cond { known_val } else { reported_val };
3742 }
3743 "#
3744 )
3745 .is_ok());
3746 }
3747
3748 #[test]
3749 fn test_binary_op_evidence_propagation() {
3750 assert!(check(
3752 r#"
3753 fn main() {
3754 let known: i64! = 1;
3755 let reported: i64~ = 2;
3756 // Result should have ~ evidence (max of ! and ~)
3757 let result = known + reported;
3758 }
3759 "#
3760 )
3761 .is_ok());
3762 }
3763
3764 #[test]
3765 fn test_match_evidence_join() {
3766 assert!(check(
3769 r#"
3770 fn main() {
3771 let x: i64 = 1;
3772 }
3773 "#
3774 )
3775 .is_ok());
3776 }
3777}