1use crate::ast::*;
8use crate::span::Span;
9use std::cell::RefCell;
10use std::collections::HashMap;
11use std::fmt;
12use std::rc::Rc;
13
14#[derive(Debug, Clone, PartialEq)]
16pub enum Type {
17 Unit,
19 Bool,
20 Int(IntSize),
21 Float(FloatSize),
22 Char,
23 Str,
24
25 Array {
27 element: Box<Type>,
28 size: Option<usize>,
29 },
30 Slice(Box<Type>),
31 Tuple(Vec<Type>),
32
33 Named {
35 name: String,
36 generics: Vec<Type>,
37 },
38
39 Function {
41 params: Vec<Type>,
42 return_type: Box<Type>,
43 is_async: bool,
44 },
45
46 Ref {
48 lifetime: Option<String>,
49 mutable: bool,
50 inner: Box<Type>,
51 },
52 Ptr {
53 mutable: bool,
54 inner: Box<Type>,
55 },
56
57 Evidential {
59 inner: Box<Type>,
60 evidence: EvidenceLevel,
61 },
62
63 Cycle {
65 modulus: usize,
66 },
67
68 Simd {
70 element: Box<Type>,
71 lanes: u8,
72 },
73
74 Atomic(Box<Type>),
76
77 Var(TypeVar),
79
80 Error,
82
83 Never,
85
86 Lifetime(String),
88
89 TraitObject(Vec<Type>),
91
92 Hrtb {
94 lifetimes: Vec<String>,
95 bound: Box<Type>,
96 },
97 InlineStruct {
99 fields: Vec<(String, Type)>,
100 },
101 ImplTrait(Vec<Type>),
103 InlineEnum(Vec<String>),
105 AssocTypeBinding { name: String, ty: Box<Type> },
107
108 Linear(Box<Type>),
110
111 Affine(Box<Type>),
113
114 Relevant(Box<Type>),
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub enum IntSize {
121 I8,
122 I16,
123 I32,
124 I64,
125 I128,
126 U8,
127 U16,
128 U32,
129 U64,
130 U128,
131 ISize,
132 USize,
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub enum FloatSize {
138 F32,
139 F64,
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
150pub enum EvidenceLevel {
151 Known, Uncertain, Reported, Paradox, }
160
161impl EvidenceLevel {
162 pub fn join(self, other: Self) -> Self {
164 std::cmp::max(self, other)
165 }
166
167 pub fn meet(self, other: Self) -> Self {
169 std::cmp::min(self, other)
170 }
171
172 pub fn from_ast(e: Evidentiality) -> Self {
174 match e {
175 Evidentiality::Known => EvidenceLevel::Known,
176 Evidentiality::Uncertain | Evidentiality::Predicted => EvidenceLevel::Uncertain,
177 Evidentiality::Reported => EvidenceLevel::Reported,
178 Evidentiality::Paradox => EvidenceLevel::Paradox,
179 }
180 }
181
182 pub fn symbol(&self) -> &'static str {
184 match self {
185 EvidenceLevel::Known => "!",
186 EvidenceLevel::Uncertain => "?",
187 EvidenceLevel::Reported => "~",
188 EvidenceLevel::Paradox => "‽",
189 }
190 }
191
192 pub fn name(&self) -> &'static str {
194 match self {
195 EvidenceLevel::Known => "known",
196 EvidenceLevel::Uncertain => "uncertain",
197 EvidenceLevel::Reported => "reported",
198 EvidenceLevel::Paradox => "paradox",
199 }
200 }
201
202 pub fn satisfies(self, required: Self) -> bool {
210 self <= required
213 }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
218pub struct TypeVar(pub u32);
219
220#[derive(Debug, Clone)]
222pub enum TypeErrorKind {
223 Mismatch {
225 expected: String,
226 actual: String,
227 context: Option<String>,
228 },
229 Undefined {
231 name: String,
232 kind: &'static str, },
234 MissingImpl {
236 type_name: String,
237 trait_name: String,
238 },
239 InvalidOperation {
241 operation: String,
242 type_name: String,
243 },
244 Generic {
246 message: String,
247 },
248}
249
250#[derive(Debug, Clone)]
252pub struct TypeError {
253 pub kind: TypeErrorKind,
254 pub message: String,
255 pub span: Option<Span>,
256 pub notes: Vec<String>,
257 pub help: Option<String>,
258}
259
260impl TypeError {
261 pub fn new(message: impl Into<String>) -> Self {
262 let msg = message.into();
263 Self {
264 kind: TypeErrorKind::Generic { message: msg.clone() },
265 message: msg,
266 span: None,
267 notes: Vec::new(),
268 help: None,
269 }
270 }
271
272 pub fn mismatch(expected: impl Into<String>, actual: impl Into<String>) -> Self {
274 let exp = expected.into();
275 let act = actual.into();
276 let msg = format!("expected `{}`, found `{}`", exp, act);
277 Self {
278 kind: TypeErrorKind::Mismatch {
279 expected: exp,
280 actual: act,
281 context: None,
282 },
283 message: msg,
284 span: None,
285 notes: Vec::new(),
286 help: None,
287 }
288 }
289
290 pub fn undefined(name: impl Into<String>, kind: &'static str) -> Self {
292 let n = name.into();
293 let msg = format!("cannot find {} `{}` in this scope", kind, n);
294 Self {
295 kind: TypeErrorKind::Undefined { name: n, kind },
296 message: msg,
297 span: None,
298 notes: Vec::new(),
299 help: None,
300 }
301 }
302
303 pub fn missing_impl(type_name: impl Into<String>, trait_name: impl Into<String>) -> Self {
305 let t = type_name.into();
306 let tr = trait_name.into();
307 let msg = format!("the trait `{}` is not implemented for `{}`", tr, t);
308 Self {
309 kind: TypeErrorKind::MissingImpl {
310 type_name: t,
311 trait_name: tr,
312 },
313 message: msg,
314 span: None,
315 notes: Vec::new(),
316 help: None,
317 }
318 }
319
320 pub fn invalid_op(operation: impl Into<String>, type_name: impl Into<String>) -> Self {
322 let op = operation.into();
323 let ty = type_name.into();
324 let msg = format!("cannot {} type `{}`", op, ty);
325 Self {
326 kind: TypeErrorKind::InvalidOperation {
327 operation: op,
328 type_name: ty,
329 },
330 message: msg,
331 span: None,
332 notes: Vec::new(),
333 help: None,
334 }
335 }
336
337 pub fn with_span(mut self, span: Span) -> Self {
338 self.span = Some(span);
339 self
340 }
341
342 pub fn with_note(mut self, note: impl Into<String>) -> Self {
343 self.notes.push(note.into());
344 self
345 }
346
347 pub fn with_help(mut self, help: impl Into<String>) -> Self {
348 self.help = Some(help.into());
349 self
350 }
351
352 pub fn code(&self) -> &'static str {
354 match &self.kind {
355 TypeErrorKind::Mismatch { .. } => "T001",
356 TypeErrorKind::Undefined { .. } => "T002",
357 TypeErrorKind::MissingImpl { .. } => "T003",
358 TypeErrorKind::InvalidOperation { .. } => "T004",
359 TypeErrorKind::Generic { .. } => "T000",
360 }
361 }
362}
363
364impl fmt::Display for TypeError {
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 write!(f, "error[{}]: {}", self.code(), self.message)?;
367 if let Some(span) = self.span {
368 write!(f, "\n --> at {}", span)?;
369 }
370 for note in &self.notes {
371 write!(f, "\n note: {}", note)?;
372 }
373 if let Some(help) = &self.help {
374 write!(f, "\n help: {}", help)?;
375 }
376 Ok(())
377 }
378}
379
380#[derive(Debug, Clone)]
382pub struct TypeEnv {
383 bindings: HashMap<String, (Type, EvidenceLevel)>,
385 parent: Option<Rc<RefCell<TypeEnv>>>,
387 consumed_linear: std::collections::HashSet<String>,
389}
390
391impl TypeEnv {
392 pub fn new() -> Self {
393 Self {
394 bindings: HashMap::new(),
395 parent: None,
396 consumed_linear: std::collections::HashSet::new(),
397 }
398 }
399
400 pub fn with_parent(parent: Rc<RefCell<TypeEnv>>) -> Self {
401 Self {
402 bindings: HashMap::new(),
403 parent: Some(parent),
404 consumed_linear: std::collections::HashSet::new(),
405 }
406 }
407
408 pub fn define(&mut self, name: String, ty: Type, evidence: EvidenceLevel) {
410 self.bindings.insert(name, (ty, evidence));
411 }
412
413 pub fn lookup(&self, name: &str) -> Option<(Type, EvidenceLevel)> {
415 if let Some(binding) = self.bindings.get(name) {
416 Some(binding.clone())
417 } else if let Some(ref parent) = self.parent {
418 parent.borrow().lookup(name)
419 } else {
420 None
421 }
422 }
423
424 pub fn is_linear(&self, name: &str) -> bool {
426 if let Some((ty, _)) = self.lookup(name) {
427 matches!(ty, Type::Linear(_))
428 } else {
429 false
430 }
431 }
432
433 pub fn is_consumed(&self, name: &str) -> bool {
435 if self.consumed_linear.contains(name) {
436 return true;
437 }
438 if let Some(ref parent) = self.parent {
439 return parent.borrow().is_consumed(name);
440 }
441 false
442 }
443
444 pub fn consume(&mut self, name: &str) {
446 self.consumed_linear.insert(name.to_string());
447 }
448
449 pub fn get_unconsumed_linear_vars(&self) -> Vec<String> {
451 self.bindings
452 .iter()
453 .filter(|(name, (ty, _))| {
454 matches!(ty, Type::Linear(_)) && !self.consumed_linear.contains(*name)
455 })
456 .map(|(name, _)| name.clone())
457 .collect()
458 }
459}
460
461impl Default for TypeEnv {
462 fn default() -> Self {
463 Self::new()
464 }
465}
466
467#[derive(Debug, Clone)]
469pub enum TypeDef {
470 Struct {
471 generics: Vec<String>,
472 fields: Vec<(String, Type)>,
473 },
474 Enum {
475 generics: Vec<String>,
476 variants: Vec<(String, Option<Vec<Type>>)>,
477 },
478 Alias {
479 generics: Vec<String>,
480 target: Type,
481 },
482}
483
484pub struct TypeChecker {
486 env: Rc<RefCell<TypeEnv>>,
488 types: HashMap<String, TypeDef>,
490 functions: HashMap<String, Type>,
492 stdlib_functions: std::collections::HashSet<String>,
494 impl_methods: HashMap<String, HashMap<String, Type>>,
496 current_self_type: Option<Type>,
498 current_generics: HashMap<String, Type>,
500 expected_return_type: Option<Type>,
502 next_var: u32,
504 substitutions: HashMap<TypeVar, Type>,
506 errors: Vec<TypeError>,
508 current_item_span: Span,
510}
511
512impl TypeChecker {
513 pub fn new() -> Self {
514 let mut checker = Self {
515 env: Rc::new(RefCell::new(TypeEnv::new())),
516 types: HashMap::new(),
517 functions: HashMap::new(),
518 stdlib_functions: std::collections::HashSet::new(),
519 impl_methods: HashMap::new(),
520 current_self_type: None,
521 current_generics: HashMap::new(),
522 expected_return_type: None,
523 next_var: 0,
524 substitutions: HashMap::new(),
525 errors: Vec::new(),
526 current_item_span: Span::default(),
527 };
528
529 checker.register_builtins();
531 checker
532 }
533
534 fn add_stdlib_fn(&mut self, name: &str, fn_type: Type) {
536 self.functions.insert(name.to_string(), fn_type);
537 self.stdlib_functions.insert(name.to_string());
538 }
539
540 fn register_builtins(&mut self) {
541 let func = |params: Vec<Type>, ret: Type| Type::Function {
543 params,
544 return_type: Box::new(ret),
545 is_async: false,
546 };
547
548 let any = Type::Var(TypeVar(9999)); self.functions
556 .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
557 self.functions
558 .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
559 self.functions
560 .insert("input".to_string(), func(vec![], Type::Str));
561 self.functions
562 .insert("input_line".to_string(), func(vec![], Type::Str));
563
564 self.functions
568 .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
569 self.functions.insert(
570 "len".to_string(),
571 func(vec![any.clone()], Type::Int(IntSize::USize)),
572 );
573
574 self.functions
578 .insert("str".to_string(), func(vec![any.clone()], Type::Str));
579 self.functions
580 .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
581 self.functions
582 .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
583 self.functions
584 .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
585 self.functions.insert(
586 "split".to_string(),
587 func(
588 vec![Type::Str, Type::Str],
589 Type::Array {
590 element: Box::new(Type::Str),
591 size: None,
592 },
593 ),
594 );
595 self.functions.insert(
596 "join".to_string(),
597 func(
598 vec![
599 Type::Array {
600 element: Box::new(Type::Str),
601 size: None,
602 },
603 Type::Str,
604 ],
605 Type::Str,
606 ),
607 );
608 self.functions.insert(
609 "contains".to_string(),
610 func(vec![Type::Str, Type::Str], Type::Bool),
611 );
612 self.functions.insert(
613 "starts_with".to_string(),
614 func(vec![Type::Str, Type::Str], Type::Bool),
615 );
616 self.functions.insert(
617 "ends_with".to_string(),
618 func(vec![Type::Str, Type::Str], Type::Bool),
619 );
620 self.functions.insert(
621 "replace".to_string(),
622 func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
623 );
624 self.functions.insert(
625 "char_at".to_string(),
626 func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
627 );
628 self.functions.insert(
629 "substring".to_string(),
630 func(
631 vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
632 Type::Str,
633 ),
634 );
635
636 let f64_ty = Type::Float(FloatSize::F64);
640 let i64_ty = Type::Int(IntSize::I64);
641
642 self.functions.insert(
643 "abs".to_string(),
644 func(vec![f64_ty.clone()], f64_ty.clone()),
645 );
646 self.functions.insert(
647 "sqrt".to_string(),
648 func(vec![f64_ty.clone()], f64_ty.clone()),
649 );
650 self.functions.insert(
651 "sin".to_string(),
652 func(vec![f64_ty.clone()], f64_ty.clone()),
653 );
654 self.functions.insert(
655 "cos".to_string(),
656 func(vec![f64_ty.clone()], f64_ty.clone()),
657 );
658 self.functions.insert(
659 "tan".to_string(),
660 func(vec![f64_ty.clone()], f64_ty.clone()),
661 );
662 self.functions.insert(
663 "floor".to_string(),
664 func(vec![f64_ty.clone()], f64_ty.clone()),
665 );
666 self.functions.insert(
667 "ceil".to_string(),
668 func(vec![f64_ty.clone()], f64_ty.clone()),
669 );
670 self.functions.insert(
671 "round".to_string(),
672 func(vec![f64_ty.clone()], f64_ty.clone()),
673 );
674 self.functions.insert(
675 "pow".to_string(),
676 func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
677 );
678 self.functions.insert(
679 "log".to_string(),
680 func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()), );
682 self.functions.insert(
683 "log10".to_string(),
684 func(vec![f64_ty.clone()], f64_ty.clone()),
685 );
686 self.functions.insert(
687 "log2".to_string(),
688 func(vec![f64_ty.clone()], f64_ty.clone()),
689 );
690 self.functions.insert(
691 "ln".to_string(),
692 func(vec![f64_ty.clone()], f64_ty.clone()),
693 );
694 self.functions.insert(
695 "exp".to_string(),
696 func(vec![f64_ty.clone()], f64_ty.clone()),
697 );
698 self.functions.insert(
699 "min".to_string(),
700 func(vec![any.clone(), any.clone()], any.clone()),
701 );
702 self.functions.insert(
703 "max".to_string(),
704 func(vec![any.clone(), any.clone()], any.clone()),
705 );
706
707 self.functions
711 .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
712 self.functions
713 .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
714 self.functions.insert(
715 "push".to_string(),
716 func(vec![any.clone(), any.clone()], Type::Unit),
717 );
718 self.functions
719 .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
720 self.functions
721 .insert("first".to_string(), func(vec![any.clone()], any.clone()));
722 self.functions
723 .insert("last".to_string(), func(vec![any.clone()], any.clone()));
724 self.functions
725 .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
726 self.functions
727 .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
728 self.functions.insert(
729 "range".to_string(),
730 func(
731 vec![i64_ty.clone(), i64_ty.clone()],
732 Type::Array {
733 element: Box::new(i64_ty.clone()),
734 size: None,
735 },
736 ),
737 );
738
739 self.functions
743 .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
744 self.functions.insert(
745 "assert_eq".to_string(),
746 func(vec![any.clone(), any.clone()], Type::Unit),
747 );
748 self.functions.insert(
749 "assert_ne".to_string(),
750 func(vec![any.clone(), any.clone()], Type::Unit),
751 );
752 self.functions.insert(
753 "assert_lt".to_string(),
754 func(vec![any.clone(), any.clone()], Type::Unit),
755 );
756 self.functions.insert(
757 "assert_le".to_string(),
758 func(vec![any.clone(), any.clone()], Type::Unit),
759 );
760 self.functions.insert(
761 "assert_gt".to_string(),
762 func(vec![any.clone(), any.clone()], Type::Unit),
763 );
764 self.functions.insert(
765 "assert_ge".to_string(),
766 func(vec![any.clone(), any.clone()], Type::Unit),
767 );
768 self.functions.insert(
769 "assert_true".to_string(),
770 func(vec![Type::Bool], Type::Unit),
771 );
772 self.functions.insert(
773 "assert_false".to_string(),
774 func(vec![Type::Bool], Type::Unit),
775 );
776 self.functions.insert(
777 "assert_null".to_string(),
778 func(vec![any.clone()], Type::Unit),
779 );
780 self.functions.insert(
781 "assert_not_null".to_string(),
782 func(vec![any.clone()], Type::Unit),
783 );
784 self.functions.insert(
785 "assert_contains".to_string(),
786 func(vec![any.clone(), any.clone()], Type::Unit),
787 );
788 self.functions.insert(
789 "assert_len".to_string(),
790 func(vec![any.clone(), i64_ty.clone()], Type::Unit),
791 );
792
793 self.functions
797 .insert("random".to_string(), func(vec![], f64_ty.clone()));
798 self.functions.insert(
799 "random_int".to_string(),
800 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
801 );
802 self.functions
803 .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
804
805 self.functions
809 .insert("now".to_string(), func(vec![], f64_ty.clone()));
810 self.functions
811 .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
812
813 self.functions
817 .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
818 self.functions
819 .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
820 self.functions
821 .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
822
823 self.functions
827 .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
828 self.functions
829 .insert("todo".to_string(), func(vec![], Type::Never));
830 self.functions
831 .insert("unreachable".to_string(), func(vec![], Type::Never));
832
833 self.functions.insert(
838 "known".to_string(),
839 func(
840 vec![any.clone()],
841 Type::Evidential {
842 inner: Box::new(any.clone()),
843 evidence: EvidenceLevel::Known,
844 },
845 ),
846 );
847 self.functions.insert(
849 "uncertain".to_string(),
850 func(
851 vec![any.clone()],
852 Type::Evidential {
853 inner: Box::new(any.clone()),
854 evidence: EvidenceLevel::Uncertain,
855 },
856 ),
857 );
858 self.functions.insert(
860 "reported".to_string(),
861 func(
862 vec![any.clone()],
863 Type::Evidential {
864 inner: Box::new(any.clone()),
865 evidence: EvidenceLevel::Reported,
866 },
867 ),
868 );
869 self.functions.insert(
871 "evidence_of".to_string(),
872 func(vec![any.clone()], Type::Str),
873 );
874 self.functions.insert(
876 "validate".to_string(),
877 func(
878 vec![any.clone()],
879 Type::Evidential {
880 inner: Box::new(any.clone()),
881 evidence: EvidenceLevel::Uncertain,
882 },
883 ),
884 );
885 self.functions.insert(
887 "verify".to_string(),
888 func(
889 vec![any.clone()],
890 Type::Evidential {
891 inner: Box::new(any.clone()),
892 evidence: EvidenceLevel::Known,
893 },
894 ),
895 );
896
897 self.functions.insert(
902 "freq".to_string(),
903 func(vec![i64_ty.clone()], f64_ty.clone()),
904 );
905 self.functions.insert(
907 "octave".to_string(),
908 func(vec![i64_ty.clone()], i64_ty.clone()),
909 );
910 self.functions.insert(
912 "pitch_class".to_string(),
913 func(vec![i64_ty.clone()], i64_ty.clone()),
914 );
915 self.functions.insert(
917 "mod_cycle".to_string(),
918 func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
919 );
920
921 self.stdlib_functions = self.functions.keys().cloned().collect();
923 }
924
925 fn fresh_var(&mut self) -> Type {
927 let var = TypeVar(self.next_var);
928 self.next_var += 1;
929 Type::Var(var)
930 }
931
932 fn type_contains_var(&self, ty: &Type) -> bool {
934 match ty {
935 Type::Var(v) => !self.substitutions.contains_key(v),
936 Type::Array { element, .. } => self.type_contains_var(element.as_ref()),
937 Type::Slice(inner) => self.type_contains_var(inner.as_ref()),
938 Type::Tuple(elems) => elems.iter().any(|e| self.type_contains_var(e)),
939 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.type_contains_var(inner.as_ref()),
940 Type::Function { params, return_type, .. } => {
941 params.iter().any(|p| self.type_contains_var(p)) || self.type_contains_var(return_type.as_ref())
942 }
943 Type::Named { generics, .. } => generics.iter().any(|g| self.type_contains_var(g)),
944 Type::ImplTrait(bounds) => bounds.iter().any(|b| self.type_contains_var(b)),
945 Type::Evidential { inner, .. } => self.type_contains_var(inner.as_ref()),
946 Type::Atomic(inner) => self.type_contains_var(inner.as_ref()),
947 Type::Simd { element, .. } => self.type_contains_var(element.as_ref()),
948 _ => false,
949 }
950 }
951
952 fn occurs_in(&self, v: &TypeVar, t: &Type) -> bool {
955 match t {
956 Type::Var(w) => {
957 if v == w {
958 return true;
959 }
960 if let Some(resolved) = self.substitutions.get(w) {
961 self.occurs_in(v, resolved)
962 } else {
963 false
964 }
965 }
966 Type::Array { element, .. } => self.occurs_in(v, element),
967 Type::Slice(inner) => self.occurs_in(v, inner),
968 Type::Tuple(elems) => elems.iter().any(|e| self.occurs_in(v, e)),
969 Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.occurs_in(v, inner),
970 Type::Function { params, return_type, .. } => {
971 params.iter().any(|p| self.occurs_in(v, p)) || self.occurs_in(v, return_type)
972 }
973 Type::Named { generics, .. } => generics.iter().any(|g| self.occurs_in(v, g)),
974 Type::ImplTrait(bounds) => bounds.iter().any(|b| self.occurs_in(v, b)),
975 Type::Evidential { inner, .. } => self.occurs_in(v, inner),
976 Type::Atomic(inner) => self.occurs_in(v, inner),
977 Type::Simd { element, .. } => self.occurs_in(v, element),
978 _ => false,
979 }
980 }
981
982 fn freshen(&mut self, ty: &Type) -> Type {
985 let mut mapping = std::collections::HashMap::new();
986 self.freshen_inner(ty, &mut mapping)
987 }
988
989 fn freshen_inner(
990 &mut self,
991 ty: &Type,
992 mapping: &mut std::collections::HashMap<u32, Type>,
993 ) -> Type {
994 match ty {
995 Type::Var(TypeVar(id)) => {
996 if let Some(fresh) = mapping.get(id) {
997 fresh.clone()
998 } else {
999 let fresh = self.fresh_var();
1000 mapping.insert(*id, fresh.clone());
1001 fresh
1002 }
1003 }
1004 Type::Array { element, size } => Type::Array {
1005 element: Box::new(self.freshen_inner(element, mapping)),
1006 size: *size,
1007 },
1008 Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
1009 Type::Ref { lifetime, mutable, inner } => Type::Ref {
1010 lifetime: lifetime.clone(),
1011 mutable: *mutable,
1012 inner: Box::new(self.freshen_inner(inner, mapping)),
1013 },
1014 Type::Tuple(elems) => Type::Tuple(
1015 elems
1016 .iter()
1017 .map(|e| self.freshen_inner(e, mapping))
1018 .collect(),
1019 ),
1020 Type::Function {
1021 params,
1022 return_type,
1023 is_async,
1024 } => Type::Function {
1025 params: params
1026 .iter()
1027 .map(|p| self.freshen_inner(p, mapping))
1028 .collect(),
1029 return_type: Box::new(self.freshen_inner(return_type, mapping)),
1030 is_async: *is_async,
1031 },
1032 Type::Evidential { inner, evidence } => Type::Evidential {
1033 inner: Box::new(self.freshen_inner(inner, mapping)),
1034 evidence: *evidence,
1035 },
1036 Type::Named { name, generics } => Type::Named {
1037 name: name.clone(),
1038 generics: generics
1039 .iter()
1040 .map(|g| self.freshen_inner(g, mapping))
1041 .collect(),
1042 },
1043 _ => ty.clone(),
1045 }
1046 }
1047
1048 fn push_scope(&mut self) {
1050 let new_env = TypeEnv::with_parent(self.env.clone());
1051 self.env = Rc::new(RefCell::new(new_env));
1052 }
1053
1054 fn pop_scope(&mut self) {
1056 let parent = self.env.borrow().parent.clone();
1057 if let Some(p) = parent {
1058 self.env = p;
1059 }
1060 }
1061
1062 fn error(&mut self, mut err: TypeError) {
1064 if err.span.is_none() && !self.current_item_span.is_empty() {
1065 err.span = Some(self.current_item_span);
1066 }
1067 self.errors.push(err);
1068 }
1069
1070 fn check_evidence(
1073 &mut self,
1074 expected: EvidenceLevel,
1075 actual: EvidenceLevel,
1076 context: &str,
1077 ) -> bool {
1078 if actual.satisfies(expected) {
1079 true
1080 } else {
1081 let mut err = TypeError::new(format!(
1082 "evidence mismatch {}: expected {} ({}), found {} ({})",
1083 context,
1084 expected.name(),
1085 expected.symbol(),
1086 actual.name(),
1087 actual.symbol(),
1088 ));
1089
1090 match (expected, actual) {
1092 (EvidenceLevel::Known, EvidenceLevel::Reported) => {
1093 err = err.with_note(
1094 "reported data (~) cannot be used where known data (!) is required",
1095 );
1096 err = err.with_note(
1097 "help: use |validate!{...} to verify and promote evidence level",
1098 );
1099 }
1100 (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
1101 err = err.with_note(
1102 "uncertain data (?) cannot be used where known data (!) is required",
1103 );
1104 err = err.with_note(
1105 "help: use pattern matching or unwrap to handle the uncertainty",
1106 );
1107 }
1108 (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
1109 err = err.with_note(
1110 "reported data (~) cannot be used where uncertain data (?) is required",
1111 );
1112 err = err.with_note("help: use |validate?{...} to verify external data");
1113 }
1114 _ => {
1115 err = err.with_note(format!(
1116 "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
1117 ));
1118 }
1119 }
1120
1121 self.error(err);
1122 false
1123 }
1124 }
1125
1126 fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
1128 match ty {
1129 Type::Evidential { evidence, .. } => *evidence,
1130 _ => EvidenceLevel::Known,
1131 }
1132 }
1133
1134 pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
1136 for item in &file.items {
1138 self.collect_type_def(&item.node);
1139 }
1140
1141 for item in &file.items {
1143 self.collect_fn_sig(&item.node);
1144 }
1145
1146 for item in &file.items {
1148 self.current_item_span = item.span;
1149 self.check_item(&item.node);
1150 }
1151
1152 if self.errors.is_empty() {
1153 Ok(())
1154 } else {
1155 Err(std::mem::take(&mut self.errors))
1156 }
1157 }
1158
1159 fn collect_type_def(&mut self, item: &Item) {
1161 match item {
1162 Item::Struct(s) => {
1163 let generics = s
1164 .generics
1165 .as_ref()
1166 .map(|g| {
1167 g.params
1168 .iter()
1169 .filter_map(|p| {
1170 if let GenericParam::Type { name, .. } = p {
1171 Some(name.name.clone())
1172 } else {
1173 None
1174 }
1175 })
1176 .collect()
1177 })
1178 .unwrap_or_default();
1179
1180 let fields = match &s.fields {
1181 StructFields::Named(fs) => fs
1182 .iter()
1183 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
1184 .collect(),
1185 StructFields::Tuple(ts) => ts
1186 .iter()
1187 .enumerate()
1188 .map(|(i, t)| (i.to_string(), self.convert_type(t)))
1189 .collect(),
1190 StructFields::Unit => vec![],
1191 };
1192
1193 if self.types.contains_key(&s.name.name) {
1195 self.error(TypeError::new(format!(
1196 "duplicate type definition: '{}'",
1197 s.name.name
1198 )));
1199 }
1200 self.types
1201 .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
1202 }
1203 Item::Enum(e) => {
1204 let generics = e
1205 .generics
1206 .as_ref()
1207 .map(|g| {
1208 g.params
1209 .iter()
1210 .filter_map(|p| {
1211 if let GenericParam::Type { name, .. } = p {
1212 Some(name.name.clone())
1213 } else {
1214 None
1215 }
1216 })
1217 .collect()
1218 })
1219 .unwrap_or_default();
1220
1221 let variants = e
1222 .variants
1223 .iter()
1224 .map(|v| {
1225 let fields = match &v.fields {
1226 StructFields::Tuple(ts) => {
1227 Some(ts.iter().map(|t| self.convert_type(t)).collect())
1228 }
1229 StructFields::Named(fs) => {
1230 Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
1231 }
1232 StructFields::Unit => None,
1233 };
1234 (v.name.name.clone(), fields)
1235 })
1236 .collect();
1237
1238 self.types
1239 .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
1240 }
1241 Item::TypeAlias(t) => {
1242 let generics = t
1243 .generics
1244 .as_ref()
1245 .map(|g| {
1246 g.params
1247 .iter()
1248 .filter_map(|p| {
1249 if let GenericParam::Type { name, .. } = p {
1250 Some(name.name.clone())
1251 } else {
1252 None
1253 }
1254 })
1255 .collect()
1256 })
1257 .unwrap_or_default();
1258
1259 let target = self.convert_type(&t.ty);
1260 self.types
1261 .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
1262 }
1263 _ => {}
1264 }
1265 }
1266
1267 fn collect_fn_sig(&mut self, item: &Item) {
1269 match item {
1270 Item::Function(f) => {
1271 if let Some(ref generics) = f.generics {
1273 for param in &generics.params {
1274 if let crate::ast::GenericParam::Type { name, .. } = param {
1275 let type_var = self.fresh_var();
1276 self.current_generics.insert(name.name.clone(), type_var);
1277 }
1278 }
1279 }
1280
1281 let params: Vec<Type> = f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1282
1283 let return_type = f
1284 .return_type
1285 .as_ref()
1286 .map(|t| self.convert_type(t))
1287 .unwrap_or(Type::Unit);
1288
1289 let fn_type = Type::Function {
1290 params,
1291 return_type: Box::new(return_type),
1292 is_async: f.is_async,
1293 };
1294
1295 if self.functions.contains_key(&f.name.name)
1297 && !self.stdlib_functions.contains(&f.name.name)
1298 {
1299 self.error(TypeError::new(format!(
1300 "duplicate function definition: '{}'",
1301 f.name.name
1302 )));
1303 }
1304 self.functions.insert(f.name.name.clone(), fn_type);
1305
1306 self.current_generics.clear();
1308 }
1309 Item::Impl(impl_block) => {
1310 let type_name = self.type_path_to_name(&impl_block.self_ty);
1312
1313 let mut generic_types = Vec::new();
1316 if let Some(ref generics) = impl_block.generics {
1317 for param in &generics.params {
1318 if let crate::ast::GenericParam::Type { name, .. } = param {
1319 let type_var = self.fresh_var();
1320 self.current_generics.insert(name.name.clone(), type_var.clone());
1321 generic_types.push(type_var);
1322 }
1323 }
1324 }
1325
1326 self.current_self_type = Some(Type::Named {
1328 name: type_name.clone(),
1329 generics: generic_types,
1330 });
1331
1332 for impl_item in &impl_block.items {
1334 if let crate::ast::ImplItem::Function(f) = impl_item {
1335 let params: Vec<Type> =
1336 f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1337
1338 let return_type = f
1339 .return_type
1340 .as_ref()
1341 .map(|t| self.convert_type(t))
1342 .unwrap_or(Type::Unit);
1343
1344 let fn_type = Type::Function {
1345 params,
1346 return_type: Box::new(return_type),
1347 is_async: f.is_async,
1348 };
1349
1350 self.impl_methods
1352 .entry(type_name.clone())
1353 .or_insert_with(HashMap::new)
1354 .insert(f.name.name.clone(), fn_type);
1355 }
1356 }
1357
1358 self.current_self_type = None;
1360 self.current_generics.clear();
1361 }
1362 _ => {}
1363 }
1364 }
1365
1366 fn type_path_to_name(&self, ty: &crate::ast::TypeExpr) -> String {
1368 match ty {
1369 crate::ast::TypeExpr::Path(path) => {
1370 path.segments
1371 .iter()
1372 .map(|s| s.ident.name.clone())
1373 .collect::<Vec<_>>()
1374 .join("::")
1375 }
1376 _ => "Unknown".to_string(),
1377 }
1378 }
1379
1380 fn check_item(&mut self, item: &Item) {
1382 match item {
1383 Item::Function(f) => self.check_function(f),
1384 Item::Const(c) => {
1385 let declared = self.convert_type(&c.ty);
1386 let inferred = self.infer_expr(&c.value);
1387 if !self.unify(&declared, &inferred) {
1388 self.error(
1389 TypeError::new(format!(
1390 "type mismatch in const '{}': expected {:?}, found {:?}",
1391 c.name.name, declared, inferred
1392 ))
1393 .with_span(c.name.span),
1394 );
1395 }
1396 }
1397 Item::Static(s) => {
1398 let declared = self.convert_type(&s.ty);
1399 let inferred = self.infer_expr(&s.value);
1400 if !self.unify(&declared, &inferred) {
1401 self.error(
1402 TypeError::new(format!(
1403 "type mismatch in static '{}': expected {:?}, found {:?}",
1404 s.name.name, declared, inferred
1405 ))
1406 .with_span(s.name.span),
1407 );
1408 }
1409 }
1410 Item::Impl(impl_block) => {
1411 let type_name = self.type_path_to_name(&impl_block.self_ty);
1413
1414 let mut generic_types = Vec::new();
1417 if let Some(ref generics) = impl_block.generics {
1418 for param in &generics.params {
1419 if let crate::ast::GenericParam::Type { name, .. } = param {
1420 let type_var = self.fresh_var();
1421 self.current_generics.insert(name.name.clone(), type_var.clone());
1422 generic_types.push(type_var);
1423 }
1424 }
1425 }
1426
1427 self.current_self_type = Some(Type::Named {
1429 name: type_name,
1430 generics: generic_types,
1431 });
1432
1433 for impl_item in &impl_block.items {
1435 if let crate::ast::ImplItem::Function(f) = impl_item {
1436 self.check_function(f);
1437 }
1438 }
1439
1440 self.current_self_type = None;
1442 self.current_generics.clear();
1443 }
1444 _ => {}
1445 }
1446 }
1447
1448 fn check_function(&mut self, func: &Function) {
1450 self.push_scope();
1451
1452 if let Some(ref generics) = func.generics {
1454 for param in &generics.params {
1455 if let crate::ast::GenericParam::Type { name, .. } = param {
1456 let type_var = self.fresh_var();
1457 self.current_generics.insert(name.name.clone(), type_var);
1458 }
1459 }
1460 }
1461
1462 for param in &func.params {
1464 let ty = self.convert_type(¶m.ty);
1465 let type_evidence = self.get_evidence(&ty);
1468 let evidence = param
1469 .pattern
1470 .evidentiality()
1471 .map(EvidenceLevel::from_ast)
1472 .unwrap_or(type_evidence);
1473
1474 if let Some(name) = param.pattern.binding_name() {
1475 self.env.borrow_mut().define(name, ty, evidence);
1476 }
1477 }
1478
1479 let expected_return = func
1481 .return_type
1482 .as_ref()
1483 .map(|t| self.convert_type(t))
1484 .unwrap_or(Type::Unit);
1485 let old_return_type = self.expected_return_type.clone();
1486 self.expected_return_type = Some(expected_return.clone());
1487
1488 if let Some(ref body) = func.body {
1490 let body_type = self.check_block(body);
1491
1492 self.expected_return_type = old_return_type;
1494
1495 let expected_return = func
1497 .return_type
1498 .as_ref()
1499 .map(|t| self.convert_type(t))
1500 .unwrap_or(Type::Unit);
1501
1502 let _ = self.unify(&expected_return, &body_type);
1506
1507 let type_has_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1513 let name_evidence = func.name.evidentiality.as_ref()
1515 .map(|e| EvidenceLevel::from_ast(*e));
1516 let has_explicit_evidence = type_has_evidence || name_evidence.is_some();
1517 let actual_evidence = self.get_evidence(&body_type);
1518
1519 if has_explicit_evidence {
1520 if name_evidence.is_none() {
1524 let expected_evidence = self.get_evidence(&expected_return);
1525 self.check_evidence(
1526 expected_evidence,
1527 actual_evidence,
1528 &format!("in return type of '{}'", func.name.name),
1529 );
1530 }
1531 } else {
1533 if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1536 self.error(
1537 TypeError::new(format!(
1538 "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1539 func.name.name,
1540 actual_evidence.name(),
1541 actual_evidence.symbol(),
1542 ))
1543 .with_span(func.name.span)
1544 .with_note("help: add explicit evidence annotation to the return type")
1545 .with_note(format!(
1546 "example: fn {}(...) -> {}{} {{ ... }}",
1547 func.name.name,
1548 expected_return,
1549 actual_evidence.symbol()
1550 )),
1551 );
1552 }
1553 }
1555 }
1556
1557 self.current_generics.clear();
1559 self.pop_scope();
1560 }
1561
1562 fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1564 match ty {
1565 Some(TypeExpr::Evidential { .. }) => true,
1566 Some(TypeExpr::Reference { inner, .. })
1567 | Some(TypeExpr::Pointer { inner, .. })
1568 | Some(TypeExpr::Slice(inner))
1569 | Some(TypeExpr::Array { element: inner, .. }) => {
1570 self.type_has_explicit_evidence(Some(inner.as_ref()))
1571 }
1572 Some(TypeExpr::Tuple(elements)) => elements
1573 .iter()
1574 .any(|e| self.type_has_explicit_evidence(Some(e))),
1575 _ => false,
1576 }
1577 }
1578
1579 fn check_block(&mut self, block: &Block) -> Type {
1581 self.push_scope();
1582
1583 let mut diverges = false;
1584 for stmt in &block.stmts {
1585 let stmt_ty = self.check_stmt(stmt);
1586 if matches!(stmt_ty, Type::Never) {
1587 diverges = true;
1588 }
1589 }
1590
1591 let result = if let Some(ref expr) = block.expr {
1592 self.infer_expr(expr)
1593 } else if diverges {
1594 Type::Never
1595 } else {
1596 Type::Unit
1597 };
1598
1599 self.pop_scope();
1600 result
1601 }
1602
1603 fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1605 match stmt {
1606 Stmt::Let { pattern, ty, init } => {
1607 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1608 let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1609
1610 let final_ty = match (&declared_ty, &init_ty) {
1611 (Some(d), Some(i)) => {
1612 if !self.unify(d, i) {
1613 let binding_name = pattern.binding_name().unwrap_or_else(|| "<pattern>".to_string());
1615
1616 let hint = match (d, i) {
1618 (Type::Slice(_), Type::Array { .. }) => {
1619 ". Hint: `[T]` is slice syntax in Sigil. \
1620 For arrays, use `[T; N]` or omit the type annotation entirely"
1621 }
1622 _ => "",
1623 };
1624
1625 let mut err = TypeError::new(format!(
1626 "type mismatch in let binding '{}': expected {:?}, found {:?}{}",
1627 binding_name, d, i, hint
1628 ));
1629 if let Some(span) = pattern.binding_span() {
1630 err = err.with_span(span);
1631 }
1632 self.error(err);
1633 }
1634 d.clone()
1635 }
1636 (Some(d), None) => d.clone(),
1637 (None, Some(i)) => i.clone(),
1638 (None, None) => self.fresh_var(),
1639 };
1640
1641 let evidence = pattern
1647 .evidentiality()
1648 .map(EvidenceLevel::from_ast)
1649 .unwrap_or_else(|| {
1650 init_ty
1652 .as_ref()
1653 .map(|ty| self.get_evidence(ty))
1654 .unwrap_or(EvidenceLevel::Known)
1655 });
1656
1657 if let Some(name) = pattern.binding_name() {
1660 self.env.borrow_mut().define(name, final_ty, evidence);
1661 } else {
1662 self.bind_pattern(pattern, &final_ty, evidence);
1663 }
1664 Type::Unit
1665 }
1666 Stmt::LetElse { pattern, ty, init, else_branch } => {
1667 let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1669 let init_ty = self.infer_expr(init);
1670 let evidence = pattern
1672 .evidentiality()
1673 .map(EvidenceLevel::from_ast)
1674 .unwrap_or_else(|| self.get_evidence(&init_ty));
1675 let final_ty = declared_ty.unwrap_or(init_ty);
1676 self.infer_expr(else_branch);
1678 if let Some(name) = pattern.binding_name() {
1681 self.env.borrow_mut().define(name, final_ty, evidence);
1682 } else {
1683 self.bind_pattern(pattern, &final_ty, evidence);
1684 }
1685 Type::Unit
1686 }
1687 Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1688 Stmt::Item(item) => {
1689 self.check_item(item);
1690 Type::Unit
1691 }
1692 }
1693 }
1694
1695 pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1697 match expr {
1698 Expr::Literal(lit) => self.infer_literal(lit),
1699
1700 Expr::Path(path) => {
1701 if path.segments.len() == 1 {
1702 let name = &path.segments[0].ident.name;
1703
1704 let lookup_result = self.env.borrow().lookup(name);
1706
1707 if let Some((ty, _)) = lookup_result {
1708 if matches!(ty, Type::Linear(_)) {
1710 let already_consumed = self.env.borrow().is_consumed(name);
1711 if already_consumed {
1712 self.error(TypeError::new(format!(
1714 "linear value '{}' used twice: linear types cannot be cloned (no-cloning theorem)",
1715 name
1716 )));
1717 } else {
1718 self.env.borrow_mut().consume(name);
1720 }
1721 }
1722 return ty;
1723 }
1724 if let Some(ty) = self.functions.get(name).cloned() {
1725 return self.freshen(&ty);
1727 }
1728 } else if path.segments.len() == 2 {
1729 let type_name = &path.segments[0].ident.name;
1731 let method_name = &path.segments[1].ident.name;
1732
1733 if let Some(methods) = self.impl_methods.get(type_name) {
1735 if let Some(ty) = methods.get(method_name) {
1736 let ty_cloned = ty.clone();
1737 return self.freshen(&ty_cloned);
1738 }
1739 }
1740
1741 if let Some(TypeDef::Enum { variants, .. }) = self.types.get(type_name) {
1743 for (variant_name, _variant_fields) in variants {
1744 if variant_name == method_name {
1745 return Type::Named {
1747 name: type_name.clone(),
1748 generics: vec![],
1749 };
1750 }
1751 }
1752 }
1753 }
1754 self.fresh_var()
1758 }
1759
1760 Expr::Binary { left, op, right } => {
1761 let lt = self.infer_expr(left);
1762 let rt = self.infer_expr(right);
1763 self.infer_binary_op(op, <, &rt)
1764 }
1765
1766 Expr::Unary { op, expr } => {
1767 let inner = self.infer_expr(expr);
1768 self.infer_unary_op(op, &inner)
1769 }
1770
1771 Expr::Call { func, args } => {
1772 let fn_type = self.infer_expr(func);
1773 let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1774
1775 if let Type::Function {
1776 params,
1777 return_type,
1778 ..
1779 } = fn_type
1780 {
1781 let func_name = match func.as_ref() {
1783 Expr::Path(path) if path.segments.len() == 1 => {
1784 Some(path.segments[0].ident.name.as_str())
1785 }
1786 _ => None,
1787 };
1788
1789 let is_variadic_builtin = func_name.map_or(false, |name| {
1793 matches!(
1794 name,
1795 "assert"
1796 | "println"
1797 | "print"
1798 | "eprintln"
1799 | "eprint"
1800 | "panic"
1801 | "todo"
1802 | "unreachable"
1803 | "format"
1804 )
1805 });
1806
1807 if is_variadic_builtin {
1810 if arg_types.len() < params.len() {
1811 self.error(TypeError::new(format!(
1812 "expected at least {} arguments, found {}",
1813 params.len(),
1814 arg_types.len()
1815 )));
1816 }
1817 } else if params.len() != arg_types.len() {
1818 self.error(TypeError::new(format!(
1819 "expected {} arguments, found {}",
1820 params.len(),
1821 arg_types.len()
1822 )));
1823 }
1824
1825 for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1827 if !self.unify(param, arg) {
1829 let is_numeric_coercion = Self::is_numeric_coercion(param, arg);
1831 let is_reference_coercion = Self::is_reference_coercion(param, arg);
1833 let is_ref_value_coercion = Self::is_ref_value_coercion(param, arg);
1835 if !matches!(param, Type::Var(_)) && !matches!(arg, Type::Var(_))
1837 && !is_numeric_coercion && !is_reference_coercion
1838 && !is_ref_value_coercion {
1839 self.error(TypeError::new(format!(
1840 "type mismatch in argument {}: expected {}, found {}",
1841 i + 1, param, arg
1842 )));
1843 }
1844 }
1845
1846 if matches!(param, Type::Evidential { .. }) {
1851 let expected_evidence = self.get_evidence(param);
1852 let actual_evidence = self.get_evidence(arg);
1853 self.check_evidence(
1854 expected_evidence,
1855 actual_evidence,
1856 &format!("in argument {}", i + 1),
1857 );
1858 }
1859 }
1860
1861 *return_type
1862 } else if let Type::Var(_) = &fn_type {
1863 let result_ty = self.fresh_var();
1866 let inferred_fn = Type::Function {
1867 params: arg_types,
1868 return_type: Box::new(result_ty.clone()),
1869 is_async: false,
1870 };
1871 self.unify(&fn_type, &inferred_fn);
1872 result_ty
1873 } else {
1874 self.fresh_var()
1876 }
1877 }
1878
1879 Expr::Array(elements) => {
1880 if elements.is_empty() {
1881 Type::Array {
1882 element: Box::new(self.fresh_var()),
1883 size: Some(0),
1884 }
1885 } else {
1886 let elem_ty = self.infer_expr(&elements[0]);
1887 for elem in &elements[1..] {
1888 let t = self.infer_expr(elem);
1889 if !self.unify(&elem_ty, &t) {
1890 self.error(TypeError::new("array elements must have same type"));
1891 }
1892 }
1893 Type::Array {
1894 element: Box::new(elem_ty),
1895 size: Some(elements.len()),
1896 }
1897 }
1898 }
1899
1900 Expr::Tuple(elements) => {
1901 Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1902 }
1903
1904 Expr::Block(block) => self.check_block(block),
1905
1906 Expr::If {
1907 condition,
1908 then_branch,
1909 else_branch,
1910 } => {
1911 let cond_ty = self.infer_expr(condition);
1912 let (bare_cond_ty, _) = self.strip_evidence(&cond_ty);
1914 if !self.unify(&Type::Bool, &bare_cond_ty) {
1915 self.error(TypeError::new("if condition must be bool"));
1916 }
1917
1918 let then_ty = self.check_block(then_branch);
1919
1920 if let Some(else_expr) = else_branch {
1921 let else_ty = match else_expr.as_ref() {
1923 Expr::Block(block) => self.check_block(block),
1924 other => self.infer_expr(other),
1925 };
1926 let _ = self.unify(&then_ty, &else_ty);
1929
1930 let then_ev = self.get_evidence(&then_ty);
1935 let else_ev = self.get_evidence(&else_ty);
1936 let joined_ev = then_ev.join(else_ev);
1937
1938 let (inner_ty, _) = self.strip_evidence(&then_ty);
1939 if joined_ev > EvidenceLevel::Known {
1940 Type::Evidential {
1941 inner: Box::new(inner_ty),
1942 evidence: joined_ev,
1943 }
1944 } else {
1945 inner_ty
1946 }
1947 } else {
1948 Type::Unit
1949 }
1950 }
1951
1952 Expr::While {
1953 condition,
1954 body,
1955 ..
1956 } => {
1957 let cond_ty = self.infer_expr(condition);
1958 let (bare_cond_ty, _) = self.strip_evidence(&cond_ty);
1959 if !self.unify(&Type::Bool, &bare_cond_ty) {
1960 self.error(TypeError::new("while condition must be bool"));
1961 }
1962 self.check_block(body);
1963 Type::Unit
1964 }
1965
1966 Expr::Loop { body, .. } => {
1967 self.check_block(body);
1968 Type::Unit
1969 }
1970
1971 Expr::For {
1972 pattern: _,
1973 iter,
1974 body,
1975 ..
1976 } => {
1977 let _ = self.infer_expr(iter);
1979 self.check_block(body);
1980 Type::Unit
1981 }
1982
1983 Expr::Pipe { expr, operations } => {
1984 let mut current = self.infer_expr(expr);
1985
1986 for op in operations {
1987 current = self.infer_pipe_op(op, ¤t);
1988 }
1989
1990 current
1991 }
1992
1993 Expr::Index { expr, index } => {
1994 let coll_ty = self.infer_expr(expr);
1995 let idx_ty = self.infer_expr(index);
1996
1997 match coll_ty {
1998 Type::Array { element, .. } | Type::Slice(element) => {
1999 if !matches!(idx_ty, Type::Int(_)) {
2000 self.error(TypeError::new("index must be integer"));
2001 }
2002 *element
2003 }
2004 _ => {
2005 self.fresh_var()
2007 }
2008 }
2009 }
2010
2011 Expr::Return(val) => {
2012 let actual_type = if let Some(e) = val {
2013 self.infer_expr(e)
2014 } else {
2015 Type::Unit
2016 };
2017
2018 if let Some(expected) = self.expected_return_type.clone() {
2020 if !self.unify(&expected, &actual_type) {
2021 self.error(TypeError::new(format!(
2022 "type mismatch in return: expected {}, found {}",
2023 expected, actual_type
2024 )));
2025 }
2026 }
2027
2028 Type::Never
2029 }
2030
2031 Expr::Evidential {
2033 expr,
2034 evidentiality,
2035 } => {
2036 let inner = self.infer_expr(expr);
2037 let ev = EvidenceLevel::from_ast(*evidentiality);
2038
2039 if ev == EvidenceLevel::Uncertain {
2042 let resolved = if let Type::Var(v) = &inner {
2043 self.substitutions.get(v).cloned().unwrap_or(inner.clone())
2044 } else {
2045 inner.clone()
2046 };
2047 let (stripped, _) = self.strip_evidence(&resolved);
2049 match &stripped {
2050 Type::Named { name, generics } if name == "Result" && !generics.is_empty() => {
2051 return generics[0].clone();
2052 }
2053 Type::Named { name, generics } if name == "Option" && !generics.is_empty() => {
2054 return generics[0].clone();
2055 }
2056 _ => {}
2057 }
2058 }
2059
2060 Type::Evidential {
2061 inner: Box::new(inner),
2062 evidence: ev,
2063 }
2064 }
2065
2066 Expr::Match { expr, arms } => {
2068 let scrutinee = self.infer_expr(expr);
2069 let scrutinee_ev = self.get_evidence(&scrutinee);
2070
2071 if arms.is_empty() {
2072 return Type::Never; }
2074
2075 let mut arm_types: Vec<Type> = Vec::new();
2077 let mut max_evidence = EvidenceLevel::Known;
2078
2079 let saved_substitutions = self.substitutions.clone();
2084
2085 for arm in arms {
2086 self.substitutions = saved_substitutions.clone();
2088 self.push_scope();
2089
2090 self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
2093
2094 if let Some(ref guard) = arm.guard {
2096 let guard_ty = self.infer_expr(guard);
2097 if !self.unify(&Type::Bool, &guard_ty) {
2098 self.error(TypeError::new("match guard must be bool"));
2099 }
2100 }
2101
2102 let body_ty = self.infer_expr(&arm.body);
2104 let body_ev = self.get_evidence(&body_ty);
2105
2106 max_evidence = max_evidence.join(body_ev);
2108 arm_types.push(body_ty);
2109
2110 self.pop_scope();
2111 }
2112
2113 self.substitutions = saved_substitutions;
2116
2117 let first_ty = &arm_types[0];
2120 for (_i, ty) in arm_types.iter().enumerate().skip(1) {
2121 let _ = self.unify(first_ty, ty);
2122 }
2123
2124 let (inner_ty, _) = self.strip_evidence(first_ty);
2126 if max_evidence > EvidenceLevel::Known {
2127 Type::Evidential {
2128 inner: Box::new(inner_ty),
2129 evidence: max_evidence,
2130 }
2131 } else {
2132 inner_ty
2133 }
2134 }
2135
2136 Expr::MethodCall {
2137 receiver,
2138 method,
2139 args,
2140 ..
2141 } => {
2142 let recv_ty = self.infer_expr(receiver);
2143 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
2144 let recv_derefed = match &recv_inner {
2146 Type::Ref { inner, .. } => {
2147 let (inner_stripped, _) = self.strip_evidence(inner);
2149 match &inner_stripped {
2151 Type::Ref { inner: inner2, .. } => {
2152 let (i2, _) = self.strip_evidence(inner2);
2153 i2
2154 }
2155 other => other.clone(),
2156 }
2157 }
2158 other => other.clone(),
2159 };
2160 let _arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
2161
2162 let user_method_result = {
2166 let mut result = None;
2168 if let Type::Named { name: ref type_name, .. } = recv_inner {
2169 if let Some(fn_type) = self.impl_methods.get(type_name)
2170 .and_then(|methods| methods.get(&method.name))
2171 .cloned()
2172 {
2173 if let Type::Function { return_type, .. } = self.freshen(&fn_type) {
2174 result = Some(*return_type);
2175 }
2176 }
2177 }
2178 if result.is_none() {
2180 if let Type::Named { name: ref type_name, .. } = recv_derefed {
2181 if let Some(fn_type) = self.impl_methods.get(type_name)
2182 .and_then(|methods| methods.get(&method.name))
2183 .cloned()
2184 {
2185 if let Type::Function { return_type, .. } = self.freshen(&fn_type) {
2186 result = Some(*return_type);
2187 }
2188 }
2189 }
2190 }
2191 result
2192 };
2193
2194 let result_ty = if let Some(user_ty) = user_method_result {
2196 user_ty
2197 } else {
2198 match method.name.as_str() {
2200 "len" | "count" | "size" => Type::Int(IntSize::USize),
2202
2203 "is_empty" | "contains" | "starts_with" | "ends_with" | "is_some"
2205 | "is_none" | "is_ok" | "is_err" | "is_ascii" | "is_alphabetic"
2206 | "is_numeric" | "is_alphanumeric" | "is_whitespace" | "is_uppercase"
2207 | "is_lowercase" | "exists" | "is_file" | "is_dir" | "is_match"
2208 | "matches" | "eq" | "ne" | "lt" | "le" | "gt" | "ge" => Type::Bool,
2209
2210 "to_string" | "to_lowercase" | "to_uppercase" | "trim" | "trim_start"
2212 | "trim_end" | "to_owned" | "replace" | "replacen" | "repeat"
2213 | "to_string_lossy" => Type::Named {
2214 name: "String".to_string(),
2215 generics: vec![],
2216 },
2217
2218 "as_str" | "trim_matches" | "trim_start_matches" | "trim_end_matches"
2220 | "strip_prefix" | "strip_suffix" => Type::Ref {
2221 lifetime: None,
2222 mutable: false,
2223 inner: Box::new(Type::Str),
2224 },
2225
2226 "clone" | "cloned" | "copied" => recv_inner.clone(),
2228
2229 "unwrap" | "unwrap_or" | "unwrap_or_default" | "unwrap_or_else"
2231 | "expect" | "ok" | "err" => {
2232 if let Type::Named { name, generics } = &recv_inner {
2233 if (name == "Option" || name == "Result") && !generics.is_empty() {
2234 generics[0].clone()
2235 } else {
2236 self.fresh_var()
2237 }
2238 } else {
2239 self.fresh_var()
2240 }
2241 }
2242
2243 "collect" => self.fresh_var(),
2245
2246 "iter" | "into_iter" | "iter_mut" | "rev" | "skip" | "take"
2248 | "filter" | "map" | "filter_map" | "flat_map" | "enumerate"
2249 | "zip" | "chain" | "flatten" | "reverse" | "sorted"
2250 | "dedup" | "unique" | "peekable" | "fuse" | "cycle" | "step_by"
2251 | "take_while" | "skip_while" | "scan" | "inspect" => recv_inner.clone(),
2252
2253 "split" | "rsplit" | "splitn" | "rsplitn" | "split_whitespace"
2255 | "split_ascii_whitespace" | "lines" | "chars" | "bytes"
2256 | "char_indices" | "split_terminator" | "rsplit_terminator"
2257 | "split_inclusive" | "matches_iter" => self.fresh_var(),
2258
2259 "keys" | "values" | "values_mut" | "into_keys"
2261 | "into_values" | "entry" | "drain" => self.fresh_var(),
2262
2263 "first" | "last" | "get" | "get_mut" | "pop" | "pop_front"
2265 | "pop_back" | "find" | "find_map" | "position" | "rposition"
2266 | "next" | "next_back" | "peek" | "nth" | "last_mut"
2267 | "binary_search" | "parent" | "file_name" | "file_stem"
2268 | "extension" => Type::Named {
2269 name: "Option".to_string(),
2270 generics: vec![self.fresh_var()],
2271 },
2272
2273 "parse" | "try_into" | "try_from" => Type::Named {
2275 name: "Result".to_string(),
2276 generics: vec![self.fresh_var(), self.fresh_var()],
2277 },
2278
2279 "remove" | "swap_remove" => {
2281 let effective_recv = if let Type::Named { .. } = &recv_inner {
2283 &recv_inner
2284 } else {
2285 &recv_derefed
2286 };
2287 if let Type::Named { generics, .. } = effective_recv {
2288 if !generics.is_empty() {
2289 generics[0].clone()
2290 } else {
2291 self.fresh_var()
2292 }
2293 } else {
2294 self.fresh_var()
2295 }
2296 }
2297
2298 "push" | "push_str" | "push_front" | "push_back" | "insert"
2300 | "clear" | "sort" | "sort_by" | "sort_by_key"
2301 | "sort_unstable" | "truncate" | "resize" | "extend" | "append"
2302 | "retain" | "swap" => Type::Unit,
2303
2304 "abs" | "floor" | "ceil" | "round" | "trunc" | "fract" | "sqrt"
2306 | "cbrt" | "sin" | "cos" | "tan" | "asin" | "acos" | "atan"
2307 | "sinh" | "cosh" | "tanh" | "exp" | "exp2" | "ln" | "log"
2308 | "log2" | "log10" | "pow" | "powi" | "powf" | "min" | "max"
2309 | "clamp" | "signum" | "copysign" | "saturating_add"
2310 | "saturating_sub" | "saturating_mul" | "wrapping_add"
2311 | "wrapping_sub" | "wrapping_mul" | "checked_add" | "checked_sub"
2312 | "checked_mul" | "checked_div" => recv_inner.clone(),
2313
2314 "to_digit" | "to_lowercase_char" | "to_uppercase_char" => Type::Named {
2316 name: "Option".to_string(),
2317 generics: vec![Type::Int(IntSize::U32)],
2318 },
2319
2320 "duration_since" | "elapsed" | "as_secs" | "as_millis" | "as_micros"
2322 | "as_nanos" | "from_secs" | "from_millis" => recv_inner.clone(),
2323
2324 "to_path_buf" | "with_extension" | "with_file_name" => {
2326 Type::Named {
2327 name: "PathBuf".to_string(),
2328 generics: vec![],
2329 }
2330 }
2331
2332 "join" => {
2334 let is_path_type = if let Type::Named { name, .. } = &recv_inner {
2336 name == "Path" || name == "PathBuf"
2337 } else {
2338 false
2339 };
2340 if is_path_type {
2341 Type::Named {
2342 name: "PathBuf".to_string(),
2343 generics: vec![],
2344 }
2345 } else {
2346 Type::Named {
2348 name: "String".to_string(),
2349 generics: vec![],
2350 }
2351 }
2352 }
2353
2354 "to_str" => Type::Named {
2356 name: "Option".to_string(),
2357 generics: vec![Type::Ref {
2358 lifetime: None,
2359 mutable: false,
2360 inner: Box::new(Type::Str),
2361 }],
2362 },
2363
2364 "fmt" | "write_str" | "write_fmt" => Type::Named {
2366 name: "Result".to_string(),
2367 generics: vec![Type::Unit, self.fresh_var()],
2368 },
2369
2370 "read" | "write" | "flush" | "read_to_string" | "read_to_end"
2372 | "read_line" | "write_all" => Type::Named {
2373 name: "Result".to_string(),
2374 generics: vec![self.fresh_var(), self.fresh_var()],
2375 },
2376
2377 "metadata" | "modified" | "created" | "accessed" | "len_file"
2379 | "is_readonly" | "permissions" => Type::Named {
2380 name: "Result".to_string(),
2381 generics: vec![self.fresh_var(), self.fresh_var()],
2382 },
2383
2384 "map_err" | "and_then" | "or_else" => recv_inner.clone(),
2386
2387 "and" | "or" => recv_inner.clone(),
2389
2390 _ => self.fresh_var(),
2393 }
2394 };
2395
2396 if recv_ev > EvidenceLevel::Known {
2398 Type::Evidential {
2399 inner: Box::new(result_ty),
2400 evidence: recv_ev,
2401 }
2402 } else {
2403 result_ty
2404 }
2405 }
2406
2407 Expr::Field { expr, field } => {
2408 let recv_ty = self.infer_expr(expr);
2409 let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
2410
2411 let field_ty = if let Type::Named { name, .. } = &recv_inner {
2413 if let Some(struct_def) = self.types.get(name) {
2415 if let TypeDef::Struct { fields, .. } = struct_def {
2416 fields
2417 .iter()
2418 .find(|(n, _)| n == &field.name)
2419 .map(|(_, ty)| ty.clone())
2420 .unwrap_or_else(|| self.fresh_var())
2421 } else {
2422 self.fresh_var()
2423 }
2424 } else {
2425 self.fresh_var()
2426 }
2427 } else {
2428 self.fresh_var()
2429 };
2430
2431 if recv_ev > EvidenceLevel::Known {
2433 Type::Evidential {
2434 inner: Box::new(field_ty),
2435 evidence: recv_ev,
2436 }
2437 } else {
2438 field_ty
2439 }
2440 }
2441
2442 Expr::Index { expr, index, .. } => {
2443 let arr_ty = self.infer_expr(expr);
2444 let idx_ty = self.infer_expr(index);
2445 let (arr_inner, arr_ev) = self.strip_evidence(&arr_ty);
2446
2447 let _ = self.unify(&idx_ty, &Type::Int(IntSize::USize));
2449
2450 let elem_ty = match arr_inner {
2452 Type::Array { element, .. } => *element,
2453 Type::Slice(element) => *element,
2454 Type::Named { name, generics } if name == "Vec" && !generics.is_empty() => {
2455 generics[0].clone()
2456 }
2457 _ => self.fresh_var(),
2458 };
2459
2460 if arr_ev > EvidenceLevel::Known {
2462 Type::Evidential {
2463 inner: Box::new(elem_ty),
2464 evidence: arr_ev,
2465 }
2466 } else {
2467 elem_ty
2468 }
2469 }
2470
2471 Expr::Try(inner) => {
2472 let inner_ty = self.infer_expr(inner);
2474 let resolved = if let Type::Var(v) = &inner_ty {
2476 self.substitutions.get(v).cloned().unwrap_or(inner_ty.clone())
2477 } else {
2478 inner_ty.clone()
2479 };
2480 let (stripped, _ev) = self.strip_evidence(&resolved);
2482 match &stripped {
2483 Type::Named { name, generics } if name == "Result" && !generics.is_empty() => {
2484 generics[0].clone()
2486 }
2487 Type::Named { name, generics } if name == "Option" && !generics.is_empty() => {
2488 generics[0].clone()
2490 }
2491 _ => {
2492 self.fresh_var()
2495 }
2496 }
2497 }
2498
2499 _ => {
2500 self.fresh_var()
2502 }
2503 }
2504 }
2505
2506 fn infer_literal(&self, lit: &Literal) -> Type {
2508 match lit {
2509 Literal::Int { .. } => Type::Int(IntSize::I64),
2510 Literal::Float { suffix, .. } => {
2511 match suffix.as_ref().map(|s| s.as_str()) {
2512 Some("f32") => Type::Float(FloatSize::F32),
2513 Some("f64") => Type::Float(FloatSize::F64),
2514 None | Some(_) => Type::Float(FloatSize::F64),
2516 }
2517 }
2518 Literal::Bool(_) => Type::Bool,
2519 Literal::Char(_) => Type::Char,
2520 Literal::ByteChar(_) => Type::Int(IntSize::U8),
2521 Literal::String(_) => Type::Ref {
2523 lifetime: None,
2524 mutable: false,
2525 inner: Box::new(Type::Str),
2526 },
2527 Literal::MultiLineString(_) => Type::Ref {
2528 lifetime: None,
2529 mutable: false,
2530 inner: Box::new(Type::Str),
2531 },
2532 Literal::RawString(_) => Type::Ref {
2533 lifetime: None,
2534 mutable: false,
2535 inner: Box::new(Type::Str),
2536 },
2537 Literal::ByteString(bytes) => Type::Ref {
2538 lifetime: None,
2539 mutable: false,
2540 inner: Box::new(Type::Array {
2541 element: Box::new(Type::Int(IntSize::U8)),
2542 size: Some(bytes.len()),
2543 }),
2544 },
2545 Literal::InterpolatedString { .. } => Type::Str,
2546 Literal::SigilStringSql(_) => Type::Str,
2547 Literal::SigilStringRoute(_) => Type::Str,
2548 Literal::Null => Type::Unit, Literal::Empty => Type::Unit,
2550 Literal::Infinity => Type::Float(FloatSize::F64),
2551 Literal::Circle => Type::Float(FloatSize::F64),
2552 }
2553 }
2554
2555 fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
2557 let (left_inner, left_ev) = self.strip_evidence(left);
2559 let (right_inner, right_ev) = self.strip_evidence(right);
2560
2561 let is_var_or_fn = |ty: &Type| {
2563 matches!(ty, Type::Var(_) | Type::Function { .. })
2564 };
2565
2566 let result_ty = match op {
2567 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
2569 let is_left_float = matches!(&left_inner, Type::Float(_));
2571 let is_right_float = matches!(&right_inner, Type::Float(_));
2572
2573 if is_left_float || is_right_float {
2574 if is_left_float { left_inner } else { right_inner }
2576 } else {
2577 let _ = self.unify(&left_inner, &right_inner);
2579 left_inner
2580 }
2581 }
2582
2583 BinOp::MatMul | BinOp::Hadamard | BinOp::TensorProd | BinOp::Convolve => {
2587 self.fresh_var()
2589 }
2590
2591 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
2593 let has_unit = |a: &Type, b: &Type| {
2595 matches!(a, Type::Unit) || matches!(b, Type::Unit)
2596 };
2597 let both_int = |a: &Type, b: &Type| {
2599 matches!(a, Type::Int(_)) && matches!(b, Type::Int(_))
2600 };
2601 let has_named = |a: &Type, b: &Type| {
2604 matches!(a, Type::Named { .. }) || matches!(b, Type::Named { .. })
2605 };
2606 if !self.unify(&left_inner, &right_inner)
2609 && !is_var_or_fn(&left_inner)
2610 && !is_var_or_fn(&right_inner)
2611 && !has_unit(&left_inner, &right_inner)
2612 && !both_int(&left_inner, &right_inner)
2613 && !has_named(&left_inner, &right_inner)
2614 {
2615 self.error(TypeError::new(format!(
2616 "comparison operands must have same type: left={:?}, right={:?}",
2617 left_inner, right_inner
2618 )));
2619 }
2620 Type::Bool
2621 }
2622
2623 BinOp::And | BinOp::Or => {
2625 if !self.unify(&Type::Bool, &left_inner) {
2626 self.error(TypeError::new("logical operand must be bool"));
2627 }
2628 if !self.unify(&Type::Bool, &right_inner) {
2629 self.error(TypeError::new("logical operand must be bool"));
2630 }
2631 Type::Bool
2632 }
2633
2634 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
2636
2637 BinOp::Concat => {
2639 if !self.unify(&Type::Str, &left_inner) {
2640 self.error(TypeError::new("concat operand must be string"));
2641 }
2642 Type::Str
2643 }
2644 };
2645
2646 let combined_ev = left_ev.join(right_ev);
2648
2649 if combined_ev > EvidenceLevel::Known {
2651 Type::Evidential {
2652 inner: Box::new(result_ty),
2653 evidence: combined_ev,
2654 }
2655 } else {
2656 result_ty
2657 }
2658 }
2659
2660 fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
2662 let (inner_ty, evidence) = self.strip_evidence(inner);
2663
2664 let result = match op {
2665 UnaryOp::Neg => inner_ty,
2666 UnaryOp::Not => {
2667 if matches!(inner_ty, Type::Int(_)) {
2669 inner_ty
2671 } else {
2672 if !self.unify(&Type::Bool, &inner_ty) {
2673 self.error(TypeError::new(format!(
2674 "type mismatch: '!' requires bool or integer, found {}",
2675 inner_ty
2676 )));
2677 }
2678 Type::Bool
2679 }
2680 }
2681 UnaryOp::Ref => Type::Ref {
2682 lifetime: None,
2683 mutable: false,
2684 inner: Box::new(inner_ty),
2685 },
2686 UnaryOp::RefMut => Type::Ref {
2687 lifetime: None,
2688 mutable: true,
2689 inner: Box::new(inner_ty),
2690 },
2691 UnaryOp::Deref => {
2692 if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
2693 *inner
2694 } else {
2695 self.fresh_var()
2697 }
2698 }
2699 };
2700
2701 if evidence > EvidenceLevel::Known {
2703 Type::Evidential {
2704 inner: Box::new(result),
2705 evidence,
2706 }
2707 } else {
2708 result
2709 }
2710 }
2711
2712 fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
2714 let (inner_ev_stripped, evidence) = self.strip_evidence(input);
2715
2716 let inner = match inner_ev_stripped {
2719 Type::Ref { inner: ref_inner, .. } => (*ref_inner).clone(),
2720 other => other,
2721 };
2722
2723 let result = match op {
2724 PipeOp::Transform(_body) => {
2726 if let Type::Array { element, size } = inner {
2727 Type::Array { element, size }
2728 } else if let Type::Slice(element) = inner {
2729 Type::Slice(element)
2730 } else {
2731 self.fresh_var()
2733 }
2734 }
2735
2736 PipeOp::Filter(_pred) => inner,
2738
2739 PipeOp::Sort(_) | PipeOp::SortBy(_) => inner,
2741
2742 PipeOp::Reduce(_) | PipeOp::ReduceWithInit(_, _) => {
2744 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2745 *element
2746 } else if let Type::Named { name, generics } = &inner {
2747 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2749 && !generics.is_empty() {
2750 generics[0].clone()
2751 } else {
2752 self.fresh_var()
2753 }
2754 } else if let Type::Var(_) = inner {
2755 self.fresh_var()
2757 } else {
2758 self.error(TypeError::new("reduce requires array or slice"));
2759 Type::Error
2760 }
2761 }
2762 PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
2763 let element = if let Type::Array { element, .. } | Type::Slice(element) = &inner {
2765 Some(element.clone())
2766 } else if let Type::Named { name, generics } = &inner {
2767 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2769 && !generics.is_empty() {
2770 Some(Box::new(generics[0].clone()))
2771 } else {
2772 None
2773 }
2774 } else {
2775 None
2776 };
2777 if let Some(element) = element {
2778 match element.as_ref() {
2779 Type::Int(_) | Type::Float(_) => *element,
2780 Type::Var(_) => *element, _ => {
2782 self.error(TypeError::new("numeric reduction requires numeric array"));
2783 Type::Error
2784 }
2785 }
2786 } else if let Type::Var(_) = inner {
2787 self.fresh_var()
2789 } else {
2790 self.error(TypeError::new("reduction requires array or slice"));
2791 Type::Error
2792 }
2793 }
2794 PipeOp::ReduceConcat => {
2795 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2797 match element.as_ref() {
2798 Type::Str => Type::Str,
2799 Type::Array { .. } => *element,
2800 Type::Var(_) => self.fresh_var(), _ => {
2802 self.error(TypeError::new(
2803 "concat reduction requires array of strings or arrays",
2804 ));
2805 Type::Error
2806 }
2807 }
2808 } else if let Type::Var(_) = inner {
2809 self.fresh_var()
2811 } else {
2812 self.error(TypeError::new("concat reduction requires array or slice"));
2813 Type::Error
2814 }
2815 }
2816 PipeOp::ReduceAll | PipeOp::ReduceAny => {
2817 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2819 match element.as_ref() {
2820 Type::Bool => Type::Bool,
2821 Type::Var(_) => Type::Bool, _ => {
2823 self.error(TypeError::new(
2824 "boolean reduction requires array of booleans",
2825 ));
2826 Type::Error
2827 }
2828 }
2829 } else if let Type::Var(_) = inner {
2830 Type::Bool
2832 } else {
2833 self.error(TypeError::new("boolean reduction requires array or slice"));
2834 Type::Error
2835 }
2836 }
2837
2838 PipeOp::Match(arms) => {
2840 if arms.is_empty() {
2842 self.error(TypeError::new("match expression has no arms"));
2843 Type::Error
2844 } else {
2845 let result_type = self.infer_expr(&arms[0].body);
2847 for arm in arms.iter().skip(1) {
2848 let arm_type = self.infer_expr(&arm.body);
2849 self.unify(&result_type, &arm_type);
2850 }
2851 result_type
2852 }
2853 }
2854
2855 PipeOp::TryMap(_) => {
2857 self.fresh_var()
2861 }
2862
2863 PipeOp::Call(callee) => {
2865 let callee_ty = self.infer_expr(callee);
2867 if let Type::Function { return_type, .. } = callee_ty {
2868 *return_type
2869 } else {
2870 self.fresh_var()
2872 }
2873 }
2874
2875 PipeOp::Method { name, type_args: _, args: _ } => {
2877 if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
2879 let fresh_ty = self.freshen(&fn_ty);
2881 if let Type::Function { return_type, .. } = fresh_ty {
2882 *return_type
2883 } else {
2884 Type::Error
2885 }
2886 } else {
2887 self.fresh_var()
2889 }
2890 }
2891
2892 PipeOp::Named { prefix, body: _ } => {
2894 if let Some(first) = prefix.first() {
2896 match first.name.as_str() {
2897 "sum" | "product" => {
2898 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2899 *element
2900 } else {
2901 self.error(TypeError::new("sum/product requires array"));
2902 Type::Error
2903 }
2904 }
2905 _ => self.fresh_var(),
2906 }
2907 } else {
2908 self.fresh_var()
2909 }
2910 }
2911
2912 PipeOp::Await => {
2914 inner
2916 }
2917
2918 PipeOp::First
2920 | PipeOp::Last
2921 | PipeOp::Middle
2922 | PipeOp::Choice
2923 | PipeOp::Nth(_)
2924 | PipeOp::Next => {
2925 if let Type::Array { element, .. } | Type::Slice(element) = inner {
2926 *element
2927 } else if let Type::Named { name, generics } = &inner {
2928 if (name == "Vec" || name == "VecDeque" || name == "LinkedList")
2930 && !generics.is_empty() {
2931 generics[0].clone()
2932 } else {
2933 self.fresh_var()
2934 }
2935 } else if let Type::Tuple(elements) = inner {
2936 if let Some(first) = elements.first() {
2938 first.clone()
2939 } else {
2940 Type::Unit
2941 }
2942 } else if let Type::Var(_) = inner {
2943 self.fresh_var()
2945 } else {
2946 self.fresh_var()
2948 }
2949 }
2950
2951 PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
2954
2955 PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
2958
2959 PipeOp::Send(_) => {
2966 Type::Evidential {
2968 inner: Box::new(self.fresh_var()),
2969 evidence: EvidenceLevel::Reported,
2970 }
2971 }
2972
2973 PipeOp::Recv => {
2975 Type::Evidential {
2977 inner: Box::new(self.fresh_var()),
2978 evidence: EvidenceLevel::Reported,
2979 }
2980 }
2981
2982 PipeOp::Stream(_) => {
2984 self.fresh_var()
2986 }
2987
2988 PipeOp::Connect(_) => {
2990 self.fresh_var()
2992 }
2993
2994 PipeOp::Close => Type::Unit,
2996
2997 PipeOp::Header { .. } => inner,
2999
3000 PipeOp::Body(_) => inner,
3002
3003 PipeOp::Timeout(_) => inner,
3005
3006 PipeOp::Retry { .. } => inner,
3008
3009 PipeOp::Validate {
3015 predicate: _,
3016 target_evidence,
3017 } => {
3018 let target_ev = EvidenceLevel::from_ast(*target_evidence);
3022
3023 if evidence < target_ev {
3025 self.error(
3026 TypeError::new(format!(
3027 "cannot demote evidence from {} ({}) to {} ({}) using validate",
3028 evidence.name(),
3029 evidence.symbol(),
3030 target_ev.name(),
3031 target_ev.symbol()
3032 ))
3033 .with_note("validate! can only promote evidence to a more certain level"),
3034 );
3035 }
3036
3037 return Type::Evidential {
3039 inner: Box::new(inner.clone()),
3040 evidence: target_ev,
3041 };
3042 }
3043
3044 PipeOp::Assume {
3046 reason: _,
3047 target_evidence,
3048 } => {
3049 let target_ev = EvidenceLevel::from_ast(*target_evidence);
3050
3051 if evidence < target_ev {
3055 self.error(
3056 TypeError::new(format!(
3057 "assume! cannot demote evidence from {} ({}) to {} ({})",
3058 evidence.name(),
3059 evidence.symbol(),
3060 target_ev.name(),
3061 target_ev.symbol()
3062 ))
3063 .with_note("assume! is for promoting evidence, not demoting"),
3064 );
3065 }
3066
3067 return Type::Evidential {
3069 inner: Box::new(inner.clone()),
3070 evidence: target_ev,
3071 };
3072 }
3073
3074 PipeOp::AssertEvidence(expected_ast) => {
3076 let expected = EvidenceLevel::from_ast(*expected_ast);
3077
3078 if !evidence.satisfies(expected) {
3079 self.error(
3080 TypeError::new(format!(
3081 "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
3082 expected.name(), expected.symbol(),
3083 evidence.name(), evidence.symbol()
3084 ))
3085 .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
3086 );
3087 }
3088
3089 return input.clone();
3091 }
3092
3093 PipeOp::Also(_) => {
3100 return input.clone();
3103 }
3104
3105 PipeOp::Apply(_) => {
3108 return input.clone();
3111 }
3112
3113 PipeOp::TakeIf(_) => {
3116 return Type::Named {
3119 name: "Option".to_string(),
3120 generics: vec![input.clone()],
3121 };
3122 }
3123
3124 PipeOp::TakeUnless(_) => {
3127 return Type::Named {
3130 name: "Option".to_string(),
3131 generics: vec![input.clone()],
3132 };
3133 }
3134
3135 PipeOp::Let(func) => {
3138 let _ = self.infer_expr(func);
3140 self.fresh_var() }
3142
3143 PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
3145 PipeOp::Compose(f) => {
3146 let _ = self.infer_expr(f);
3147 self.fresh_var()
3148 }
3149 PipeOp::Zip(other) => {
3150 let _ = self.infer_expr(other);
3151 self.fresh_var() }
3153 PipeOp::Scan(f) => {
3154 let _ = self.infer_expr(f);
3155 self.fresh_var() }
3157 PipeOp::Diff => self.fresh_var(), PipeOp::Gradient(var) => {
3159 let _ = self.infer_expr(var);
3160 self.fresh_var() }
3162 PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
3163 inner.clone() }
3165 PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
3166 let _ = self.infer_expr(n);
3167 self.fresh_var() }
3169 PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
3170 PipeOp::Enumerate => self.fresh_var(), PipeOp::Universal => {
3174 if let Type::Array { element, .. } | Type::Slice(element) = inner {
3176 *element
3177 } else if let Type::Named { name, generics } = &inner {
3178 if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
3179 && !generics.is_empty()
3180 {
3181 generics[0].clone()
3182 } else {
3183 self.fresh_var()
3184 }
3185 } else {
3186 self.fresh_var()
3187 }
3188 }
3189 PipeOp::Possibility { .. } => self.fresh_var(), PipeOp::Necessity { .. } => self.fresh_var(), PipeOp::PossibilityExtract => self.fresh_var(), PipeOp::NecessityVerify => inner, };
3194
3195 if evidence > EvidenceLevel::Known {
3197 Type::Evidential {
3198 inner: Box::new(result),
3199 evidence,
3200 }
3201 } else {
3202 result
3203 }
3204 }
3205
3206 fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
3208 match ty {
3209 Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
3210 _ => (ty.clone(), EvidenceLevel::Known),
3211 }
3212 }
3213
3214 fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
3217 let (inner_ty, ty_ev) = self.strip_evidence(ty);
3218 let final_ev = evidence.join(ty_ev);
3220
3221 match pattern {
3222 Pattern::Ident {
3223 name,
3224 evidentiality,
3225 ..
3226 } => {
3227 let ev = evidentiality
3229 .map(EvidenceLevel::from_ast)
3230 .unwrap_or(final_ev);
3231 self.env
3232 .borrow_mut()
3233 .define(name.name.clone(), inner_ty, ev);
3234 }
3235 Pattern::Tuple(patterns) => {
3236 if let Type::Tuple(types) = &inner_ty {
3237 for (pat, ty) in patterns.iter().zip(types.iter()) {
3238 self.bind_pattern(pat, ty, final_ev);
3239 }
3240 }
3241 }
3242 Pattern::Struct { fields, .. } => {
3243 for field in fields {
3246 let fresh = self.fresh_var();
3247 if let Some(ref pat) = field.pattern {
3248 self.bind_pattern(pat, &fresh, final_ev);
3249 } else {
3250 self.env
3251 .borrow_mut()
3252 .define(field.name.name.clone(), fresh, final_ev);
3253 }
3254 }
3255 }
3256 Pattern::TupleStruct { fields, .. } => {
3257 for pat in fields {
3258 let fresh = self.fresh_var();
3259 self.bind_pattern(pat, &fresh, final_ev);
3260 }
3261 }
3262 Pattern::Slice(patterns) => {
3263 let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
3264 {
3265 *element.clone()
3266 } else {
3267 self.fresh_var()
3268 };
3269 for pat in patterns {
3270 self.bind_pattern(pat, &elem_ty, final_ev);
3271 }
3272 }
3273 Pattern::Or(patterns) => {
3274 if let Some(first) = patterns.first() {
3277 self.bind_pattern(first, ty, evidence);
3278 }
3279 }
3280 Pattern::Wildcard | Pattern::Rest | Pattern::Literal(_) | Pattern::Range { .. } | Pattern::Path(_) => {
3281 }
3283 Pattern::Ref { pattern, .. } => {
3284 let inner_ty = self.fresh_var();
3287 self.bind_pattern(pattern, &inner_ty, final_ev);
3288 }
3289 Pattern::RefBinding {
3290 name,
3291 evidentiality,
3292 ..
3293 } => {
3294 let ev = evidentiality
3296 .map(EvidenceLevel::from_ast)
3297 .unwrap_or(final_ev);
3298 self.env
3299 .borrow_mut()
3300 .define(name.name.clone(), inner_ty, ev);
3301 }
3302 }
3303 }
3304
3305 fn resolve_alias(&self, ty: &Type) -> Type {
3307 if let Type::Named { name, generics } = ty {
3308 if generics.is_empty() {
3309 if let Some(TypeDef::Alias { target, .. }) = self.types.get(name) {
3310 return target.clone();
3311 }
3312 }
3313 }
3314 ty.clone()
3315 }
3316
3317 fn unify(&mut self, a: &Type, b: &Type) -> bool {
3319 let a = self.resolve_alias(a);
3321 let b = self.resolve_alias(b);
3322
3323 match (&a, &b) {
3324 (Type::Var(v), t) => {
3326 if let Some(resolved) = self.substitutions.get(v) {
3327 let resolved = resolved.clone();
3328 self.unify(&resolved, t)
3329 } else if !self.occurs_in(v, t) {
3330 self.substitutions.insert(*v, t.clone());
3331 true
3332 } else {
3333 true
3335 }
3336 }
3337 (t, Type::Var(v)) => {
3338 if let Some(resolved) = self.substitutions.get(v) {
3339 let resolved = resolved.clone();
3340 self.unify(t, &resolved)
3341 } else if !self.occurs_in(v, t) {
3342 self.substitutions.insert(*v, t.clone());
3343 true
3344 } else {
3345 true
3347 }
3348 }
3349
3350 (Type::Unit, Type::Unit) |
3352 (Type::Bool, Type::Bool) |
3353 (Type::Char, Type::Char) |
3354 (Type::Str, Type::Str) |
3355 (Type::Never, Type::Never) |
3356 (Type::Error, _) |
3357 (_, Type::Error) |
3358 (Type::Never, _) |
3360 (_, Type::Never) => true,
3361
3362 (Type::Linear(inner), other) => self.unify(inner, other),
3364 (other, Type::Linear(inner)) => self.unify(other, inner),
3365
3366 (Type::Int(_), Type::Int(_)) => true,
3369 (Type::Float(_), Type::Float(_)) => true,
3372
3373 (Type::Ref { mutable: false, inner: a, .. }, Type::Str) if matches!(a.as_ref(), Type::Str) => true,
3375 (Type::Str, Type::Ref { mutable: false, inner: b, .. }) if matches!(b.as_ref(), Type::Str) => true,
3376
3377 (Type::Named { name: n, .. }, Type::Ref { mutable: false, inner, .. })
3380 if n == "String" && matches!(inner.as_ref(), Type::Str) => true,
3381 (Type::Ref { mutable: false, inner, .. }, Type::Named { name: n, .. })
3382 if n == "String" && matches!(inner.as_ref(), Type::Str) => true,
3383
3384 (Type::Str, Type::Named { name, .. }) if name == "String" => true,
3389 (Type::Named { name, .. }, Type::Str) if name == "String" => true,
3390
3391 (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
3393 (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
3394 }
3395
3396 (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
3398
3399 (Type::Slice(a), Type::Array { element: b, .. }) => self.unify(a, b),
3402 (Type::Array { element: a, .. }, Type::Slice(b)) => self.unify(a, b),
3403
3404 (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
3406 a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
3407 }
3408
3409 (Type::Ref { mutable: ma, inner: a, .. }, Type::Ref { mutable: mb, inner: b, .. }) => {
3411 match (a.as_ref(), b.as_ref()) {
3413 (Type::Array { element: ea, .. }, Type::Slice(es)) => {
3414 (ma == mb || !ma) && self.unify(ea, es)
3415 }
3416 (Type::Slice(es), Type::Array { element: ea, .. }) => {
3417 (ma == mb || !mb) && self.unify(es, ea)
3418 }
3419 _ => {
3420 let mut_ok = ma == mb || (!ma && *mb) || (!mb && *ma);
3421 if mut_ok && self.unify(a, b) {
3422 return true;
3423 }
3424 if let Type::Ref { inner: inner_b, .. } = b.as_ref() {
3426 if self.unify(a, inner_b) {
3427 return true;
3428 }
3429 }
3430 if let Type::Ref { inner: inner_a, .. } = a.as_ref() {
3431 if self.unify(inner_a, b) {
3432 return true;
3433 }
3434 }
3435 if let Type::Named { name, generics, .. } = b.as_ref() {
3437 if matches!(name.as_str(), "Arc" | "Rc" | "Box" | "Cell" | "RefCell" | "Mutex")
3438 && !generics.is_empty()
3439 {
3440 if self.unify(a, &generics[0]) {
3441 return true;
3442 }
3443 }
3444 }
3445 if let Type::Named { name, generics, .. } = a.as_ref() {
3446 if matches!(name.as_str(), "Arc" | "Rc" | "Box" | "Cell" | "RefCell" | "Mutex")
3447 && !generics.is_empty()
3448 {
3449 if self.unify(&generics[0], b) {
3450 return true;
3451 }
3452 }
3453 }
3454 false
3455 }
3456 }
3457 }
3458
3459 (Type::Function { params: pa, return_type: ra, is_async: aa },
3461 Type::Function { params: pb, return_type: rb, is_async: ab }) => {
3462 aa == ab && pa.len() == pb.len() &&
3463 pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
3464 self.unify(ra, rb)
3465 }
3466
3467 (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
3469 if na == nb {
3470 if ga.len() == gb.len() {
3472 return ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y));
3473 }
3474 if ga.is_empty() || gb.is_empty() {
3477 return true;
3478 }
3479 return false;
3480 }
3481 if (ga.is_empty() && Self::is_type_parameter(na))
3484 || (gb.is_empty() && Self::is_type_parameter(nb)) {
3485 return true;
3486 }
3487 false
3488 }
3489
3490 (Type::Unit, Type::Evidential { evidence, .. })
3492 if *evidence == EvidenceLevel::Uncertain => true,
3493 (Type::Evidential { evidence, .. }, Type::Unit)
3494 if *evidence == EvidenceLevel::Uncertain => true,
3495
3496 (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
3498 self.unify(a, b)
3499 }
3500 (Type::Evidential { inner: a, .. }, b) => {
3501 self.unify(a, b)
3502 }
3503 (a, Type::Evidential { inner: b, .. }) => {
3504 self.unify(a, b)
3505 }
3506
3507 (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
3509
3510 (Type::ImplTrait(bounds_a), Type::ImplTrait(bounds_b)) => {
3513 bounds_a.len() == bounds_b.len() &&
3514 bounds_a.iter().zip(bounds_b.iter()).all(|(a, b)| self.unify(a, b))
3515 }
3516 (Type::ImplTrait(_), _) | (_, Type::ImplTrait(_)) => true,
3519
3520 (Type::Named { name, generics }, _) | (_, Type::Named { name, generics })
3524 if generics.is_empty() && Self::is_type_parameter(name) => {
3525 true
3526 }
3527
3528 (Type::Ref { inner: a, .. }, b) => self.unify(a, b),
3531 (a, Type::Ref { inner: b, .. }) => self.unify(a, b),
3532
3533 _ => false,
3534 }
3535 }
3536
3537 fn is_type_parameter(name: &str) -> bool {
3539 if name.len() == 1 && name.chars().next().map(|c| c.is_ascii_uppercase()).unwrap_or(false) {
3541 return true;
3542 }
3543 matches!(name, "Item" | "Output" | "Error" | "Key" | "Value" | "Idx" | "Self")
3545 }
3546
3547 fn is_numeric_coercion(expected: &Type, actual: &Type) -> bool {
3549 match (expected, actual) {
3551 (Type::Float(_), Type::Int(_)) => true,
3552 (Type::Evidential { inner: exp, .. }, Type::Int(_)) => {
3554 matches!(exp.as_ref(), Type::Float(_))
3555 }
3556 (Type::Float(_), Type::Evidential { inner: act, .. }) => {
3557 matches!(act.as_ref(), Type::Int(_))
3558 }
3559 _ => false,
3560 }
3561 }
3562
3563 fn is_reference_coercion(expected: &Type, actual: &Type) -> bool {
3565 let (exp_inner, exp_mutable) = match expected {
3567 Type::Ref { inner, mutable, .. } => (inner.as_ref(), *mutable),
3568 _ => return false,
3569 };
3570 let (act_inner, act_mutable) = match actual {
3571 Type::Ref { inner, mutable, .. } => (inner.as_ref(), *mutable),
3572 _ => return false,
3573 };
3574
3575 if !exp_mutable && act_mutable {
3577 if Self::types_structurally_equal(exp_inner, act_inner) {
3579 return true;
3580 }
3581 }
3582
3583 if let Type::Named { name, generics, .. } = act_inner {
3585 if matches!(name.as_str(), "Box" | "Arc" | "Rc" | "Cell" | "RefCell" | "Mutex")
3586 && !generics.is_empty()
3587 {
3588 if Self::types_structurally_equal(exp_inner, &generics[0]) {
3589 return true;
3590 }
3591 }
3592 }
3593
3594 if let Type::Named { name, generics, .. } = act_inner {
3596 if name == "Vec" && !generics.is_empty() {
3597 if let Type::Slice(element) = exp_inner {
3598 if Self::types_structurally_equal(element.as_ref(), &generics[0]) {
3599 return true;
3600 }
3601 }
3602 }
3603 }
3604
3605 if let Type::Ref { inner: act_inner_inner, .. } = act_inner {
3607 if Self::types_structurally_equal(exp_inner, act_inner_inner.as_ref()) {
3608 return true;
3609 }
3610 }
3611
3612 false
3613 }
3614
3615 fn is_ref_value_coercion(expected: &Type, actual: &Type) -> bool {
3618 if let Type::Ref { inner, .. } = actual {
3620 if Self::types_structurally_equal(expected, inner.as_ref()) {
3621 return true;
3622 }
3623 }
3624 if let Type::Ref { inner, .. } = expected {
3626 if Self::types_structurally_equal(inner.as_ref(), actual) {
3627 return true;
3628 }
3629 }
3630 false
3631 }
3632
3633 fn types_structurally_equal(a: &Type, b: &Type) -> bool {
3635 match (a, b) {
3636 (Type::Int(a_bits), Type::Int(b_bits)) => a_bits == b_bits,
3637 (Type::Float(a_bits), Type::Float(b_bits)) => a_bits == b_bits,
3638 (Type::Bool, Type::Bool) => true,
3639 (Type::Str, Type::Str) => true,
3640 (Type::Named { name: a_name, generics: a_gen, .. },
3641 Type::Named { name: b_name, generics: b_gen, .. }) => {
3642 a_name == b_name && a_gen.len() == b_gen.len() &&
3643 a_gen.iter().zip(b_gen.iter()).all(|(a, b)| Self::types_structurally_equal(a, b))
3644 }
3645 (Type::Slice(a_el), Type::Slice(b_el)) => {
3646 Self::types_structurally_equal(a_el, b_el)
3647 }
3648 (Type::Ref { inner: a_in, .. }, Type::Ref { inner: b_in, .. }) => {
3649 Self::types_structurally_equal(a_in, b_in)
3650 }
3651 (Type::Evidential { inner: a_in, .. }, Type::Evidential { inner: b_in, .. }) => {
3652 Self::types_structurally_equal(a_in, b_in)
3653 }
3654 (Type::Evidential { inner, .. }, other) | (other, Type::Evidential { inner, .. }) => {
3656 Self::types_structurally_equal(inner, other)
3657 }
3658 _ => false,
3659 }
3660 }
3661
3662 fn convert_type(&self, ty: &TypeExpr) -> Type {
3664 match ty {
3665 TypeExpr::Path(path) => {
3666 if path.segments.len() == 1 {
3667 let name = &path.segments[0].ident.name;
3668 match name.as_str() {
3669 "bool" => return Type::Bool,
3670 "char" => return Type::Char,
3671 "str" | "String" => return Type::Str,
3672 "i8" => return Type::Int(IntSize::I8),
3673 "i16" => return Type::Int(IntSize::I16),
3674 "i32" => return Type::Int(IntSize::I32),
3675 "i64" => return Type::Int(IntSize::I64),
3676 "i128" => return Type::Int(IntSize::I128),
3677 "isize" => return Type::Int(IntSize::ISize),
3678 "u8" => return Type::Int(IntSize::U8),
3679 "u16" => return Type::Int(IntSize::U16),
3680 "u32" => return Type::Int(IntSize::U32),
3681 "u64" => return Type::Int(IntSize::U64),
3682 "u128" => return Type::Int(IntSize::U128),
3683 "usize" => return Type::Int(IntSize::USize),
3684 "f32" => return Type::Float(FloatSize::F32),
3685 "f64" => return Type::Float(FloatSize::F64),
3686 "Self" => {
3688 if let Some(ref self_ty) = self.current_self_type {
3689 return self_ty.clone();
3690 }
3691 }
3692 _ => {
3693 if let Some(ty) = self.current_generics.get(name) {
3695 return ty.clone();
3696 }
3697 }
3698 }
3699 }
3700
3701 let name = path
3702 .segments
3703 .iter()
3704 .map(|s| s.ident.name.clone())
3705 .collect::<Vec<_>>()
3706 .join("::");
3707
3708 let generics = path
3709 .segments
3710 .last()
3711 .and_then(|s| s.generics.as_ref())
3712 .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
3713 .unwrap_or_default();
3714
3715 Type::Named { name, generics }
3716 }
3717
3718 TypeExpr::Reference { lifetime, mutable, inner } => Type::Ref {
3719 lifetime: lifetime.clone(),
3720 mutable: *mutable,
3721 inner: Box::new(self.convert_type(inner)),
3722 },
3723
3724 TypeExpr::Pointer { mutable, inner } => Type::Ptr {
3725 mutable: *mutable,
3726 inner: Box::new(self.convert_type(inner)),
3727 },
3728
3729 TypeExpr::Array { element, size: _ } => {
3730 Type::Array {
3731 element: Box::new(self.convert_type(element)),
3732 size: None, }
3734 }
3735
3736 TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
3737
3738 TypeExpr::Tuple(elements) => {
3739 Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
3740 }
3741
3742 TypeExpr::Function {
3743 params,
3744 return_type,
3745 } => Type::Function {
3746 params: params.iter().map(|t| self.convert_type(t)).collect(),
3747 return_type: Box::new(
3748 return_type
3749 .as_ref()
3750 .map(|t| self.convert_type(t))
3751 .unwrap_or(Type::Unit),
3752 ),
3753 is_async: false,
3754 },
3755
3756 TypeExpr::Evidential {
3757 inner,
3758 evidentiality,
3759 error_type,
3760 } => {
3761 let _ = error_type; Type::Evidential {
3765 inner: Box::new(self.convert_type(inner)),
3766 evidence: EvidenceLevel::from_ast(*evidentiality),
3767 }
3768 }
3769
3770 TypeExpr::Cycle { modulus: _ } => {
3771 Type::Cycle { modulus: 12 } }
3773
3774 TypeExpr::Simd { element, lanes } => {
3775 let elem_ty = self.convert_type(element);
3776 Type::Simd {
3777 element: Box::new(elem_ty),
3778 lanes: *lanes,
3779 }
3780 }
3781
3782 TypeExpr::Atomic(inner) => {
3783 let inner_ty = self.convert_type(inner);
3784 Type::Atomic(Box::new(inner_ty))
3785 }
3786
3787 TypeExpr::Never => Type::Never,
3788 TypeExpr::Infer => Type::Var(TypeVar(0)), TypeExpr::Lifetime(name) => Type::Lifetime(name.clone()),
3790 TypeExpr::TraitObject(bounds) => {
3791 let converted: Vec<Type> = bounds.iter().map(|b| self.convert_type(b)).collect();
3792 Type::TraitObject(converted)
3793 }
3794 TypeExpr::Hrtb { lifetimes, bound } => Type::Hrtb {
3795 lifetimes: lifetimes.clone(),
3796 bound: Box::new(self.convert_type(bound)),
3797 },
3798 TypeExpr::InlineStruct { fields } => Type::InlineStruct {
3799 fields: fields
3800 .iter()
3801 .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
3802 .collect(),
3803 },
3804 TypeExpr::ImplTrait(bounds) => {
3805 Type::ImplTrait(bounds.iter().map(|b| self.convert_type(b)).collect())
3806 }
3807 TypeExpr::InlineEnum { variants } => {
3808 Type::InlineEnum(variants.iter().map(|v| v.name.name.clone()).collect())
3809 }
3810 TypeExpr::AssocTypeBinding { name, ty } => Type::AssocTypeBinding {
3811 name: name.name.clone(),
3812 ty: Box::new(self.convert_type(ty)),
3813 },
3814 TypeExpr::ConstExpr(_) => {
3815 Type::Var(TypeVar(0))
3818 }
3819 TypeExpr::QualifiedPath { self_type, trait_path, item_path } => {
3820 let trait_part = trait_path.as_ref()
3823 .map(|tp| tp.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::"))
3824 .unwrap_or_default();
3825 let item_part = item_path.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::");
3826 let name = if trait_part.is_empty() {
3827 format!("<_>::{}", item_part)
3828 } else {
3829 format!("<_ as {}>::{}", trait_part, item_part)
3830 };
3831 Type::Named {
3832 name,
3833 generics: vec![self.convert_type(self_type)],
3834 }
3835 }
3836 TypeExpr::Linear(inner) => Type::Linear(Box::new(self.convert_type(inner))),
3839 TypeExpr::Affine(inner) => Type::Affine(Box::new(self.convert_type(inner))),
3840 TypeExpr::Relevant(inner) => Type::Relevant(Box::new(self.convert_type(inner))),
3841 }
3842 }
3843
3844 pub fn errors(&self) -> &[TypeError] {
3846 &self.errors
3847 }
3848}
3849
3850impl Default for TypeChecker {
3851 fn default() -> Self {
3852 Self::new()
3853 }
3854}
3855
3856trait PatternExt {
3858 fn evidentiality(&self) -> Option<Evidentiality>;
3859 fn binding_name(&self) -> Option<String>;
3860 fn binding_span(&self) -> Option<Span>;
3861}
3862
3863impl PatternExt for Pattern {
3864 fn evidentiality(&self) -> Option<Evidentiality> {
3865 match self {
3866 Pattern::Ident { evidentiality, .. } => *evidentiality,
3867 _ => None,
3868 }
3869 }
3870
3871 fn binding_name(&self) -> Option<String> {
3872 match self {
3873 Pattern::Ident { name, .. } => Some(name.name.clone()),
3874 _ => None,
3875 }
3876 }
3877
3878 fn binding_span(&self) -> Option<Span> {
3879 match self {
3880 Pattern::Ident { name, .. } => Some(name.span),
3881 _ => None,
3882 }
3883 }
3884}
3885
3886impl fmt::Display for Type {
3887 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3888 match self {
3889 Type::Unit => write!(f, "()"),
3890 Type::Bool => write!(f, "bool"),
3891 Type::Int(size) => write!(f, "{:?}", size),
3892 Type::Float(size) => write!(f, "{:?}", size),
3893 Type::Char => write!(f, "char"),
3894 Type::Str => write!(f, "str"),
3895 Type::Array { element, size } => {
3896 if let Some(n) = size {
3897 write!(f, "[{}; {}]", element, n)
3898 } else {
3899 write!(f, "[{}]", element)
3900 }
3901 }
3902 Type::Slice(inner) => write!(f, "[{}]", inner),
3903 Type::Tuple(elems) => {
3904 write!(f, "(")?;
3905 for (i, e) in elems.iter().enumerate() {
3906 if i > 0 {
3907 write!(f, ", ")?;
3908 }
3909 write!(f, "{}", e)?;
3910 }
3911 write!(f, ")")
3912 }
3913 Type::Named { name, generics } => {
3914 write!(f, "{}", name)?;
3915 if !generics.is_empty() {
3916 write!(f, "<")?;
3917 for (i, g) in generics.iter().enumerate() {
3918 if i > 0 {
3919 write!(f, ", ")?;
3920 }
3921 write!(f, "{}", g)?;
3922 }
3923 write!(f, ">")?;
3924 }
3925 Ok(())
3926 }
3927 Type::Function {
3928 params,
3929 return_type,
3930 is_async,
3931 } => {
3932 if *is_async {
3933 write!(f, "async ")?;
3934 }
3935 write!(f, "fn(")?;
3936 for (i, p) in params.iter().enumerate() {
3937 if i > 0 {
3938 write!(f, ", ")?;
3939 }
3940 write!(f, "{}", p)?;
3941 }
3942 write!(f, ") -> {}", return_type)
3943 }
3944 Type::Ref { lifetime, mutable, inner } => {
3945 let lt = lifetime.as_ref().map(|l| format!("'{} ", l)).unwrap_or_default();
3946 write!(f, "&{}{}{}", lt, if *mutable { "mut " } else { "" }, inner)
3947 }
3948 Type::Ptr { mutable, inner } => {
3949 write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
3950 }
3951 Type::Evidential { inner, evidence } => {
3952 write!(f, "{}{}", inner, evidence.symbol())
3953 }
3954 Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
3955 Type::Var(v) => write!(f, "?{}", v.0),
3956 Type::Error => write!(f, "<error>"),
3957 Type::Never => write!(f, "!"),
3958 Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
3959 Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
3960 Type::Lifetime(name) => write!(f, "'{}", name),
3961 Type::TraitObject(bounds) => {
3962 write!(f, "dyn ")?;
3963 for (i, bound) in bounds.iter().enumerate() {
3964 if i > 0 {
3965 write!(f, " + ")?;
3966 }
3967 write!(f, "{}", bound)?;
3968 }
3969 Ok(())
3970 }
3971 Type::Hrtb { lifetimes, bound } => {
3972 write!(f, "for<")?;
3973 for (i, lt) in lifetimes.iter().enumerate() {
3974 if i > 0 {
3975 write!(f, ", ")?;
3976 }
3977 write!(f, "'{}", lt)?;
3978 }
3979 write!(f, "> {}", bound)
3980 }
3981 Type::InlineStruct { fields } => {
3982 write!(f, "struct {{ ")?;
3983 for (i, (name, ty)) in fields.iter().enumerate() {
3984 if i > 0 {
3985 write!(f, ", ")?;
3986 }
3987 write!(f, "{}: {}", name, ty)?;
3988 }
3989 write!(f, " }}")
3990 }
3991 Type::ImplTrait(bounds) => {
3992 write!(f, "impl ")?;
3993 for (i, bound) in bounds.iter().enumerate() {
3994 if i > 0 {
3995 write!(f, " + ")?;
3996 }
3997 write!(f, "{}", bound)?;
3998 }
3999 Ok(())
4000 }
4001 Type::InlineEnum(variants) => {
4002 write!(f, "enum {{ ")?;
4003 for (i, name) in variants.iter().enumerate() {
4004 if i > 0 {
4005 write!(f, ", ")?;
4006 }
4007 write!(f, "{}", name)?;
4008 }
4009 write!(f, " }}")
4010 }
4011 Type::AssocTypeBinding { name, ty } => {
4012 write!(f, "{} = {}", name, ty)
4013 }
4014 Type::Linear(inner) => write!(f, "linear {}", inner),
4016 Type::Affine(inner) => write!(f, "affine {}", inner),
4017 Type::Relevant(inner) => write!(f, "relevant {}", inner),
4018 }
4019 }
4020}
4021
4022#[cfg(test)]
4023mod tests {
4024 use super::*;
4025 use crate::Parser;
4026
4027 fn check(source: &str) -> Result<(), Vec<TypeError>> {
4028 let mut parser = Parser::new(source);
4029 let file = parser.parse_file().expect("parse failed");
4030 let mut checker = TypeChecker::new();
4031 checker.check_file(&file)
4032 }
4033
4034 #[test]
4035 fn test_basic_types() {
4036 assert!(check("rite main() { ≔ x: i64 = 42; }").is_ok());
4037 assert!(check("rite main() { ≔ x: bool = true; }").is_ok());
4038 assert!(check("rite main() { ≔ x: f64 = 3.14; }").is_ok());
4039 }
4040
4041 #[test]
4042 fn test_type_mismatch() {
4043 assert!(check("rite main() { ≔ x: bool = 42; }").is_err());
4044 }
4045
4046 #[test]
4047 fn test_evidence_propagation() {
4048 assert!(check(
4050 r#"
4051 rite main() {
4052 ≔ known: i64! = 42;
4053 ≔ uncertain: i64? = 10;
4054 ≔ result = known + uncertain;
4055 }
4056 "#
4057 )
4058 .is_ok());
4059 }
4060
4061 #[test]
4062 fn test_function_return() {
4063 let result = check(
4064 r#"
4065 rite add(a: i64, b: i64) -> i64 {
4066 ⤺ a + b;
4067 }
4068 rite main() {
4069 ≔ x = add(1, 2);
4070 }
4071 "#,
4072 );
4073 if let Err(errors) = &result {
4074 for e in errors {
4075 eprintln!("Error: {}", e);
4076 }
4077 }
4078 assert!(result.is_ok());
4079 }
4080
4081 #[test]
4082 fn test_array_types() {
4083 assert!(check(
4084 r#"
4085 rite main() {
4086 ≔ arr = [1, 2, 3];
4087 ≔ x = arr[0];
4088 }
4089 "#
4090 )
4091 .is_ok());
4092 }
4093
4094 #[test]
4099 fn test_evidence_inference_from_initializer() {
4100 assert!(check(
4102 r#"
4103 rite main() {
4104 ≔ reported_val: i64~ = 42;
4105 // x should inherit ~ evidence from reported_val
4106 ≔ x = reported_val + 1;
4107 }
4108 "#
4109 )
4110 .is_ok());
4111 }
4112
4113 #[test]
4114 fn test_evidence_inference_explicit_override() {
4115 assert!(check(
4117 r#"
4118 rite main() {
4119 ≔ reported_val: i64~ = 42;
4120 // Explicit ! annotation - this would fail ⎇ we checked evidence properly
4121 // but the type system allows it as an override
4122 ≔ x! = 42;
4123 }
4124 "#
4125 )
4126 .is_ok());
4127 }
4128
4129 #[test]
4130 fn test_if_else_evidence_join() {
4131 assert!(check(
4133 r#"
4134 rite main() {
4135 ≔ known_val: i64! = 1;
4136 ≔ reported_val: i64~ = 2;
4137 ≔ cond: bool = true;
4138 // Result should have ~ evidence (join of ! and ~)
4139 ≔ result = ⎇ cond { known_val } ⎉ { reported_val };
4140 }
4141 "#
4142 )
4143 .is_ok());
4144 }
4145
4146 #[test]
4147 fn test_binary_op_evidence_propagation() {
4148 assert!(check(
4150 r#"
4151 rite main() {
4152 ≔ known: i64! = 1;
4153 ≔ reported: i64~ = 2;
4154 // Result should have ~ evidence (max of ! and ~)
4155 ≔ result = known + reported;
4156 }
4157 "#
4158 )
4159 .is_ok());
4160 }
4161
4162 #[test]
4163 fn test_match_evidence_join() {
4164 assert!(check(
4167 r#"
4168 rite main() {
4169 ≔ x: i64 = 1;
4170 }
4171 "#
4172 )
4173 .is_ok());
4174 }
4175}