sigil_parser/
typeck.rs

1//! Type checker for Sigil.
2//!
3//! Implements bidirectional type inference with evidentiality tracking.
4//! The type system enforces that evidence levels propagate correctly
5//! through computations.
6
7use crate::ast::*;
8use crate::span::Span;
9use std::cell::RefCell;
10use std::collections::HashMap;
11use std::fmt;
12use std::rc::Rc;
13
14/// Internal type representation.
15#[derive(Debug, Clone, PartialEq)]
16pub enum Type {
17    /// Primitive types
18    Unit,
19    Bool,
20    Int(IntSize),
21    Float(FloatSize),
22    Char,
23    Str,
24
25    /// Compound types
26    Array {
27        element: Box<Type>,
28        size: Option<usize>,
29    },
30    Slice(Box<Type>),
31    Tuple(Vec<Type>),
32
33    /// Named type (struct, enum, type alias)
34    Named {
35        name: String,
36        generics: Vec<Type>,
37    },
38
39    /// Function type
40    Function {
41        params: Vec<Type>,
42        return_type: Box<Type>,
43        is_async: bool,
44    },
45
46    /// Reference types
47    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 wrapper - the core of Sigil's type system
58    Evidential {
59        inner: Box<Type>,
60        evidence: EvidenceLevel,
61    },
62
63    /// Cyclic type (modular arithmetic)
64    Cycle {
65        modulus: usize,
66    },
67
68    /// SIMD vector type
69    Simd {
70        element: Box<Type>,
71        lanes: u8,
72    },
73
74    /// Atomic type
75    Atomic(Box<Type>),
76
77    /// Type variable for inference
78    Var(TypeVar),
79
80    /// Error type (for error recovery)
81    Error,
82
83    /// Never type (diverging)
84    Never,
85
86    /// Lifetime bound ('static, 'a)
87    Lifetime(String),
88
89    /// Trait object: dyn Trait
90    TraitObject(Vec<Type>),
91
92    /// Higher-ranked trait bound: for<'a> Trait<'a>
93    Hrtb {
94        lifetimes: Vec<String>,
95        bound: Box<Type>,
96    },
97    /// Inline struct type: struct { field: Type, ... }
98    InlineStruct {
99        fields: Vec<(String, Type)>,
100    },
101    /// Impl trait: impl Trait bounds
102    ImplTrait(Vec<Type>),
103    /// Inline enum type: enum { Variant1, Variant2, ... }
104    InlineEnum(Vec<String>),
105    /// Associated type binding: Output = Type
106    AssocTypeBinding { name: String, ty: Box<Type> },
107}
108
109/// Integer sizes
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111pub enum IntSize {
112    I8,
113    I16,
114    I32,
115    I64,
116    I128,
117    U8,
118    U16,
119    U32,
120    U64,
121    U128,
122    ISize,
123    USize,
124}
125
126/// Float sizes
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub enum FloatSize {
129    F32,
130    F64,
131}
132
133/// Evidence levels in the type system.
134///
135/// Evidence forms a lattice:
136///   Known (!) < Uncertain (?) < Reported (~) < Paradox (‽)
137///
138/// Operations combine evidence levels using join (⊔):
139///   a + b : join(evidence(a), evidence(b))
140#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
141pub enum EvidenceLevel {
142    /// Direct knowledge - computed locally, verified
143    Known, // !
144    /// Uncertain - inferred, possible, not verified
145    Uncertain, // ?
146    /// Reported - from external source, hearsay
147    Reported, // ~
148    /// Paradox - contradictory information
149    Paradox, // ‽
150}
151
152impl EvidenceLevel {
153    /// Join two evidence levels (least upper bound in lattice)
154    pub fn join(self, other: Self) -> Self {
155        std::cmp::max(self, other)
156    }
157
158    /// Meet two evidence levels (greatest lower bound)
159    pub fn meet(self, other: Self) -> Self {
160        std::cmp::min(self, other)
161    }
162
163    /// Convert from AST representation
164    pub fn from_ast(e: Evidentiality) -> Self {
165        match e {
166            Evidentiality::Known => EvidenceLevel::Known,
167            Evidentiality::Uncertain | Evidentiality::Predicted => EvidenceLevel::Uncertain,
168            Evidentiality::Reported => EvidenceLevel::Reported,
169            Evidentiality::Paradox => EvidenceLevel::Paradox,
170        }
171    }
172
173    /// Symbol representation
174    pub fn symbol(&self) -> &'static str {
175        match self {
176            EvidenceLevel::Known => "!",
177            EvidenceLevel::Uncertain => "?",
178            EvidenceLevel::Reported => "~",
179            EvidenceLevel::Paradox => "‽",
180        }
181    }
182
183    /// Human-readable name
184    pub fn name(&self) -> &'static str {
185        match self {
186            EvidenceLevel::Known => "known",
187            EvidenceLevel::Uncertain => "uncertain",
188            EvidenceLevel::Reported => "reported",
189            EvidenceLevel::Paradox => "paradox",
190        }
191    }
192
193    /// Check if this evidence level can satisfy a required level.
194    ///
195    /// Evidence is covariant: you can pass more certain data where less certain is expected.
196    /// Known (!) can satisfy any requirement.
197    /// Reported (~) can only satisfy Reported or Paradox requirements.
198    ///
199    /// Returns true if `self` (actual) can be used where `required` is expected.
200    pub fn satisfies(self, required: Self) -> bool {
201        // More certain evidence (lower in lattice) can satisfy less certain requirements
202        // Known <= Uncertain <= Reported <= Paradox
203        self <= required
204    }
205}
206
207/// Type variable for inference
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
209pub struct TypeVar(pub u32);
210
211/// Type error
212#[derive(Debug, Clone)]
213pub struct TypeError {
214    pub message: String,
215    pub span: Option<Span>,
216    pub notes: Vec<String>,
217}
218
219impl TypeError {
220    pub fn new(message: impl Into<String>) -> Self {
221        Self {
222            message: message.into(),
223            span: None,
224            notes: Vec::new(),
225        }
226    }
227
228    pub fn with_span(mut self, span: Span) -> Self {
229        self.span = Some(span);
230        self
231    }
232
233    pub fn with_note(mut self, note: impl Into<String>) -> Self {
234        self.notes.push(note.into());
235        self
236    }
237}
238
239impl fmt::Display for TypeError {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        write!(f, "{}", self.message)?;
242        if let Some(span) = self.span {
243            write!(f, " at {}", span)?;
244        }
245        for note in &self.notes {
246            write!(f, "\n  note: {}", note)?;
247        }
248        Ok(())
249    }
250}
251
252/// Type environment for scoped lookups
253#[derive(Debug, Clone)]
254pub struct TypeEnv {
255    /// Variable bindings: name -> (type, evidence)
256    bindings: HashMap<String, (Type, EvidenceLevel)>,
257    /// Parent scope
258    parent: Option<Rc<RefCell<TypeEnv>>>,
259}
260
261impl TypeEnv {
262    pub fn new() -> Self {
263        Self {
264            bindings: HashMap::new(),
265            parent: None,
266        }
267    }
268
269    pub fn with_parent(parent: Rc<RefCell<TypeEnv>>) -> Self {
270        Self {
271            bindings: HashMap::new(),
272            parent: Some(parent),
273        }
274    }
275
276    /// Define a new binding
277    pub fn define(&mut self, name: String, ty: Type, evidence: EvidenceLevel) {
278        self.bindings.insert(name, (ty, evidence));
279    }
280
281    /// Look up a binding
282    pub fn lookup(&self, name: &str) -> Option<(Type, EvidenceLevel)> {
283        if let Some(binding) = self.bindings.get(name) {
284            Some(binding.clone())
285        } else if let Some(ref parent) = self.parent {
286            parent.borrow().lookup(name)
287        } else {
288            None
289        }
290    }
291}
292
293impl Default for TypeEnv {
294    fn default() -> Self {
295        Self::new()
296    }
297}
298
299/// Type definitions (structs, enums, type aliases)
300#[derive(Debug, Clone)]
301pub enum TypeDef {
302    Struct {
303        generics: Vec<String>,
304        fields: Vec<(String, Type)>,
305    },
306    Enum {
307        generics: Vec<String>,
308        variants: Vec<(String, Option<Vec<Type>>)>,
309    },
310    Alias {
311        generics: Vec<String>,
312        target: Type,
313    },
314}
315
316/// The type checker
317pub struct TypeChecker {
318    /// Type environment stack
319    env: Rc<RefCell<TypeEnv>>,
320    /// Type definitions
321    types: HashMap<String, TypeDef>,
322    /// Function signatures
323    functions: HashMap<String, Type>,
324    /// Associated functions/methods per type: type_name -> (method_name -> method_type)
325    impl_methods: HashMap<String, HashMap<String, Type>>,
326    /// Current Self type when inside an impl block
327    current_self_type: Option<String>,
328    /// Current generic type parameters (name -> type variable)
329    current_generics: HashMap<String, Type>,
330    /// Expected return type for the current function (for checking return statements)
331    expected_return_type: Option<Type>,
332    /// Type variable counter
333    next_var: u32,
334    /// Inferred type variable substitutions
335    substitutions: HashMap<TypeVar, Type>,
336    /// Collected errors
337    errors: Vec<TypeError>,
338    /// Set of mutable variable names (for assignment checking)
339    mutable_vars: std::collections::HashSet<String>,
340}
341
342impl TypeChecker {
343    pub fn new() -> Self {
344        let mut checker = Self {
345            env: Rc::new(RefCell::new(TypeEnv::new())),
346            types: HashMap::new(),
347            functions: HashMap::new(),
348            impl_methods: HashMap::new(),
349            current_self_type: None,
350            current_generics: HashMap::new(),
351            expected_return_type: None,
352            next_var: 0,
353            substitutions: HashMap::new(),
354            errors: Vec::new(),
355            mutable_vars: std::collections::HashSet::new(),
356        };
357
358        // Register built-in types and functions
359        checker.register_builtins();
360        checker
361    }
362
363    fn register_builtins(&mut self) {
364        // Helper to create a function type
365        let func = |params: Vec<Type>, ret: Type| Type::Function {
366            params,
367            return_type: Box::new(ret),
368            is_async: false,
369        };
370
371        // Type variable for generic functions
372        let any = Type::Var(TypeVar(9999)); // Use high number to avoid conflicts
373
374        // ===================
375        // Option/Result constructors (for type checking)
376        // ===================
377        // Some: fn<T>(T) -> Option<T>
378        let t1 = Type::Var(TypeVar(9998));
379        self.functions.insert(
380            "Some".to_string(),
381            func(
382                vec![t1.clone()],
383                Type::Named {
384                    name: "Option".to_string(),
385                    generics: vec![t1],
386                },
387            ),
388        );
389
390        // None: fn<T>() -> Option<T>
391        let t2 = Type::Var(TypeVar(9997));
392        self.functions.insert(
393            "None".to_string(),
394            func(
395                vec![],
396                Type::Named {
397                    name: "Option".to_string(),
398                    generics: vec![t2],
399                },
400            ),
401        );
402
403        // Ok: fn<T, E>(T) -> Result<T, E>
404        let t3 = Type::Var(TypeVar(9996));
405        let e1 = Type::Var(TypeVar(9995));
406        self.functions.insert(
407            "Ok".to_string(),
408            func(
409                vec![t3.clone()],
410                Type::Named {
411                    name: "Result".to_string(),
412                    generics: vec![t3, e1],
413                },
414            ),
415        );
416
417        // Err: fn<T, E>(E) -> Result<T, E>
418        let t4 = Type::Var(TypeVar(9994));
419        let e2 = Type::Var(TypeVar(9993));
420        self.functions.insert(
421            "Err".to_string(),
422            func(
423                vec![e2.clone()],
424                Type::Named {
425                    name: "Result".to_string(),
426                    generics: vec![t4, e2],
427                },
428            ),
429        );
430
431        // ===================
432        // Core I/O
433        // ===================
434        // print accepts any type (polymorphic)
435        self.functions
436            .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
437        self.functions
438            .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
439        self.functions
440            .insert("input".to_string(), func(vec![], Type::Str));
441        self.functions
442            .insert("input_line".to_string(), func(vec![], Type::Str));
443
444        // ===================
445        // Type inspection
446        // ===================
447        self.functions
448            .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
449        self.functions.insert(
450            "len".to_string(),
451            func(vec![any.clone()], Type::Int(IntSize::USize)),
452        );
453
454        // ===================
455        // String functions
456        // ===================
457        self.functions
458            .insert("str".to_string(), func(vec![any.clone()], Type::Str));
459        self.functions
460            .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
461        self.functions
462            .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
463        self.functions
464            .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
465        self.functions.insert(
466            "split".to_string(),
467            func(
468                vec![Type::Str, Type::Str],
469                Type::Array {
470                    element: Box::new(Type::Str),
471                    size: None,
472                },
473            ),
474        );
475        self.functions.insert(
476            "join".to_string(),
477            func(
478                vec![
479                    Type::Array {
480                        element: Box::new(Type::Str),
481                        size: None,
482                    },
483                    Type::Str,
484                ],
485                Type::Str,
486            ),
487        );
488        self.functions.insert(
489            "contains".to_string(),
490            func(vec![Type::Str, Type::Str], Type::Bool),
491        );
492        self.functions.insert(
493            "starts_with".to_string(),
494            func(vec![Type::Str, Type::Str], Type::Bool),
495        );
496        self.functions.insert(
497            "ends_with".to_string(),
498            func(vec![Type::Str, Type::Str], Type::Bool),
499        );
500        self.functions.insert(
501            "replace".to_string(),
502            func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
503        );
504        self.functions.insert(
505            "char_at".to_string(),
506            func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
507        );
508        self.functions.insert(
509            "substring".to_string(),
510            func(
511                vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
512                Type::Str,
513            ),
514        );
515
516        // ===================
517        // Math functions
518        // ===================
519        let f64_ty = Type::Float(FloatSize::F64);
520        let i64_ty = Type::Int(IntSize::I64);
521
522        self.functions.insert(
523            "abs".to_string(),
524            func(vec![f64_ty.clone()], f64_ty.clone()),
525        );
526        self.functions.insert(
527            "sqrt".to_string(),
528            func(vec![f64_ty.clone()], f64_ty.clone()),
529        );
530        self.functions.insert(
531            "sin".to_string(),
532            func(vec![f64_ty.clone()], f64_ty.clone()),
533        );
534        self.functions.insert(
535            "cos".to_string(),
536            func(vec![f64_ty.clone()], f64_ty.clone()),
537        );
538        self.functions.insert(
539            "tan".to_string(),
540            func(vec![f64_ty.clone()], f64_ty.clone()),
541        );
542        self.functions.insert(
543            "floor".to_string(),
544            func(vec![f64_ty.clone()], f64_ty.clone()),
545        );
546        self.functions.insert(
547            "ceil".to_string(),
548            func(vec![f64_ty.clone()], f64_ty.clone()),
549        );
550        self.functions.insert(
551            "round".to_string(),
552            func(vec![f64_ty.clone()], f64_ty.clone()),
553        );
554        self.functions.insert(
555            "pow".to_string(),
556            func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
557        );
558        self.functions.insert(
559            "log".to_string(),
560            func(vec![f64_ty.clone()], f64_ty.clone()),
561        );
562        self.functions.insert(
563            "exp".to_string(),
564            func(vec![f64_ty.clone()], f64_ty.clone()),
565        );
566        self.functions.insert(
567            "min".to_string(),
568            func(vec![any.clone(), any.clone()], any.clone()),
569        );
570        self.functions.insert(
571            "max".to_string(),
572            func(vec![any.clone(), any.clone()], any.clone()),
573        );
574
575        // ===================
576        // Array/Collection functions
577        // ===================
578        self.functions
579            .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
580        self.functions
581            .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
582        self.functions.insert(
583            "push".to_string(),
584            func(vec![any.clone(), any.clone()], Type::Unit),
585        );
586        self.functions
587            .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
588        self.functions
589            .insert("first".to_string(), func(vec![any.clone()], any.clone()));
590        self.functions
591            .insert("last".to_string(), func(vec![any.clone()], any.clone()));
592        self.functions
593            .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
594        self.functions
595            .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
596        self.functions.insert(
597            "range".to_string(),
598            func(
599                vec![i64_ty.clone(), i64_ty.clone()],
600                Type::Array {
601                    element: Box::new(i64_ty.clone()),
602                    size: None,
603                },
604            ),
605        );
606
607        // ===================
608        // Assertions (for testing)
609        // ===================
610        self.functions
611            .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
612        self.functions.insert(
613            "assert_eq".to_string(),
614            func(vec![any.clone(), any.clone()], Type::Unit),
615        );
616        self.functions.insert(
617            "assert_ne".to_string(),
618            func(vec![any.clone(), any.clone()], Type::Unit),
619        );
620        self.functions.insert(
621            "assert_lt".to_string(),
622            func(vec![any.clone(), any.clone()], Type::Unit),
623        );
624        self.functions.insert(
625            "assert_le".to_string(),
626            func(vec![any.clone(), any.clone()], Type::Unit),
627        );
628        self.functions.insert(
629            "assert_gt".to_string(),
630            func(vec![any.clone(), any.clone()], Type::Unit),
631        );
632        self.functions.insert(
633            "assert_ge".to_string(),
634            func(vec![any.clone(), any.clone()], Type::Unit),
635        );
636        self.functions.insert(
637            "assert_true".to_string(),
638            func(vec![Type::Bool], Type::Unit),
639        );
640        self.functions.insert(
641            "assert_false".to_string(),
642            func(vec![Type::Bool], Type::Unit),
643        );
644        self.functions.insert(
645            "assert_null".to_string(),
646            func(vec![any.clone()], Type::Unit),
647        );
648        self.functions.insert(
649            "assert_not_null".to_string(),
650            func(vec![any.clone()], Type::Unit),
651        );
652        self.functions.insert(
653            "assert_contains".to_string(),
654            func(vec![any.clone(), any.clone()], Type::Unit),
655        );
656        self.functions.insert(
657            "assert_len".to_string(),
658            func(vec![any.clone(), i64_ty.clone()], Type::Unit),
659        );
660
661        // ===================
662        // Random
663        // ===================
664        self.functions
665            .insert("random".to_string(), func(vec![], f64_ty.clone()));
666        self.functions.insert(
667            "random_int".to_string(),
668            func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
669        );
670        self.functions
671            .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
672
673        // ===================
674        // Time
675        // ===================
676        self.functions
677            .insert("now".to_string(), func(vec![], f64_ty.clone()));
678        self.functions
679            .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
680
681        // ===================
682        // Conversion
683        // ===================
684        self.functions
685            .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
686        self.functions
687            .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
688        self.functions
689            .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
690
691        // ===================
692        // Error handling
693        // ===================
694        self.functions
695            .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
696        self.functions
697            .insert("todo".to_string(), func(vec![], Type::Never));
698        self.functions
699            .insert("unreachable".to_string(), func(vec![], Type::Never));
700
701        // ===================
702        // Evidentiality functions
703        // ===================
704        // Create known evidence (!)
705        self.functions.insert(
706            "known".to_string(),
707            func(
708                vec![any.clone()],
709                Type::Evidential {
710                    inner: Box::new(any.clone()),
711                    evidence: EvidenceLevel::Known,
712                },
713            ),
714        );
715        // Create uncertain evidence (?)
716        self.functions.insert(
717            "uncertain".to_string(),
718            func(
719                vec![any.clone()],
720                Type::Evidential {
721                    inner: Box::new(any.clone()),
722                    evidence: EvidenceLevel::Uncertain,
723                },
724            ),
725        );
726        // Create reported evidence (~)
727        self.functions.insert(
728            "reported".to_string(),
729            func(
730                vec![any.clone()],
731                Type::Evidential {
732                    inner: Box::new(any.clone()),
733                    evidence: EvidenceLevel::Reported,
734                },
735            ),
736        );
737        // Get evidence level as string
738        self.functions.insert(
739            "evidence_of".to_string(),
740            func(vec![any.clone()], Type::Str),
741        );
742        // Validate reported -> uncertain
743        self.functions.insert(
744            "validate".to_string(),
745            func(
746                vec![any.clone()],
747                Type::Evidential {
748                    inner: Box::new(any.clone()),
749                    evidence: EvidenceLevel::Uncertain,
750                },
751            ),
752        );
753        // Verify uncertain -> known
754        self.functions.insert(
755            "verify".to_string(),
756            func(
757                vec![any.clone()],
758                Type::Evidential {
759                    inner: Box::new(any.clone()),
760                    evidence: EvidenceLevel::Known,
761                },
762            ),
763        );
764
765        // ===================
766        // Poly-cultural math (cycles, music theory)
767        // ===================
768        // MIDI note to frequency (A4 = 440Hz)
769        self.functions.insert(
770            "freq".to_string(),
771            func(vec![i64_ty.clone()], f64_ty.clone()),
772        );
773        // Octave calculation (12-tone equal temperament)
774        self.functions.insert(
775            "octave".to_string(),
776            func(vec![i64_ty.clone()], i64_ty.clone()),
777        );
778        // Note within octave (0-11)
779        self.functions.insert(
780            "pitch_class".to_string(),
781            func(vec![i64_ty.clone()], i64_ty.clone()),
782        );
783        // Modular arithmetic (cycles)
784        self.functions.insert(
785            "mod_cycle".to_string(),
786            func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
787        );
788    }
789
790    /// Fresh type variable
791    fn fresh_var(&mut self) -> Type {
792        let var = TypeVar(self.next_var);
793        self.next_var += 1;
794        Type::Var(var)
795    }
796
797    /// Check if a type contains unresolved type variables
798    fn type_contains_var(&self, ty: &Type) -> bool {
799        match ty {
800            Type::Var(v) => !self.substitutions.contains_key(v),
801            Type::Array { element, .. } => self.type_contains_var(element.as_ref()),
802            Type::Slice(inner) => self.type_contains_var(inner.as_ref()),
803            Type::Tuple(elems) => elems.iter().any(|e| self.type_contains_var(e)),
804            Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.type_contains_var(inner.as_ref()),
805            Type::Function { params, return_type, .. } => {
806                params.iter().any(|p| self.type_contains_var(p)) || self.type_contains_var(return_type.as_ref())
807            }
808            Type::Named { generics, .. } => generics.iter().any(|g| self.type_contains_var(g)),
809            Type::Evidential { inner, .. } => self.type_contains_var(inner.as_ref()),
810            Type::Atomic(inner) => self.type_contains_var(inner.as_ref()),
811            Type::Simd { element, .. } => self.type_contains_var(element.as_ref()),
812            _ => false,
813        }
814    }
815
816    /// Occurs check: does type variable v occur in type t?
817    /// Used to prevent creating cyclic/infinite types
818    fn occurs_in(&self, v: &TypeVar, t: &Type) -> bool {
819        match t {
820            Type::Var(w) => {
821                if v == w {
822                    return true;
823                }
824                if let Some(resolved) = self.substitutions.get(w) {
825                    self.occurs_in(v, resolved)
826                } else {
827                    false
828                }
829            }
830            Type::Array { element, .. } => self.occurs_in(v, element),
831            Type::Slice(inner) => self.occurs_in(v, inner),
832            Type::Tuple(elems) => elems.iter().any(|e| self.occurs_in(v, e)),
833            Type::Ref { inner, .. } | Type::Ptr { inner, .. } => self.occurs_in(v, inner),
834            Type::Function { params, return_type, .. } => {
835                params.iter().any(|p| self.occurs_in(v, p)) || self.occurs_in(v, return_type)
836            }
837            Type::Named { generics, .. } => generics.iter().any(|g| self.occurs_in(v, g)),
838            Type::Evidential { inner, .. } => self.occurs_in(v, inner),
839            Type::Atomic(inner) => self.occurs_in(v, inner),
840            Type::Simd { element, .. } => self.occurs_in(v, element),
841            _ => false,
842        }
843    }
844
845    /// Freshen a type by replacing all type variables with fresh ones
846    /// This is used for polymorphic built-in functions
847    fn freshen(&mut self, ty: &Type) -> Type {
848        let mut mapping = std::collections::HashMap::new();
849        self.freshen_inner(ty, &mut mapping)
850    }
851
852    fn freshen_inner(
853        &mut self,
854        ty: &Type,
855        mapping: &mut std::collections::HashMap<u32, Type>,
856    ) -> Type {
857        match ty {
858            Type::Var(TypeVar(id)) => {
859                if let Some(fresh) = mapping.get(id) {
860                    fresh.clone()
861                } else {
862                    let fresh = self.fresh_var();
863                    mapping.insert(*id, fresh.clone());
864                    fresh
865                }
866            }
867            Type::Array { element, size } => Type::Array {
868                element: Box::new(self.freshen_inner(element, mapping)),
869                size: *size,
870            },
871            Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
872            Type::Ref { lifetime, mutable, inner } => Type::Ref {
873                lifetime: lifetime.clone(),
874                mutable: *mutable,
875                inner: Box::new(self.freshen_inner(inner, mapping)),
876            },
877            Type::Tuple(elems) => Type::Tuple(
878                elems
879                    .iter()
880                    .map(|e| self.freshen_inner(e, mapping))
881                    .collect(),
882            ),
883            Type::Function {
884                params,
885                return_type,
886                is_async,
887            } => Type::Function {
888                params: params
889                    .iter()
890                    .map(|p| self.freshen_inner(p, mapping))
891                    .collect(),
892                return_type: Box::new(self.freshen_inner(return_type, mapping)),
893                is_async: *is_async,
894            },
895            Type::Evidential { inner, evidence } => Type::Evidential {
896                inner: Box::new(self.freshen_inner(inner, mapping)),
897                evidence: *evidence,
898            },
899            Type::Named { name, generics } => Type::Named {
900                name: name.clone(),
901                generics: generics
902                    .iter()
903                    .map(|g| self.freshen_inner(g, mapping))
904                    .collect(),
905            },
906            // Primitive types don't contain type variables
907            _ => ty.clone(),
908        }
909    }
910
911    /// Push a new scope
912    fn push_scope(&mut self) {
913        let new_env = TypeEnv::with_parent(self.env.clone());
914        self.env = Rc::new(RefCell::new(new_env));
915    }
916
917    /// Pop current scope
918    fn pop_scope(&mut self) {
919        let parent = self.env.borrow().parent.clone();
920        if let Some(p) = parent {
921            self.env = p;
922        }
923    }
924
925    /// Record an error
926    fn error(&mut self, err: TypeError) {
927        self.errors.push(err);
928    }
929
930    /// Check if actual evidence can satisfy expected evidence requirement.
931    /// Returns Ok(()) if compatible, Err with helpful message if not.
932    fn check_evidence(
933        &mut self,
934        expected: EvidenceLevel,
935        actual: EvidenceLevel,
936        context: &str,
937    ) -> bool {
938        if actual.satisfies(expected) {
939            true
940        } else {
941            let mut err = TypeError::new(format!(
942                "evidence mismatch {}: expected {} ({}), found {} ({})",
943                context,
944                expected.name(),
945                expected.symbol(),
946                actual.name(),
947                actual.symbol(),
948            ));
949
950            // Add helpful notes based on the specific mismatch
951            match (expected, actual) {
952                (EvidenceLevel::Known, EvidenceLevel::Reported) => {
953                    err = err.with_note(
954                        "reported data (~) cannot be used where known data (!) is required",
955                    );
956                    err = err.with_note(
957                        "help: use |validate!{...} to verify and promote evidence level",
958                    );
959                }
960                (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
961                    err = err.with_note(
962                        "uncertain data (?) cannot be used where known data (!) is required",
963                    );
964                    err = err.with_note(
965                        "help: use pattern matching or unwrap to handle the uncertainty",
966                    );
967                }
968                (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
969                    err = err.with_note(
970                        "reported data (~) cannot be used where uncertain data (?) is required",
971                    );
972                    err = err.with_note("help: use |validate?{...} to verify external data");
973                }
974                _ => {
975                    err = err.with_note(format!(
976                        "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
977                    ));
978                }
979            }
980
981            self.error(err);
982            false
983        }
984    }
985
986    /// Extract evidence level from a type, defaulting to Known
987    fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
988        match ty {
989            Type::Evidential { evidence, .. } => *evidence,
990            _ => EvidenceLevel::Known,
991        }
992    }
993
994    /// Check a source file
995    pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
996        // First pass: collect type definitions
997        for item in &file.items {
998            self.collect_type_def(&item.node);
999        }
1000
1001        // Second pass: collect function signatures
1002        for item in &file.items {
1003            self.collect_fn_sig(&item.node);
1004        }
1005
1006        // Third pass: check function bodies
1007        for item in &file.items {
1008            self.check_item(&item.node);
1009        }
1010
1011        if self.errors.is_empty() {
1012            Ok(())
1013        } else {
1014            Err(std::mem::take(&mut self.errors))
1015        }
1016    }
1017
1018    /// Collect type definitions (first pass)
1019    fn collect_type_def(&mut self, item: &Item) {
1020        match item {
1021            Item::Struct(s) => {
1022                let generics = s
1023                    .generics
1024                    .as_ref()
1025                    .map(|g| {
1026                        g.params
1027                            .iter()
1028                            .filter_map(|p| {
1029                                if let GenericParam::Type { name, .. } = p {
1030                                    Some(name.name.clone())
1031                                } else {
1032                                    None
1033                                }
1034                            })
1035                            .collect()
1036                    })
1037                    .unwrap_or_default();
1038
1039                let fields = match &s.fields {
1040                    StructFields::Named(fs) => fs
1041                        .iter()
1042                        .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
1043                        .collect(),
1044                    StructFields::Tuple(ts) => ts
1045                        .iter()
1046                        .enumerate()
1047                        .map(|(i, t)| (i.to_string(), self.convert_type(t)))
1048                        .collect(),
1049                    StructFields::Unit => vec![],
1050                };
1051
1052                // Check for duplicate struct definition
1053                if self.types.contains_key(&s.name.name) {
1054                    self.error(TypeError::new(format!(
1055                        "duplicate type definition: '{}'",
1056                        s.name.name
1057                    )));
1058                }
1059                self.types
1060                    .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
1061            }
1062            Item::Enum(e) => {
1063                let generics = e
1064                    .generics
1065                    .as_ref()
1066                    .map(|g| {
1067                        g.params
1068                            .iter()
1069                            .filter_map(|p| {
1070                                if let GenericParam::Type { name, .. } = p {
1071                                    Some(name.name.clone())
1072                                } else {
1073                                    None
1074                                }
1075                            })
1076                            .collect()
1077                    })
1078                    .unwrap_or_default();
1079
1080                let variants = e
1081                    .variants
1082                    .iter()
1083                    .map(|v| {
1084                        let fields = match &v.fields {
1085                            StructFields::Tuple(ts) => {
1086                                Some(ts.iter().map(|t| self.convert_type(t)).collect())
1087                            }
1088                            StructFields::Named(fs) => {
1089                                Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
1090                            }
1091                            StructFields::Unit => None,
1092                        };
1093                        (v.name.name.clone(), fields)
1094                    })
1095                    .collect();
1096
1097                self.types
1098                    .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
1099            }
1100            Item::TypeAlias(t) => {
1101                let generics = t
1102                    .generics
1103                    .as_ref()
1104                    .map(|g| {
1105                        g.params
1106                            .iter()
1107                            .filter_map(|p| {
1108                                if let GenericParam::Type { name, .. } = p {
1109                                    Some(name.name.clone())
1110                                } else {
1111                                    None
1112                                }
1113                            })
1114                            .collect()
1115                    })
1116                    .unwrap_or_default();
1117
1118                let target = self.convert_type(&t.ty);
1119                self.types
1120                    .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
1121            }
1122            _ => {}
1123        }
1124    }
1125
1126    /// Collect function signatures (second pass)
1127    fn collect_fn_sig(&mut self, item: &Item) {
1128        match item {
1129            Item::Function(f) => {
1130                let params: Vec<Type> = f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1131
1132                let return_type = f
1133                    .return_type
1134                    .as_ref()
1135                    .map(|t| self.convert_type(t))
1136                    .unwrap_or(Type::Unit);
1137
1138                let fn_type = Type::Function {
1139                    params,
1140                    return_type: Box::new(return_type),
1141                    is_async: f.is_async,
1142                };
1143
1144                // Check for duplicate function definition
1145                if self.functions.contains_key(&f.name.name) {
1146                    self.error(TypeError::new(format!(
1147                        "duplicate function definition: '{}'",
1148                        f.name.name
1149                    )));
1150                }
1151                self.functions.insert(f.name.name.clone(), fn_type);
1152            }
1153            Item::Impl(impl_block) => {
1154                // Get the type name being implemented
1155                let type_name = self.type_path_to_name(&impl_block.self_ty);
1156
1157                // Set current_self_type so Self resolves correctly in convert_type
1158                self.current_self_type = Some(type_name.clone());
1159
1160                // Set up generic type parameters as type variables
1161                if let Some(ref generics) = impl_block.generics {
1162                    for param in &generics.params {
1163                        if let crate::ast::GenericParam::Type { name, .. } = param {
1164                            let type_var = self.fresh_var();
1165                            self.current_generics.insert(name.name.clone(), type_var);
1166                        }
1167                    }
1168                }
1169
1170                // Collect associated functions/methods
1171                for impl_item in &impl_block.items {
1172                    if let crate::ast::ImplItem::Function(f) = impl_item {
1173                        let params: Vec<Type> =
1174                            f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
1175
1176                        let return_type = f
1177                            .return_type
1178                            .as_ref()
1179                            .map(|t| self.convert_type(t))
1180                            .unwrap_or(Type::Unit);
1181
1182                        let fn_type = Type::Function {
1183                            params,
1184                            return_type: Box::new(return_type),
1185                            is_async: f.is_async,
1186                        };
1187
1188                        // Register in impl_methods
1189                        self.impl_methods
1190                            .entry(type_name.clone())
1191                            .or_insert_with(HashMap::new)
1192                            .insert(f.name.name.clone(), fn_type);
1193                    }
1194                }
1195
1196                // Clear current_self_type and generics when done
1197                self.current_self_type = None;
1198                self.current_generics.clear();
1199            }
1200            _ => {}
1201        }
1202    }
1203
1204    /// Convert a TypePath to a simple type name string
1205    fn type_path_to_name(&self, ty: &crate::ast::TypeExpr) -> String {
1206        match ty {
1207            crate::ast::TypeExpr::Path(path) => {
1208                path.segments
1209                    .iter()
1210                    .map(|s| s.ident.name.clone())
1211                    .collect::<Vec<_>>()
1212                    .join("::")
1213            }
1214            _ => "Unknown".to_string(),
1215        }
1216    }
1217
1218    /// Check an item (third pass)
1219    fn check_item(&mut self, item: &Item) {
1220        match item {
1221            Item::Function(f) => self.check_function(f),
1222            Item::Const(c) => {
1223                let declared = self.convert_type(&c.ty);
1224                let inferred = self.infer_expr(&c.value);
1225                if !self.unify(&declared, &inferred) {
1226                    self.error(
1227                        TypeError::new(format!(
1228                            "type mismatch in const '{}': expected {:?}, found {:?}",
1229                            c.name.name, declared, inferred
1230                        ))
1231                        .with_span(c.name.span),
1232                    );
1233                }
1234            }
1235            Item::Static(s) => {
1236                let declared = self.convert_type(&s.ty);
1237                let inferred = self.infer_expr(&s.value);
1238                if !self.unify(&declared, &inferred) {
1239                    self.error(
1240                        TypeError::new(format!(
1241                            "type mismatch in static '{}': expected {:?}, found {:?}",
1242                            s.name.name, declared, inferred
1243                        ))
1244                        .with_span(s.name.span),
1245                    );
1246                }
1247            }
1248            Item::Impl(impl_block) => {
1249                // Set current_self_type so Self resolves correctly
1250                let type_name = self.type_path_to_name(&impl_block.self_ty);
1251                self.current_self_type = Some(type_name);
1252
1253                // Set up generic type parameters as type variables
1254                if let Some(ref generics) = impl_block.generics {
1255                    for param in &generics.params {
1256                        if let crate::ast::GenericParam::Type { name, .. } = param {
1257                            let type_var = self.fresh_var();
1258                            self.current_generics.insert(name.name.clone(), type_var);
1259                        }
1260                    }
1261                }
1262
1263                // Check each function in the impl block
1264                for impl_item in &impl_block.items {
1265                    if let crate::ast::ImplItem::Function(f) = impl_item {
1266                        self.check_function(f);
1267                    }
1268                }
1269
1270                // Clear current_self_type and generics when done
1271                self.current_self_type = None;
1272                self.current_generics.clear();
1273            }
1274            _ => {}
1275        }
1276    }
1277
1278    /// Check a function body
1279    fn check_function(&mut self, func: &Function) {
1280        self.push_scope();
1281
1282        // Bind parameters with evidence inference
1283        for param in &func.params {
1284            let ty = self.convert_type(&param.ty);
1285            // Infer parameter evidence from type annotation if present,
1286            // otherwise from pattern annotation, otherwise default to Known
1287            let type_evidence = self.get_evidence(&ty);
1288            let evidence = param
1289                .pattern
1290                .evidentiality()
1291                .map(EvidenceLevel::from_ast)
1292                .unwrap_or(type_evidence);
1293
1294            if let Some(name) = param.pattern.binding_name() {
1295                self.env.borrow_mut().define(name, ty, evidence);
1296            }
1297        }
1298
1299        // Set expected return type for checking explicit return statements
1300        let expected_return = func
1301            .return_type
1302            .as_ref()
1303            .map(|t| self.convert_type(t))
1304            .unwrap_or(Type::Unit);
1305        let old_return_type = self.expected_return_type.clone();
1306        self.expected_return_type = Some(expected_return.clone());
1307
1308        // Check body
1309        if let Some(ref body) = func.body {
1310            let body_type = self.check_block(body);
1311
1312            // Restore old return type
1313            self.expected_return_type = old_return_type;
1314
1315            // Check return type (for implicit returns)
1316            let expected_return = func
1317                .return_type
1318                .as_ref()
1319                .map(|t| self.convert_type(t))
1320                .unwrap_or(Type::Unit);
1321
1322            // Check structural type compatibility
1323            // For bootstrapping: skip return type checking to be lenient with
1324            // cross-file references and unresolved type variables
1325            let _ = self.unify(&expected_return, &body_type);
1326
1327            // Evidence inference for return types:
1328            // - If return type has explicit evidence annotation → check compatibility
1329            // - If function name has evidence annotation (e.g., validate!) → use that
1330            // - If no explicit annotation → infer evidence from body
1331            // - For public functions, warn if evidence should be annotated at module boundary
1332            let type_has_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1333            // Function name evidentiality (e.g., validate_model! has ! evidentiality)
1334            let name_evidence = func.name.evidentiality.as_ref()
1335                .map(|e| EvidenceLevel::from_ast(*e));
1336            let has_explicit_evidence = type_has_evidence || name_evidence.is_some();
1337            let actual_evidence = self.get_evidence(&body_type);
1338
1339            if has_explicit_evidence {
1340                // Explicit annotation: check compatibility
1341                // EXCEPT: if evidentiality is on the function NAME (e.g., validate!),
1342                // the function is declaring it transforms evidence - trust that declaration
1343                if name_evidence.is_none() {
1344                    let expected_evidence = self.get_evidence(&expected_return);
1345                    self.check_evidence(
1346                        expected_evidence,
1347                        actual_evidence,
1348                        &format!("in return type of '{}'", func.name.name),
1349                    );
1350                }
1351                // If name has evidentiality, skip the check - function transforms evidence
1352            } else {
1353                // No explicit annotation: infer from body
1354                // For public functions at module boundaries, suggest annotation
1355                if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1356                    self.error(
1357                        TypeError::new(format!(
1358                            "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1359                            func.name.name,
1360                            actual_evidence.name(),
1361                            actual_evidence.symbol(),
1362                        ))
1363                        .with_span(func.name.span)
1364                        .with_note("help: add explicit evidence annotation to the return type")
1365                        .with_note(format!(
1366                            "example: fn {}(...) -> {}{} {{ ... }}",
1367                            func.name.name,
1368                            expected_return,
1369                            actual_evidence.symbol()
1370                        )),
1371                    );
1372                }
1373                // Inference succeeds - the body's evidence becomes the function's evidence
1374            }
1375        }
1376
1377        self.pop_scope();
1378    }
1379
1380    /// Check if a type expression has an explicit evidence annotation
1381    fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1382        match ty {
1383            Some(TypeExpr::Evidential { .. }) => true,
1384            Some(TypeExpr::Reference { inner, .. })
1385            | Some(TypeExpr::Pointer { inner, .. })
1386            | Some(TypeExpr::Slice(inner))
1387            | Some(TypeExpr::Array { element: inner, .. }) => {
1388                self.type_has_explicit_evidence(Some(inner.as_ref()))
1389            }
1390            Some(TypeExpr::Tuple(elements)) => elements
1391                .iter()
1392                .any(|e| self.type_has_explicit_evidence(Some(e))),
1393            _ => false,
1394        }
1395    }
1396
1397    /// Check a block and return its type
1398    fn check_block(&mut self, block: &Block) -> Type {
1399        self.push_scope();
1400
1401        let mut diverges = false;
1402        for stmt in &block.stmts {
1403            let stmt_ty = self.check_stmt(stmt);
1404            if matches!(stmt_ty, Type::Never) {
1405                diverges = true;
1406            }
1407        }
1408
1409        let result = if let Some(ref expr) = block.expr {
1410            self.infer_expr(expr)
1411        } else if diverges {
1412            Type::Never
1413        } else {
1414            Type::Unit
1415        };
1416
1417        self.pop_scope();
1418        result
1419    }
1420
1421    /// Check a statement and return its type (Never if it diverges)
1422    fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1423        match stmt {
1424            Stmt::Let { pattern, ty, init } => {
1425                let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1426                let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1427
1428                let final_ty = match (&declared_ty, &init_ty) {
1429                    (Some(d), Some(i)) => {
1430                        if !self.unify(d, i) {
1431                            // Report type mismatch error
1432                            let binding_name = pattern.binding_name().unwrap_or_else(|| "<pattern>".to_string());
1433                            let mut err = TypeError::new(format!(
1434                                "type mismatch in let binding '{}': expected {:?}, found {:?}",
1435                                binding_name, d, i
1436                            ));
1437                            if let Some(span) = pattern.binding_span() {
1438                                err = err.with_span(span);
1439                            }
1440                            self.error(err);
1441                        }
1442                        d.clone()
1443                    }
1444                    (Some(d), None) => d.clone(),
1445                    (None, Some(i)) => i.clone(),
1446                    (None, None) => self.fresh_var(),
1447                };
1448
1449                // Evidence inference: explicit annotation takes precedence,
1450                // otherwise infer from initializer expression.
1451                // This reduces annotation burden while maintaining safety:
1452                // - `let x = network_call()` → x is automatically ~
1453                // - `let x! = validated_data` → explicit ! annotation honored
1454                let evidence = pattern
1455                    .evidentiality()
1456                    .map(EvidenceLevel::from_ast)
1457                    .unwrap_or_else(|| {
1458                        // Infer evidence from initializer type
1459                        init_ty
1460                            .as_ref()
1461                            .map(|ty| self.get_evidence(ty))
1462                            .unwrap_or(EvidenceLevel::Known)
1463                    });
1464
1465                if let Some(name) = pattern.binding_name() {
1466                    // Track mutability for assignment checking
1467                    if pattern.is_mutable() {
1468                        self.mutable_vars.insert(name.clone());
1469                    }
1470                    self.env.borrow_mut().define(name, final_ty, evidence);
1471                }
1472                Type::Unit
1473            }
1474            Stmt::LetElse { pattern, ty, init, else_branch } => {
1475                // Type check let-else similar to let
1476                let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1477                let init_ty = self.infer_expr(init);
1478                // Infer evidence before moving init_ty
1479                let evidence = pattern
1480                    .evidentiality()
1481                    .map(EvidenceLevel::from_ast)
1482                    .unwrap_or_else(|| self.get_evidence(&init_ty));
1483                let final_ty = declared_ty.unwrap_or(init_ty);
1484                // Check else branch
1485                self.infer_expr(else_branch);
1486                if let Some(name) = pattern.binding_name() {
1487                    self.env.borrow_mut().define(name, final_ty, evidence);
1488                }
1489                Type::Unit
1490            }
1491            Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1492            Stmt::Item(item) => {
1493                self.check_item(item);
1494                Type::Unit
1495            }
1496        }
1497    }
1498
1499    /// Infer the type of an expression
1500    pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1501        match expr {
1502            Expr::Literal(lit) => self.infer_literal(lit),
1503
1504            Expr::Path(path) => {
1505                if path.segments.len() == 1 {
1506                    let name = &path.segments[0].ident.name;
1507                    if let Some((ty, _)) = self.env.borrow().lookup(name) {
1508                        return ty;
1509                    }
1510                    if let Some(ty) = self.functions.get(name).cloned() {
1511                        // Freshen polymorphic types to get fresh type variables
1512                        return self.freshen(&ty);
1513                    }
1514                } else if path.segments.len() == 2 {
1515                    // Handle Type::method() - associated function lookup
1516                    let type_name = &path.segments[0].ident.name;
1517                    let method_name = &path.segments[1].ident.name;
1518
1519                    // Check impl_methods for associated functions
1520                    if let Some(methods) = self.impl_methods.get(type_name) {
1521                        if let Some(ty) = methods.get(method_name) {
1522                            let ty_cloned = ty.clone();
1523                            return self.freshen(&ty_cloned);
1524                        }
1525                    }
1526
1527                    // Check for enum variant constructors: Enum::Variant
1528                    if let Some(TypeDef::Enum { variants, .. }) = self.types.get(type_name).cloned() {
1529                        for (variant_name, _variant_fields) in &variants {
1530                            if variant_name == method_name {
1531                                // Return the enum type for unit/tuple variants
1532                                return Type::Named {
1533                                    name: type_name.clone(),
1534                                    generics: vec![],
1535                                };
1536                            }
1537                        }
1538                        // Variant not found - report error
1539                        let available: Vec<_> = variants.iter().map(|(n, _)| n.as_str()).collect();
1540                        self.error(TypeError::new(format!(
1541                            "no variant '{}' on enum '{}'. Available variants: {}",
1542                            method_name, type_name, available.join(", ")
1543                        )));
1544                        return Type::Named {
1545                            name: type_name.clone(),
1546                            generics: vec![],
1547                        };
1548                    }
1549                }
1550                // For bootstrapping: treat undefined paths as unknown types
1551                // This allows cross-file references to not cause errors
1552                // A real type checker would require imports or multi-file analysis
1553                self.fresh_var()
1554            }
1555
1556            Expr::Binary { left, op, right } => {
1557                let lt = self.infer_expr(left);
1558                let rt = self.infer_expr(right);
1559                self.infer_binary_op(op, &lt, &rt)
1560            }
1561
1562            Expr::Unary { op, expr } => {
1563                let inner = self.infer_expr(expr);
1564                self.infer_unary_op(op, &inner)
1565            }
1566
1567            Expr::Call { func, args } => {
1568                let fn_type = self.infer_expr(func);
1569                let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1570
1571                if let Type::Function {
1572                    params,
1573                    return_type,
1574                    ..
1575                } = fn_type
1576                {
1577                    // Check argument count
1578                    if params.len() != arg_types.len() {
1579                        self.error(TypeError::new(format!(
1580                            "expected {} arguments, found {}",
1581                            params.len(),
1582                            arg_types.len()
1583                        )));
1584                    }
1585
1586                    // Check argument types and evidence levels
1587                    for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1588                        // Check argument type matches parameter type
1589                        if !self.unify(param, arg) {
1590                            // Allow implicit numeric coercion: int → float
1591                            let is_numeric_coercion = Self::is_numeric_coercion(param, arg);
1592                            // Only report error for concrete type mismatches, not type variables
1593                            if !matches!(param, Type::Var(_)) && !matches!(arg, Type::Var(_)) && !is_numeric_coercion {
1594                                self.error(TypeError::new(format!(
1595                                    "type mismatch in argument {}: expected {}, found {}",
1596                                    i + 1, param, arg
1597                                )));
1598                            }
1599                        }
1600
1601                        // Check evidence compatibility only for non-polymorphic parameters.
1602                        // Type variables (used in polymorphic functions like print, len, etc.)
1603                        // accept arguments of any evidence level.
1604                        if !matches!(param, Type::Var(_)) {
1605                            let expected_evidence = self.get_evidence(param);
1606                            let actual_evidence = self.get_evidence(arg);
1607                            self.check_evidence(
1608                                expected_evidence,
1609                                actual_evidence,
1610                                &format!("in argument {}", i + 1),
1611                            );
1612                        }
1613                    }
1614
1615                    *return_type
1616                } else if let Type::Var(_) = &fn_type {
1617                    // For bootstrapping: if function is a type variable (undefined path),
1618                    // create a function type and unify, then return fresh result
1619                    let result_ty = self.fresh_var();
1620                    let inferred_fn = Type::Function {
1621                        params: arg_types,
1622                        return_type: Box::new(result_ty.clone()),
1623                        is_async: false,
1624                    };
1625                    self.unify(&fn_type, &inferred_fn);
1626                    result_ty
1627                } else {
1628                    // For bootstrapping: return fresh type variable instead of error
1629                    self.fresh_var()
1630                }
1631            }
1632
1633            Expr::Array(elements) => {
1634                if elements.is_empty() {
1635                    Type::Array {
1636                        element: Box::new(self.fresh_var()),
1637                        size: Some(0),
1638                    }
1639                } else {
1640                    let elem_ty = self.infer_expr(&elements[0]);
1641                    for elem in &elements[1..] {
1642                        let t = self.infer_expr(elem);
1643                        if !self.unify(&elem_ty, &t) {
1644                            self.error(TypeError::new("array elements must have same type"));
1645                        }
1646                    }
1647                    Type::Array {
1648                        element: Box::new(elem_ty),
1649                        size: Some(elements.len()),
1650                    }
1651                }
1652            }
1653
1654            Expr::Tuple(elements) => {
1655                Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1656            }
1657
1658            Expr::Block(block) => self.check_block(block),
1659
1660            Expr::If {
1661                condition,
1662                then_branch,
1663                else_branch,
1664            } => {
1665                let cond_ty = self.infer_expr(condition);
1666                if !self.unify(&Type::Bool, &cond_ty) {
1667                    self.error(TypeError::new("if condition must be bool"));
1668                }
1669
1670                let then_ty = self.check_block(then_branch);
1671
1672                if let Some(else_expr) = else_branch {
1673                    // Else branch can be another expr (e.g., if-else chain) or a block
1674                    let else_ty = match else_expr.as_ref() {
1675                        Expr::Block(block) => self.check_block(block),
1676                        other => self.infer_expr(other),
1677                    };
1678                    // For bootstrapping: just try to unify, skip error if unification fails
1679                    // (type inference is incomplete so false positives are common)
1680                    let _ = self.unify(&then_ty, &else_ty);
1681
1682                    // Evidence inference for control flow:
1683                    // Join evidence from both branches (pessimistic - takes least certain)
1684                    // This ensures that if either branch produces uncertain data,
1685                    // the result is marked as uncertain.
1686                    let then_ev = self.get_evidence(&then_ty);
1687                    let else_ev = self.get_evidence(&else_ty);
1688                    let joined_ev = then_ev.join(else_ev);
1689
1690                    let (inner_ty, _) = self.strip_evidence(&then_ty);
1691                    if joined_ev > EvidenceLevel::Known {
1692                        Type::Evidential {
1693                            inner: Box::new(inner_ty),
1694                            evidence: joined_ev,
1695                        }
1696                    } else {
1697                        inner_ty
1698                    }
1699                } else {
1700                    Type::Unit
1701                }
1702            }
1703
1704            Expr::While {
1705                condition,
1706                body,
1707                ..
1708            } => {
1709                let cond_ty = self.infer_expr(condition);
1710                if !self.unify(&Type::Bool, &cond_ty) {
1711                    self.error(TypeError::new("while condition must be bool"));
1712                }
1713                self.check_block(body);
1714                Type::Unit
1715            }
1716
1717            Expr::Loop { body, .. } => {
1718                self.check_block(body);
1719                Type::Unit
1720            }
1721
1722            Expr::For {
1723                pattern: _,
1724                iter,
1725                body,
1726                ..
1727            } => {
1728                // Infer the iterable type (for basic type checking)
1729                let _ = self.infer_expr(iter);
1730                self.check_block(body);
1731                Type::Unit
1732            }
1733
1734            Expr::Pipe { expr, operations } => {
1735                let mut current = self.infer_expr(expr);
1736
1737                for op in operations {
1738                    current = self.infer_pipe_op(op, &current);
1739                }
1740
1741                current
1742            }
1743
1744            Expr::Index { expr, index } => {
1745                let coll_ty = self.infer_expr(expr);
1746                let idx_ty = self.infer_expr(index);
1747
1748                // Check for negative literal index
1749                if let Expr::Unary { op: UnaryOp::Neg, expr: inner } = index.as_ref() {
1750                    if let Expr::Literal(Literal::Int { .. }) = inner.as_ref() {
1751                        self.error(TypeError::new("negative index is not allowed"));
1752                    }
1753                }
1754
1755                match coll_ty {
1756                    Type::Array { element, .. } | Type::Slice(element) => {
1757                        if !matches!(idx_ty, Type::Int(_)) {
1758                            self.error(TypeError::new("index must be integer"));
1759                        }
1760                        *element
1761                    }
1762                    _ => {
1763                        // For bootstrapping: return fresh type variable
1764                        self.fresh_var()
1765                    }
1766                }
1767            }
1768
1769            Expr::Return(val) => {
1770                let actual_type = if let Some(e) = val {
1771                    self.infer_expr(e)
1772                } else {
1773                    Type::Unit
1774                };
1775
1776                // Check against expected return type if we're inside a function
1777                if let Some(expected) = self.expected_return_type.clone() {
1778                    if !self.unify(&expected, &actual_type) {
1779                        self.error(TypeError::new(format!(
1780                            "type mismatch in return: expected {}, found {}",
1781                            expected, actual_type
1782                        )));
1783                    }
1784                }
1785
1786                Type::Never
1787            }
1788
1789            // Assignment expression
1790            Expr::Assign { target, value } => {
1791                // Check if target is a simple variable
1792                if let Expr::Path(path) = target.as_ref() {
1793                    if path.segments.len() == 1 {
1794                        let name = &path.segments[0].ident.name;
1795                        // Check if variable is mutable
1796                        if !self.mutable_vars.contains(name) {
1797                            self.error(TypeError::new(format!(
1798                                "cannot assign to immutable variable '{}'",
1799                                name
1800                            )));
1801                        }
1802                    }
1803                }
1804                // Type check the value
1805                let val_ty = self.infer_expr(value);
1806                // Type check the target and ensure types match
1807                let target_ty = self.infer_expr(target);
1808                if !self.unify(&target_ty, &val_ty) {
1809                    self.error(TypeError::new(format!(
1810                        "type mismatch in assignment: expected {}, found {}",
1811                        target_ty, val_ty
1812                    )));
1813                }
1814                Type::Unit
1815            }
1816
1817            // Mark expression with evidence
1818            Expr::Evidential {
1819                expr,
1820                evidentiality,
1821            } => {
1822                let inner = self.infer_expr(expr);
1823                Type::Evidential {
1824                    inner: Box::new(inner),
1825                    evidence: EvidenceLevel::from_ast(*evidentiality),
1826                }
1827            }
1828
1829            // Match expression with evidence-aware dispatch
1830            Expr::Match { expr, arms } => {
1831                let scrutinee = self.infer_expr(expr);
1832                let scrutinee_ev = self.get_evidence(&scrutinee);
1833
1834                if arms.is_empty() {
1835                    return Type::Never; // Empty match is diverging
1836                }
1837
1838                // Check all arms and collect their types
1839                let mut arm_types: Vec<Type> = Vec::new();
1840                let mut max_evidence = EvidenceLevel::Known;
1841
1842                for arm in arms {
1843                    self.push_scope();
1844
1845                    // Bind pattern variables with scrutinee's evidence level
1846                    // This propagates evidence through pattern matching
1847                    self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
1848
1849                    // Check guard if present
1850                    if let Some(ref guard) = arm.guard {
1851                        let guard_ty = self.infer_expr(guard);
1852                        if !self.unify(&Type::Bool, &guard_ty) {
1853                            self.error(TypeError::new("match guard must be bool"));
1854                        }
1855                    }
1856
1857                    // Infer arm body type
1858                    let body_ty = self.infer_expr(&arm.body);
1859                    let body_ev = self.get_evidence(&body_ty);
1860
1861                    // Join evidence from all arms (pessimistic)
1862                    max_evidence = max_evidence.join(body_ev);
1863                    arm_types.push(body_ty);
1864
1865                    self.pop_scope();
1866                }
1867
1868                // Unify all arm types - ensure all arms return same type
1869                let first_ty = &arm_types[0];
1870                for (i, ty) in arm_types.iter().enumerate().skip(1) {
1871                    if !self.unify(first_ty, ty) {
1872                        self.error(TypeError::new(format!(
1873                            "type mismatch in match arm {}: expected {:?}, found {:?}",
1874                            i + 1, first_ty, ty
1875                        )));
1876                    }
1877                }
1878
1879                // Result has joined evidence from all arms
1880                let (inner_ty, _) = self.strip_evidence(first_ty);
1881                if max_evidence > EvidenceLevel::Known {
1882                    Type::Evidential {
1883                        inner: Box::new(inner_ty),
1884                        evidence: max_evidence,
1885                    }
1886                } else {
1887                    inner_ty
1888                }
1889            }
1890
1891            Expr::MethodCall {
1892                receiver,
1893                method,
1894                args,
1895                ..
1896            } => {
1897                let recv_ty = self.infer_expr(receiver);
1898                let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
1899                let _arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1900
1901                // Resolve known methods based on receiver type and method name
1902                let result_ty = match method.name.as_str() {
1903                    // Collection methods returning usize
1904                    "len" | "count" | "size" => Type::Int(IntSize::USize),
1905
1906                    // Boolean predicates
1907                    "is_empty" | "contains" | "starts_with" | "ends_with" | "is_some"
1908                    | "is_none" | "is_ok" | "is_err" | "is_ascii" | "is_alphabetic"
1909                    | "is_numeric" | "is_alphanumeric" | "is_whitespace" | "is_uppercase"
1910                    | "is_lowercase" | "exists" | "is_file" | "is_dir" | "is_match"
1911                    | "matches" | "eq" | "ne" | "lt" | "le" | "gt" | "ge" => Type::Bool,
1912
1913                    // String methods returning String
1914                    "to_string" | "to_lowercase" | "to_uppercase" | "trim" | "trim_start"
1915                    | "trim_end" | "to_owned" | "replace" | "replacen" | "repeat"
1916                    | "to_string_lossy" => Type::Named {
1917                        name: "String".to_string(),
1918                        generics: vec![],
1919                    },
1920
1921                    // String methods returning &str
1922                    "as_str" | "trim_matches" | "trim_start_matches" | "trim_end_matches"
1923                    | "strip_prefix" | "strip_suffix" => Type::Ref {
1924                        lifetime: None,
1925                        mutable: false,
1926                        inner: Box::new(Type::Str),
1927                    },
1928
1929                    // Clone returns same type as receiver
1930                    "clone" | "cloned" | "copied" => recv_inner.clone(),
1931
1932                    // Option/Result unwrapping - return inner type or fresh var
1933                    "unwrap" | "unwrap_or" | "unwrap_or_default" | "unwrap_or_else"
1934                    | "expect" | "ok" | "err" => {
1935                        if let Type::Named { name, generics } = &recv_inner {
1936                            if (name == "Option" || name == "Result") && !generics.is_empty() {
1937                                generics[0].clone()
1938                            } else {
1939                                self.fresh_var()
1940                            }
1941                        } else {
1942                            self.fresh_var()
1943                        }
1944                    }
1945
1946                    // collect() returns fresh var to unify with type annotation
1947                    "collect" => self.fresh_var(),
1948
1949                    // Iterator/collection transformation methods - preserve receiver type
1950                    "iter" | "into_iter" | "iter_mut" | "rev" | "skip" | "take"
1951                    | "filter" | "map" | "filter_map" | "flat_map" | "enumerate"
1952                    | "zip" | "chain" | "flatten" | "reverse" | "sorted"
1953                    | "dedup" | "unique" | "peekable" | "fuse" | "cycle" | "step_by"
1954                    | "take_while" | "skip_while" | "scan" | "inspect" => recv_inner.clone(),
1955
1956                    // String splitting/iteration - returns iterator (fresh var for proper chaining)
1957                    "split" | "rsplit" | "splitn" | "rsplitn" | "split_whitespace"
1958                    | "split_ascii_whitespace" | "lines" | "chars" | "bytes"
1959                    | "char_indices" | "split_terminator" | "rsplit_terminator"
1960                    | "split_inclusive" | "matches_iter" => self.fresh_var(),
1961
1962                    // HashMap/BTreeMap methods - return iterator-like fresh var
1963                    "keys" | "values" | "values_mut" | "into_keys"
1964                    | "into_values" | "entry" | "drain" => self.fresh_var(),
1965
1966                    // Methods returning Option<T>
1967                    "first" | "last" | "get" | "get_mut" | "pop" | "pop_front"
1968                    | "pop_back" | "find" | "find_map" | "position" | "rposition"
1969                    | "next" | "next_back" | "peek" | "nth" | "last_mut"
1970                    | "binary_search" | "parent" | "file_name" | "file_stem"
1971                    | "extension" => Type::Named {
1972                        name: "Option".to_string(),
1973                        generics: vec![self.fresh_var()],
1974                    },
1975
1976                    // Methods returning Result
1977                    "parse" | "try_into" | "try_from" => Type::Named {
1978                        name: "Result".to_string(),
1979                        generics: vec![self.fresh_var(), self.fresh_var()],
1980                    },
1981
1982                    // Push method - check argument type against Vec's element type
1983                    "push" => {
1984                        // For Vec<T>, push takes T as argument
1985                        if let Type::Named { name, generics } = &recv_inner {
1986                            if name == "Vec" && !generics.is_empty() && !_arg_types.is_empty() {
1987                                let elem_ty = &generics[0];
1988                                let arg_ty = &_arg_types[0];
1989                                if !self.unify(elem_ty, arg_ty) {
1990                                    self.error(TypeError::new(format!(
1991                                        "type mismatch in Vec::push: expected {}, found {}",
1992                                        elem_ty, arg_ty
1993                                    )));
1994                                }
1995                            }
1996                        }
1997                        Type::Unit
1998                    }
1999
2000                    // Other mutating methods return unit
2001                    "push_str" | "push_front" | "push_back" | "insert"
2002                    | "remove" | "clear" | "sort" | "sort_by" | "sort_by_key"
2003                    | "sort_unstable" | "truncate" | "resize" | "extend" | "append"
2004                    | "retain" | "swap" | "swap_remove" => Type::Unit,
2005
2006                    // Numeric methods
2007                    "abs" | "floor" | "ceil" | "round" | "trunc" | "fract" | "sqrt"
2008                    | "cbrt" | "sin" | "cos" | "tan" | "asin" | "acos" | "atan"
2009                    | "sinh" | "cosh" | "tanh" | "exp" | "exp2" | "ln" | "log"
2010                    | "log2" | "log10" | "pow" | "powi" | "powf" | "min" | "max"
2011                    | "clamp" | "signum" | "copysign" | "saturating_add"
2012                    | "saturating_sub" | "saturating_mul" | "wrapping_add"
2013                    | "wrapping_sub" | "wrapping_mul" | "checked_add" | "checked_sub"
2014                    | "checked_mul" | "checked_div" => recv_inner.clone(),
2015
2016                    // Char methods
2017                    "to_digit" | "to_lowercase_char" | "to_uppercase_char" => Type::Named {
2018                        name: "Option".to_string(),
2019                        generics: vec![Type::Int(IntSize::U32)],
2020                    },
2021
2022                    // Duration/Time methods
2023                    "duration_since" | "elapsed" | "as_secs" | "as_millis" | "as_micros"
2024                    | "as_nanos" | "from_secs" | "from_millis" => recv_inner.clone(),
2025
2026                    // Path methods returning PathBuf/String
2027                    "to_path_buf" | "join" | "with_extension" | "with_file_name" => {
2028                        Type::Named {
2029                            name: "PathBuf".to_string(),
2030                            generics: vec![],
2031                        }
2032                    }
2033
2034                    // Path methods returning &str via OsStr
2035                    "to_str" => Type::Named {
2036                        name: "Option".to_string(),
2037                        generics: vec![Type::Ref {
2038                            lifetime: None,
2039                            mutable: false,
2040                            inner: Box::new(Type::Str),
2041                        }],
2042                    },
2043
2044                    // Formatting
2045                    "fmt" | "write_str" | "write_fmt" => Type::Named {
2046                        name: "Result".to_string(),
2047                        generics: vec![Type::Unit, self.fresh_var()],
2048                    },
2049
2050                    // IO methods
2051                    "read" | "write" | "flush" | "read_to_string" | "read_to_end"
2052                    | "read_line" | "write_all" => Type::Named {
2053                        name: "Result".to_string(),
2054                        generics: vec![self.fresh_var(), self.fresh_var()],
2055                    },
2056
2057                    // fs metadata
2058                    "metadata" | "modified" | "created" | "accessed" | "len_file"
2059                    | "is_readonly" | "permissions" => Type::Named {
2060                        name: "Result".to_string(),
2061                        generics: vec![self.fresh_var(), self.fresh_var()],
2062                    },
2063
2064                    // Map error
2065                    "map_err" | "and_then" | "or_else" => recv_inner.clone(),
2066
2067                    // and/or for Option/Result
2068                    "and" | "or" => recv_inner.clone(),
2069
2070                    // Default: check if type is known primitive - report error for unknown methods
2071                    _ => {
2072                        // Check if receiver is a primitive type
2073                        let is_primitive = matches!(
2074                            &recv_inner,
2075                            Type::Int(_) | Type::Float(_) | Type::Bool | Type::Char | Type::Str | Type::Unit
2076                        );
2077                        if is_primitive {
2078                            self.error(TypeError::new(format!(
2079                                "no method '{}' on primitive type {:?}",
2080                                method.name, recv_inner
2081                            )));
2082                        }
2083                        self.fresh_var()
2084                    }
2085                };
2086
2087                // Propagate evidence from receiver
2088                if recv_ev > EvidenceLevel::Known {
2089                    Type::Evidential {
2090                        inner: Box::new(result_ty),
2091                        evidence: recv_ev,
2092                    }
2093                } else {
2094                    result_ty
2095                }
2096            }
2097
2098            Expr::Field { expr, field } => {
2099                let recv_ty = self.infer_expr(expr);
2100                let (recv_inner, recv_ev) = self.strip_evidence(&recv_ty);
2101
2102                // Try to resolve field type from struct definition
2103                let field_ty = if let Type::Named { name, .. } = &recv_inner {
2104                    // Look up struct definition in type definitions
2105                    if let Some(struct_def) = self.types.get(name) {
2106                        if let TypeDef::Struct { fields, .. } = struct_def {
2107                            if let Some((_, ty)) = fields.iter().find(|(n, _)| n == &field.name) {
2108                                ty.clone()
2109                            } else {
2110                                // Field not found on known struct - report error
2111                                let available: Vec<_> = fields.iter().map(|(n, _)| n.as_str()).collect();
2112                                self.error(TypeError::new(format!(
2113                                    "no field '{}' on type '{}'. Available fields: {}",
2114                                    field.name, name, available.join(", ")
2115                                )));
2116                                self.fresh_var()
2117                            }
2118                        } else {
2119                            self.fresh_var()
2120                        }
2121                    } else {
2122                        self.fresh_var()
2123                    }
2124                } else {
2125                    self.fresh_var()
2126                };
2127
2128                // Propagate evidence from receiver
2129                if recv_ev > EvidenceLevel::Known {
2130                    Type::Evidential {
2131                        inner: Box::new(field_ty),
2132                        evidence: recv_ev,
2133                    }
2134                } else {
2135                    field_ty
2136                }
2137            }
2138
2139            Expr::Index { expr, index, .. } => {
2140                let arr_ty = self.infer_expr(expr);
2141                let idx_ty = self.infer_expr(index);
2142                let (arr_inner, arr_ev) = self.strip_evidence(&arr_ty);
2143
2144                // Index should be usize
2145                let _ = self.unify(&idx_ty, &Type::Int(IntSize::USize));
2146
2147                // Get element type from array/slice
2148                let elem_ty = match arr_inner {
2149                    Type::Array { element, .. } => *element,
2150                    Type::Slice(element) => *element,
2151                    Type::Named { name, generics } if name == "Vec" && !generics.is_empty() => {
2152                        generics[0].clone()
2153                    }
2154                    _ => self.fresh_var(),
2155                };
2156
2157                // Propagate evidence
2158                if arr_ev > EvidenceLevel::Known {
2159                    Type::Evidential {
2160                        inner: Box::new(elem_ty),
2161                        evidence: arr_ev,
2162                    }
2163                } else {
2164                    elem_ty
2165                }
2166            }
2167
2168            Expr::Struct { path, fields, rest: _ } => {
2169                // Get struct name from path
2170                let struct_name = path.segments.first()
2171                    .map(|s| s.ident.name.clone())
2172                    .unwrap_or_default();
2173
2174                // Check struct exists and validate fields
2175                if let Some(TypeDef::Struct { fields: struct_fields, generics }) = self.types.get(&struct_name).cloned() {
2176                    // Check all provided fields exist
2177                    for field_init in fields {
2178                        let field_name = &field_init.name.name;
2179                        if !struct_fields.iter().any(|(n, _)| n == field_name) {
2180                            self.error(TypeError::new(format!(
2181                                "unknown field '{}' on struct '{}'",
2182                                field_name, struct_name
2183                            )));
2184                        }
2185                        // Type check the field value if present
2186                        if let Some(ref value) = field_init.value {
2187                            self.infer_expr(value);
2188                        }
2189                    }
2190
2191                    // Check for missing required fields
2192                    let provided: std::collections::HashSet<_> = fields.iter().map(|f| f.name.name.as_str()).collect();
2193                    for (field_name, _) in &struct_fields {
2194                        if !provided.contains(field_name.as_str()) {
2195                            self.error(TypeError::new(format!(
2196                                "missing field '{}' in struct '{}'",
2197                                field_name, struct_name
2198                            )));
2199                        }
2200                    }
2201
2202                    // Return the named struct type
2203                    Type::Named {
2204                        name: struct_name,
2205                        generics: generics.iter().map(|_| self.fresh_var()).collect(),
2206                    }
2207                } else {
2208                    // Unknown struct type
2209                    self.error(TypeError::new(format!(
2210                        "unknown struct type '{}'",
2211                        struct_name
2212                    )));
2213                    self.fresh_var()
2214                }
2215            }
2216
2217            _ => {
2218                // Handle other expression types
2219                self.fresh_var()
2220            }
2221        }
2222    }
2223
2224    /// Infer type from literal
2225    fn infer_literal(&self, lit: &Literal) -> Type {
2226        match lit {
2227            Literal::Int { .. } => Type::Int(IntSize::I64),
2228            Literal::Float { suffix, .. } => {
2229                match suffix.as_ref().map(|s| s.as_str()) {
2230                    Some("f32") => Type::Float(FloatSize::F32),
2231                    Some("f64") => Type::Float(FloatSize::F64),
2232                    // Default to f64 for unsuffixed or other suffixes
2233                    None | Some(_) => Type::Float(FloatSize::F64),
2234                }
2235            }
2236            Literal::Bool(_) => Type::Bool,
2237            Literal::Char(_) => Type::Char,
2238            Literal::ByteChar(_) => Type::Int(IntSize::U8),
2239            // String literals have type &str
2240            Literal::String(_) => Type::Ref {
2241                lifetime: None,
2242                mutable: false,
2243                inner: Box::new(Type::Str),
2244            },
2245            Literal::MultiLineString(_) => Type::Ref {
2246                lifetime: None,
2247                mutable: false,
2248                inner: Box::new(Type::Str),
2249            },
2250            Literal::RawString(_) => Type::Ref {
2251                lifetime: None,
2252                mutable: false,
2253                inner: Box::new(Type::Str),
2254            },
2255            Literal::ByteString(bytes) => Type::Ref {
2256                lifetime: None,
2257                mutable: false,
2258                inner: Box::new(Type::Array {
2259                    element: Box::new(Type::Int(IntSize::U8)),
2260                    size: Some(bytes.len()),
2261                }),
2262            },
2263            Literal::InterpolatedString { .. } => Type::Str,
2264            Literal::SigilStringSql(_) => Type::Str,
2265            Literal::SigilStringRoute(_) => Type::Str,
2266            Literal::Null => Type::Unit, // null has unit type
2267            Literal::Empty => Type::Unit,
2268            Literal::Infinity => Type::Float(FloatSize::F64),
2269            Literal::Circle => Type::Float(FloatSize::F64),
2270        }
2271    }
2272
2273    /// Infer type of binary operation
2274    fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
2275        // Extract evidence levels for propagation
2276        let (left_inner, left_ev) = self.strip_evidence(left);
2277        let (right_inner, right_ev) = self.strip_evidence(right);
2278
2279        // Helper to detect type variable or function types (incomplete inference)
2280        let is_var_or_fn = |ty: &Type| {
2281            matches!(ty, Type::Var(_) | Type::Function { .. })
2282        };
2283
2284        let result_ty = match op {
2285            // Arithmetic: numeric -> numeric
2286            BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
2287                // For bootstrapping: just try to unify, skip error if unification fails
2288                // (type inference is incomplete so false positives are common with integer types)
2289                let _ = self.unify(&left_inner, &right_inner);
2290                left_inner
2291            }
2292
2293            // Matrix multiplication: tensor @ tensor -> tensor
2294            // Hadamard/element-wise: tensor ⊙ tensor -> tensor
2295            // Tensor product: tensor ⊗ tensor -> tensor
2296            BinOp::MatMul | BinOp::Hadamard | BinOp::TensorProd => {
2297                // Return a fresh type variable for now (proper tensor type checking would go here)
2298                self.fresh_var()
2299            }
2300
2301            // Comparison: any -> bool
2302            BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
2303                // For bootstrapping: skip error when either side is a type variable or function
2304                // (indicates incomplete type inference from unhandled expressions)
2305                if !self.unify(&left_inner, &right_inner)
2306                    && !is_var_or_fn(&left_inner)
2307                    && !is_var_or_fn(&right_inner)
2308                {
2309                    self.error(TypeError::new(format!(
2310                        "comparison operands must have same type: left={:?}, right={:?}",
2311                        left_inner, right_inner
2312                    )));
2313                }
2314                Type::Bool
2315            }
2316
2317            // Logical: bool -> bool
2318            BinOp::And | BinOp::Or => {
2319                if !self.unify(&Type::Bool, &left_inner) {
2320                    self.error(TypeError::new("logical operand must be bool"));
2321                }
2322                if !self.unify(&Type::Bool, &right_inner) {
2323                    self.error(TypeError::new("logical operand must be bool"));
2324                }
2325                Type::Bool
2326            }
2327
2328            // Bitwise: int -> int
2329            BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
2330
2331            // String concatenation
2332            BinOp::Concat => {
2333                if !self.unify(&Type::Str, &left_inner) {
2334                    self.error(TypeError::new("concat operand must be string"));
2335                }
2336                Type::Str
2337            }
2338        };
2339
2340        // Combine evidence levels
2341        let combined_ev = left_ev.join(right_ev);
2342
2343        // Wrap result in evidence if either operand had evidence
2344        if combined_ev > EvidenceLevel::Known {
2345            Type::Evidential {
2346                inner: Box::new(result_ty),
2347                evidence: combined_ev,
2348            }
2349        } else {
2350            result_ty
2351        }
2352    }
2353
2354    /// Infer type of unary operation
2355    fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
2356        let (inner_ty, evidence) = self.strip_evidence(inner);
2357
2358        let result = match op {
2359            UnaryOp::Neg => inner_ty,
2360            UnaryOp::Not => {
2361                // ! operator requires bool operand
2362                if !self.unify(&Type::Bool, &inner_ty) {
2363                    self.error(TypeError::new(format!(
2364                        "type mismatch: '!' requires bool, found {}",
2365                        inner_ty
2366                    )));
2367                }
2368                Type::Bool
2369            }
2370            UnaryOp::Ref => Type::Ref {
2371                lifetime: None,
2372                mutable: false,
2373                inner: Box::new(inner_ty),
2374            },
2375            UnaryOp::RefMut => Type::Ref {
2376                lifetime: None,
2377                mutable: true,
2378                inner: Box::new(inner_ty),
2379            },
2380            UnaryOp::Deref => {
2381                if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
2382                    *inner
2383                } else {
2384                    // For bootstrapping: return fresh type variable
2385                    self.fresh_var()
2386                }
2387            }
2388        };
2389
2390        // Preserve evidence
2391        if evidence > EvidenceLevel::Known {
2392            Type::Evidential {
2393                inner: Box::new(result),
2394                evidence,
2395            }
2396        } else {
2397            result
2398        }
2399    }
2400
2401    /// Infer type of pipe operation
2402    fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
2403        let (inner_ev_stripped, evidence) = self.strip_evidence(input);
2404
2405        // Also strip reference wrapper for pipe operations
2406        // This allows `&[T]` to be treated as `[T]` in pipes
2407        let inner = match inner_ev_stripped {
2408            Type::Ref { inner: ref_inner, .. } => (*ref_inner).clone(),
2409            other => other,
2410        };
2411
2412        let result = match op {
2413            // Transform: [T] -> [U] where body: T -> U
2414            PipeOp::Transform(_body) => {
2415                if let Type::Array { element, size } = inner {
2416                    Type::Array { element, size }
2417                } else if let Type::Slice(element) = inner {
2418                    Type::Slice(element)
2419                } else {
2420                    // For bootstrapping: return fresh type variable
2421                    self.fresh_var()
2422                }
2423            }
2424
2425            // Filter: [T] -> [T]
2426            PipeOp::Filter(_pred) => inner,
2427
2428            // Sort: [T] -> [T]
2429            PipeOp::Sort(_) => inner,
2430
2431            // Reduce: [T] -> T (also Vec<T> -> T)
2432            PipeOp::Reduce(_) => {
2433                if let Type::Array { element, .. } | Type::Slice(element) = inner {
2434                    *element
2435                } else if let Type::Named { name, generics } = &inner {
2436                    // Support Vec<T>, LinkedList<T>, etc.
2437                    if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2438                        && !generics.is_empty() {
2439                        generics[0].clone()
2440                    } else {
2441                        self.fresh_var()
2442                    }
2443                } else if let Type::Var(_) = inner {
2444                    // For bootstrapping: return fresh type variable when input is unknown
2445                    self.fresh_var()
2446                } else {
2447                    self.error(TypeError::new("reduce requires array or slice"));
2448                    Type::Error
2449                }
2450            }
2451            PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
2452                // Numeric reductions return the element type
2453                let element = if let Type::Array { element, .. } | Type::Slice(element) = &inner {
2454                    Some(element.clone())
2455                } else if let Type::Named { name, generics } = &inner {
2456                    // Support Vec<T>, etc.
2457                    if (name == "Vec" || name == "LinkedList" || name == "VecDeque")
2458                        && !generics.is_empty() {
2459                        Some(Box::new(generics[0].clone()))
2460                    } else {
2461                        None
2462                    }
2463                } else {
2464                    None
2465                };
2466                if let Some(element) = element {
2467                    match element.as_ref() {
2468                        Type::Int(_) | Type::Float(_) => *element,
2469                        Type::Var(_) => *element, // For bootstrapping: allow type variables
2470                        _ => {
2471                            self.error(TypeError::new("numeric reduction requires numeric array"));
2472                            Type::Error
2473                        }
2474                    }
2475                } else if let Type::Var(_) = inner {
2476                    // For bootstrapping: return fresh type variable when input is unknown
2477                    self.fresh_var()
2478                } else {
2479                    self.error(TypeError::new("reduction requires array or slice"));
2480                    Type::Error
2481                }
2482            }
2483            PipeOp::ReduceConcat => {
2484                // Concat returns string or array depending on element type
2485                if let Type::Array { element, .. } | Type::Slice(element) = inner {
2486                    match element.as_ref() {
2487                        Type::Str => Type::Str,
2488                        Type::Array { .. } => *element,
2489                        Type::Var(_) => self.fresh_var(), // For bootstrapping
2490                        _ => {
2491                            self.error(TypeError::new(
2492                                "concat reduction requires array of strings or arrays",
2493                            ));
2494                            Type::Error
2495                        }
2496                    }
2497                } else if let Type::Var(_) = inner {
2498                    // For bootstrapping: return fresh type variable
2499                    self.fresh_var()
2500                } else {
2501                    self.error(TypeError::new("concat reduction requires array or slice"));
2502                    Type::Error
2503                }
2504            }
2505            PipeOp::ReduceAll | PipeOp::ReduceAny => {
2506                // Boolean reductions return bool
2507                if let Type::Array { element, .. } | Type::Slice(element) = inner {
2508                    match element.as_ref() {
2509                        Type::Bool => Type::Bool,
2510                        Type::Var(_) => Type::Bool, // For bootstrapping: assume bool
2511                        _ => {
2512                            self.error(TypeError::new(
2513                                "boolean reduction requires array of booleans",
2514                            ));
2515                            Type::Error
2516                        }
2517                    }
2518                } else if let Type::Var(_) = inner {
2519                    // For bootstrapping: return bool
2520                    Type::Bool
2521                } else {
2522                    self.error(TypeError::new("boolean reduction requires array or slice"));
2523                    Type::Error
2524                }
2525            }
2526
2527            // Match morpheme: |match{ Pattern => expr, ... }
2528            PipeOp::Match(arms) => {
2529                // All arms should return the same type
2530                if arms.is_empty() {
2531                    self.error(TypeError::new("match expression has no arms"));
2532                    Type::Error
2533                } else {
2534                    // Infer type from first arm, other arms should match
2535                    let result_type = self.infer_expr(&arms[0].body);
2536                    for arm in arms.iter().skip(1) {
2537                        let arm_type = self.infer_expr(&arm.body);
2538                        self.unify(&result_type, &arm_type);
2539                    }
2540                    result_type
2541                }
2542            }
2543
2544            // Try/Error transformation: |? or |?{mapper}
2545            PipeOp::TryMap(_) => {
2546                // Unwraps Result<T, E> to T or Option<T> to T
2547                // For now, return a fresh type variable
2548                // (proper implementation would extract inner type from Result/Option)
2549                self.fresh_var()
2550            }
2551
2552            // Call expression (like |self.layer)
2553            PipeOp::Call(callee) => {
2554                // Infer the type of the callee and extract return type
2555                let callee_ty = self.infer_expr(callee);
2556                if let Type::Function { return_type, .. } = callee_ty {
2557                    *return_type
2558                } else {
2559                    // Could be a callable struct or closure, return fresh var
2560                    self.fresh_var()
2561                }
2562            }
2563
2564            // Method call
2565            PipeOp::Method { name, type_args: _, args: _ } => {
2566                // Look up method
2567                if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
2568                    // Freshen to get fresh type variables for polymorphic functions
2569                    let fresh_ty = self.freshen(&fn_ty);
2570                    if let Type::Function { return_type, .. } = fresh_ty {
2571                        *return_type
2572                    } else {
2573                        Type::Error
2574                    }
2575                } else {
2576                    // Could be a method on the type
2577                    self.fresh_var()
2578                }
2579            }
2580
2581            // Named operation (morpheme)
2582            PipeOp::Named { prefix, body: _ } => {
2583                // Named operations like |sum, |product
2584                if let Some(first) = prefix.first() {
2585                    match first.name.as_str() {
2586                        "sum" | "product" => {
2587                            if let Type::Array { element, .. } | Type::Slice(element) = inner {
2588                                *element
2589                            } else {
2590                                self.error(TypeError::new("sum/product requires array"));
2591                                Type::Error
2592                            }
2593                        }
2594                        _ => self.fresh_var(),
2595                    }
2596                } else {
2597                    self.fresh_var()
2598                }
2599            }
2600
2601            // Await: unwrap future
2602            PipeOp::Await => {
2603                // Future<T> -> T
2604                inner
2605            }
2606
2607            // Access morphemes: [T] -> T (return element type)
2608            PipeOp::First
2609            | PipeOp::Last
2610            | PipeOp::Middle
2611            | PipeOp::Choice
2612            | PipeOp::Nth(_)
2613            | PipeOp::Next => {
2614                if let Type::Array { element, .. } | Type::Slice(element) = inner {
2615                    *element
2616                } else if let Type::Named { name, generics } = &inner {
2617                    // Support Vec<T>, VecDeque<T>, etc.
2618                    if (name == "Vec" || name == "VecDeque" || name == "LinkedList")
2619                        && !generics.is_empty() {
2620                        generics[0].clone()
2621                    } else {
2622                        self.fresh_var()
2623                    }
2624                } else if let Type::Tuple(elements) = inner {
2625                    // For tuple, return Any since elements might be different types
2626                    if let Some(first) = elements.first() {
2627                        first.clone()
2628                    } else {
2629                        Type::Unit
2630                    }
2631                } else if let Type::Var(_) = inner {
2632                    // For bootstrapping: return fresh type variable
2633                    self.fresh_var()
2634                } else {
2635                    // For bootstrapping: allow access on unknown types, return fresh var
2636                    self.fresh_var()
2637                }
2638            }
2639
2640            // Parallel morpheme: ∥ - wraps another operation
2641            // Type is determined by the inner operation
2642            PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
2643
2644            // GPU morpheme: ⊛ - wraps another operation for GPU execution
2645            // Type is determined by the inner operation
2646            PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
2647
2648            // ==========================================
2649            // Protocol Operations - Sigil-native networking
2650            // All protocol results have Reported evidentiality
2651            // ==========================================
2652
2653            // Send: connection -> response (with Reported evidence)
2654            PipeOp::Send(_) => {
2655                // Returns response object with Reported evidentiality
2656                Type::Evidential {
2657                    inner: Box::new(self.fresh_var()),
2658                    evidence: EvidenceLevel::Reported,
2659                }
2660            }
2661
2662            // Recv: connection -> data (with Reported evidence)
2663            PipeOp::Recv => {
2664                // Returns received data with Reported evidentiality
2665                Type::Evidential {
2666                    inner: Box::new(self.fresh_var()),
2667                    evidence: EvidenceLevel::Reported,
2668                }
2669            }
2670
2671            // Stream: connection -> Stream<T> (elements have Reported evidence)
2672            PipeOp::Stream(_) => {
2673                // Returns a stream type
2674                self.fresh_var()
2675            }
2676
2677            // Connect: url/config -> connection
2678            PipeOp::Connect(_) => {
2679                // Returns connection object
2680                self.fresh_var()
2681            }
2682
2683            // Close: connection -> ()
2684            PipeOp::Close => Type::Unit,
2685
2686            // Header: request -> request (adds header)
2687            PipeOp::Header { .. } => inner,
2688
2689            // Body: request -> request (sets body)
2690            PipeOp::Body(_) => inner,
2691
2692            // Timeout: request -> request (sets timeout)
2693            PipeOp::Timeout(_) => inner,
2694
2695            // Retry: request -> request (sets retry policy)
2696            PipeOp::Retry { .. } => inner,
2697
2698            // ==========================================
2699            // Evidence Promotion Operations
2700            // ==========================================
2701
2702            // Validate: T~ -> T! (promotes with validation)
2703            PipeOp::Validate {
2704                predicate: _,
2705                target_evidence,
2706            } => {
2707                // Check that the predicate returns bool
2708                // (We'd need to infer the closure type properly, skipping for now)
2709
2710                let target_ev = EvidenceLevel::from_ast(*target_evidence);
2711
2712                // Validation can only promote evidence (make more certain)
2713                if evidence < target_ev {
2714                    self.error(
2715                        TypeError::new(format!(
2716                            "cannot demote evidence from {} ({}) to {} ({}) using validate",
2717                            evidence.name(),
2718                            evidence.symbol(),
2719                            target_ev.name(),
2720                            target_ev.symbol()
2721                        ))
2722                        .with_note("validate! can only promote evidence to a more certain level"),
2723                    );
2724                }
2725
2726                // Return inner type with promoted evidence
2727                return Type::Evidential {
2728                    inner: Box::new(inner.clone()),
2729                    evidence: target_ev,
2730                };
2731            }
2732
2733            // Assume: T~ -> T! (explicit trust with audit trail)
2734            PipeOp::Assume {
2735                reason: _,
2736                target_evidence,
2737            } => {
2738                let target_ev = EvidenceLevel::from_ast(*target_evidence);
2739
2740                // Assumption always succeeds but should be logged/audited
2741                // In a real implementation, this would record for security review
2742
2743                if evidence < target_ev {
2744                    self.error(
2745                        TypeError::new(format!(
2746                            "assume! cannot demote evidence from {} ({}) to {} ({})",
2747                            evidence.name(),
2748                            evidence.symbol(),
2749                            target_ev.name(),
2750                            target_ev.symbol()
2751                        ))
2752                        .with_note("assume! is for promoting evidence, not demoting"),
2753                    );
2754                }
2755
2756                // Return inner type with assumed evidence
2757                return Type::Evidential {
2758                    inner: Box::new(inner.clone()),
2759                    evidence: target_ev,
2760                };
2761            }
2762
2763            // AssertEvidence: compile-time evidence check
2764            PipeOp::AssertEvidence(expected_ast) => {
2765                let expected = EvidenceLevel::from_ast(*expected_ast);
2766
2767                if !evidence.satisfies(expected) {
2768                    self.error(
2769                        TypeError::new(format!(
2770                            "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
2771                            expected.name(), expected.symbol(),
2772                            evidence.name(), evidence.symbol()
2773                        ))
2774                        .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
2775                    );
2776                }
2777
2778                // Return the same type (this is just an assertion)
2779                return input.clone();
2780            }
2781
2782            // ==========================================
2783            // Scope Functions (Kotlin-inspired)
2784            // ==========================================
2785
2786            // Also: execute side effect, return original value unchanged
2787            // T -> T (side effect executed but value preserved)
2788            PipeOp::Also(_) => {
2789                // The closure is executed for side effects only
2790                // Return type is same as input, evidence preserved
2791                return input.clone();
2792            }
2793
2794            // Apply: mutate value in place, return modified value
2795            // T -> T (value may be mutated)
2796            PipeOp::Apply(_) => {
2797                // The closure can mutate the value
2798                // Return type is same as input, evidence preserved
2799                return input.clone();
2800            }
2801
2802            // TakeIf: return Some(value) if predicate true, None otherwise
2803            // T -> Option<T>
2804            PipeOp::TakeIf(_) => {
2805                // Returns Option wrapping the input type
2806                // Evidence is preserved in the inner type
2807                return Type::Named {
2808                    name: "Option".to_string(),
2809                    generics: vec![input.clone()],
2810                };
2811            }
2812
2813            // TakeUnless: return Some(value) if predicate false, None otherwise
2814            // T -> Option<T>
2815            PipeOp::TakeUnless(_) => {
2816                // Returns Option wrapping the input type
2817                // Evidence is preserved in the inner type
2818                return Type::Named {
2819                    name: "Option".to_string(),
2820                    generics: vec![input.clone()],
2821                };
2822            }
2823
2824            // Let: transform value (alias for Transform/tau)
2825            // T -> U
2826            PipeOp::Let(func) => {
2827                // Same as Transform - applies function and returns result
2828                let _ = self.infer_expr(func);
2829                self.fresh_var() // Result type depends on function
2830            }
2831
2832            // Mathematical & APL-Inspired Operations
2833            PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
2834            PipeOp::Compose(f) => {
2835                let _ = self.infer_expr(f);
2836                self.fresh_var()
2837            }
2838            PipeOp::Zip(other) => {
2839                let _ = self.infer_expr(other);
2840                self.fresh_var() // Array of tuples
2841            }
2842            PipeOp::Scan(f) => {
2843                let _ = self.infer_expr(f);
2844                self.fresh_var() // Array of accumulated values
2845            }
2846            PipeOp::Diff => self.fresh_var(), // Array of differences
2847            PipeOp::Gradient(var) => {
2848                let _ = self.infer_expr(var);
2849                self.fresh_var() // Gradient value
2850            }
2851            PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
2852                inner.clone() // Same type, reordered
2853            }
2854            PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
2855                let _ = self.infer_expr(n);
2856                self.fresh_var() // Array type
2857            }
2858            PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
2859            PipeOp::Enumerate => self.fresh_var(), // Array of (index, value) tuples
2860        };
2861
2862        // Preserve evidence through pipe
2863        if evidence > EvidenceLevel::Known {
2864            Type::Evidential {
2865                inner: Box::new(result),
2866                evidence,
2867            }
2868        } else {
2869            result
2870        }
2871    }
2872
2873    /// Strip evidence wrapper, returning (inner_type, evidence_level)
2874    fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
2875        match ty {
2876            Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
2877            _ => (ty.clone(), EvidenceLevel::Known),
2878        }
2879    }
2880
2881    /// Bind pattern variables with the given type and evidence level.
2882    /// This propagates evidence through pattern matching.
2883    fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
2884        let (inner_ty, ty_ev) = self.strip_evidence(ty);
2885        // Use the more restrictive evidence level
2886        let final_ev = evidence.join(ty_ev);
2887
2888        match pattern {
2889            Pattern::Ident {
2890                name,
2891                evidentiality,
2892                ..
2893            } => {
2894                // Explicit evidence annotation overrides inference
2895                let ev = evidentiality
2896                    .map(EvidenceLevel::from_ast)
2897                    .unwrap_or(final_ev);
2898                self.env
2899                    .borrow_mut()
2900                    .define(name.name.clone(), inner_ty, ev);
2901            }
2902            Pattern::Tuple(patterns) => {
2903                if let Type::Tuple(types) = &inner_ty {
2904                    for (pat, ty) in patterns.iter().zip(types.iter()) {
2905                        self.bind_pattern(pat, ty, final_ev);
2906                    }
2907                }
2908            }
2909            Pattern::Struct { fields, .. } => {
2910                // For struct patterns, we'd need field type info
2911                // For now, bind with fresh vars
2912                for field in fields {
2913                    let fresh = self.fresh_var();
2914                    if let Some(ref pat) = field.pattern {
2915                        self.bind_pattern(pat, &fresh, final_ev);
2916                    } else {
2917                        self.env
2918                            .borrow_mut()
2919                            .define(field.name.name.clone(), fresh, final_ev);
2920                    }
2921                }
2922            }
2923            Pattern::TupleStruct { fields, .. } => {
2924                for pat in fields {
2925                    let fresh = self.fresh_var();
2926                    self.bind_pattern(pat, &fresh, final_ev);
2927                }
2928            }
2929            Pattern::Slice(patterns) => {
2930                let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
2931                {
2932                    *element.clone()
2933                } else {
2934                    self.fresh_var()
2935                };
2936                for pat in patterns {
2937                    self.bind_pattern(pat, &elem_ty, final_ev);
2938                }
2939            }
2940            Pattern::Or(patterns) => {
2941                // For or-patterns, bind the same variables from any branch
2942                // (they should all have the same bindings)
2943                if let Some(first) = patterns.first() {
2944                    self.bind_pattern(first, ty, evidence);
2945                }
2946            }
2947            Pattern::Wildcard | Pattern::Rest | Pattern::Literal(_) | Pattern::Range { .. } | Pattern::Path(_) => {
2948                // These don't introduce bindings
2949            }
2950            Pattern::Ref { pattern, .. } => {
2951                // For reference patterns, bind the inner pattern
2952                // The inner type would be the deref'd type, but for now use a fresh var
2953                let inner_ty = self.fresh_var();
2954                self.bind_pattern(pattern, &inner_ty, final_ev);
2955            }
2956            Pattern::RefBinding {
2957                name,
2958                evidentiality,
2959                ..
2960            } => {
2961                // Ref binding - similar to Ident but binds by reference
2962                let ev = evidentiality
2963                    .map(EvidenceLevel::from_ast)
2964                    .unwrap_or(final_ev);
2965                self.env
2966                    .borrow_mut()
2967                    .define(name.name.clone(), inner_ty, ev);
2968            }
2969        }
2970    }
2971
2972    /// Resolve type aliases to their underlying types
2973    fn resolve_alias(&self, ty: &Type) -> Type {
2974        if let Type::Named { name, generics } = ty {
2975            if generics.is_empty() {
2976                if let Some(TypeDef::Alias { target, .. }) = self.types.get(name) {
2977                    return target.clone();
2978                }
2979            }
2980        }
2981        ty.clone()
2982    }
2983
2984    /// Attempt to unify two types
2985    fn unify(&mut self, a: &Type, b: &Type) -> bool {
2986        // Resolve type aliases first
2987        let a = self.resolve_alias(a);
2988        let b = self.resolve_alias(b);
2989
2990        match (&a, &b) {
2991            // Type variables - check these FIRST before other patterns
2992            (Type::Var(v), t) => {
2993                if let Some(resolved) = self.substitutions.get(v) {
2994                    let resolved = resolved.clone();
2995                    self.unify(&resolved, t)
2996                } else if !self.occurs_in(v, t) {
2997                    self.substitutions.insert(*v, t.clone());
2998                    true
2999                } else {
3000                    // Occurs check failed - cyclic type, just return true for bootstrapping
3001                    true
3002                }
3003            }
3004            (t, Type::Var(v)) => {
3005                if let Some(resolved) = self.substitutions.get(v) {
3006                    let resolved = resolved.clone();
3007                    self.unify(t, &resolved)
3008                } else if !self.occurs_in(v, t) {
3009                    self.substitutions.insert(*v, t.clone());
3010                    true
3011                } else {
3012                    // Occurs check failed - cyclic type, just return true for bootstrapping
3013                    true
3014                }
3015            }
3016
3017            // Same types
3018            (Type::Unit, Type::Unit) |
3019            (Type::Bool, Type::Bool) |
3020            (Type::Char, Type::Char) |
3021            (Type::Str, Type::Str) |
3022            (Type::Never, Type::Never) |
3023            (Type::Error, _) |
3024            (_, Type::Error) |
3025            // Never (bottom type) unifies with anything
3026            (Type::Never, _) |
3027            (_, Type::Never) => true,
3028
3029            // For bootstrapping: allow integer literals to coerce to any integer type
3030            // This is lenient - a proper type system would have more precise rules
3031            (Type::Int(_), Type::Int(_)) => true,
3032            // For bootstrapping: allow float literals to coerce to any float type
3033            // This handles cases like `const X: f32 = 0.3;` where 0.3 infers as f64
3034            (Type::Float(_), Type::Float(_)) => true,
3035
3036            // For bootstrapping: allow &str to coerce to Str and vice versa
3037            (Type::Ref { mutable: false, inner: a, .. }, Type::Str) if matches!(a.as_ref(), Type::Str) => true,
3038            (Type::Str, Type::Ref { mutable: false, inner: b, .. }) if matches!(b.as_ref(), Type::Str) => true,
3039
3040            // Arrays
3041            (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
3042                (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
3043            }
3044
3045            // Slices
3046            (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
3047
3048            // Tuples
3049            (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
3050                a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
3051            }
3052
3053            // References
3054            (Type::Ref { mutable: ma, inner: a, .. }, Type::Ref { mutable: mb, inner: b, .. }) => {
3055                // Allow &[T; N] to coerce to &[T] (array to slice)
3056                match (a.as_ref(), b.as_ref()) {
3057                    (Type::Array { element: ea, .. }, Type::Slice(es)) => {
3058                        ma == mb && self.unify(ea, es)
3059                    }
3060                    (Type::Slice(es), Type::Array { element: ea, .. }) => {
3061                        ma == mb && self.unify(es, ea)
3062                    }
3063                    _ => ma == mb && self.unify(a, b)
3064                }
3065            }
3066
3067            // Functions
3068            (Type::Function { params: pa, return_type: ra, is_async: aa },
3069             Type::Function { params: pb, return_type: rb, is_async: ab }) => {
3070                aa == ab && pa.len() == pb.len() &&
3071                pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
3072                self.unify(ra, rb)
3073            }
3074
3075            // Named types
3076            (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
3077                na == nb && ga.len() == gb.len() &&
3078                ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y))
3079            }
3080
3081            // Evidential types: inner must unify, evidence can differ
3082            (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
3083                self.unify(a, b)
3084            }
3085            (Type::Evidential { inner: a, .. }, b) => {
3086                self.unify(a, b)
3087            }
3088            (a, Type::Evidential { inner: b, .. }) => {
3089                self.unify(a, b)
3090            }
3091
3092            // Cycles
3093            (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
3094
3095            // For bootstrapping: treat type parameters (single uppercase letter names like T, U, E)
3096            // as compatible with any type. This allows generic functions to type check without
3097            // full generic instantiation support.
3098            (Type::Named { name, generics }, _) | (_, Type::Named { name, generics })
3099                if generics.is_empty() && Self::is_type_parameter(name) => {
3100                true
3101            }
3102
3103            _ => false,
3104        }
3105    }
3106
3107    /// Check if a name looks like a type parameter (single uppercase letter or common generic names)
3108    fn is_type_parameter(name: &str) -> bool {
3109        // Single uppercase letter (T, U, E, K, V, etc.)
3110        if name.len() == 1 && name.chars().next().map(|c| c.is_ascii_uppercase()).unwrap_or(false) {
3111            return true;
3112        }
3113        // Common generic parameter names
3114        matches!(name, "Item" | "Output" | "Error" | "Key" | "Value" | "Idx" | "Self")
3115    }
3116
3117    /// Check if this is an allowed implicit numeric coercion (int → float)
3118    fn is_numeric_coercion(expected: &Type, actual: &Type) -> bool {
3119        // Allow integers to coerce to floats
3120        match (expected, actual) {
3121            (Type::Float(_), Type::Int(_)) => true,
3122            // Also allow through evidential wrappers
3123            (Type::Evidential { inner: exp, .. }, Type::Int(_)) => {
3124                matches!(exp.as_ref(), Type::Float(_))
3125            }
3126            (Type::Float(_), Type::Evidential { inner: act, .. }) => {
3127                matches!(act.as_ref(), Type::Int(_))
3128            }
3129            _ => false,
3130        }
3131    }
3132
3133    /// Convert AST type to internal type
3134    fn convert_type(&self, ty: &TypeExpr) -> Type {
3135        match ty {
3136            TypeExpr::Path(path) => {
3137                if path.segments.len() == 1 {
3138                    let name = &path.segments[0].ident.name;
3139                    match name.as_str() {
3140                        "bool" => return Type::Bool,
3141                        "char" => return Type::Char,
3142                        "str" | "String" => return Type::Str,
3143                        "i8" => return Type::Int(IntSize::I8),
3144                        "i16" => return Type::Int(IntSize::I16),
3145                        "i32" => return Type::Int(IntSize::I32),
3146                        "i64" => return Type::Int(IntSize::I64),
3147                        "i128" => return Type::Int(IntSize::I128),
3148                        "isize" => return Type::Int(IntSize::ISize),
3149                        "u8" => return Type::Int(IntSize::U8),
3150                        "u16" => return Type::Int(IntSize::U16),
3151                        "u32" => return Type::Int(IntSize::U32),
3152                        "u64" => return Type::Int(IntSize::U64),
3153                        "u128" => return Type::Int(IntSize::U128),
3154                        "usize" => return Type::Int(IntSize::USize),
3155                        "f32" => return Type::Float(FloatSize::F32),
3156                        "f64" => return Type::Float(FloatSize::F64),
3157                        // Handle Self type - resolve to current impl type
3158                        "Self" => {
3159                            if let Some(ref self_ty) = self.current_self_type {
3160                                return Type::Named {
3161                                    name: self_ty.clone(),
3162                                    generics: vec![],
3163                                };
3164                            }
3165                        }
3166                        _ => {
3167                            // Check if this is a generic type parameter
3168                            if let Some(ty) = self.current_generics.get(name) {
3169                                return ty.clone();
3170                            }
3171                        }
3172                    }
3173                }
3174
3175                let name = path
3176                    .segments
3177                    .iter()
3178                    .map(|s| s.ident.name.clone())
3179                    .collect::<Vec<_>>()
3180                    .join("::");
3181
3182                let generics = path
3183                    .segments
3184                    .last()
3185                    .and_then(|s| s.generics.as_ref())
3186                    .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
3187                    .unwrap_or_default();
3188
3189                Type::Named { name, generics }
3190            }
3191
3192            TypeExpr::Reference { lifetime, mutable, inner } => Type::Ref {
3193                lifetime: lifetime.clone(),
3194                mutable: *mutable,
3195                inner: Box::new(self.convert_type(inner)),
3196            },
3197
3198            TypeExpr::Pointer { mutable, inner } => Type::Ptr {
3199                mutable: *mutable,
3200                inner: Box::new(self.convert_type(inner)),
3201            },
3202
3203            TypeExpr::Array { element, size: _ } => {
3204                Type::Array {
3205                    element: Box::new(self.convert_type(element)),
3206                    size: None, // Could evaluate const expr
3207                }
3208            }
3209
3210            TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
3211
3212            TypeExpr::Tuple(elements) => {
3213                Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
3214            }
3215
3216            TypeExpr::Function {
3217                params,
3218                return_type,
3219            } => Type::Function {
3220                params: params.iter().map(|t| self.convert_type(t)).collect(),
3221                return_type: Box::new(
3222                    return_type
3223                        .as_ref()
3224                        .map(|t| self.convert_type(t))
3225                        .unwrap_or(Type::Unit),
3226                ),
3227                is_async: false,
3228            },
3229
3230            TypeExpr::Evidential {
3231                inner,
3232                evidentiality,
3233                error_type,
3234            } => {
3235                // If error_type is specified, this is sugar for Result<T, E>
3236                // For now, lower as evidential type; full expansion to Result comes later
3237                let _ = error_type; // TODO: expand T?[E] to Result<T, E> with evidence
3238                Type::Evidential {
3239                    inner: Box::new(self.convert_type(inner)),
3240                    evidence: EvidenceLevel::from_ast(*evidentiality),
3241                }
3242            }
3243
3244            TypeExpr::Cycle { modulus: _ } => {
3245                Type::Cycle { modulus: 12 } // Default, should evaluate
3246            }
3247
3248            TypeExpr::Simd { element, lanes } => {
3249                let elem_ty = self.convert_type(element);
3250                Type::Simd {
3251                    element: Box::new(elem_ty),
3252                    lanes: *lanes,
3253                }
3254            }
3255
3256            TypeExpr::Atomic(inner) => {
3257                let inner_ty = self.convert_type(inner);
3258                Type::Atomic(Box::new(inner_ty))
3259            }
3260
3261            TypeExpr::Never => Type::Never,
3262            TypeExpr::Infer => Type::Var(TypeVar(0)), // Fresh var
3263            TypeExpr::Lifetime(name) => Type::Lifetime(name.clone()),
3264            TypeExpr::TraitObject(bounds) => {
3265                let converted: Vec<Type> = bounds.iter().map(|b| self.convert_type(b)).collect();
3266                Type::TraitObject(converted)
3267            }
3268            TypeExpr::Hrtb { lifetimes, bound } => Type::Hrtb {
3269                lifetimes: lifetimes.clone(),
3270                bound: Box::new(self.convert_type(bound)),
3271            },
3272            TypeExpr::InlineStruct { fields } => Type::InlineStruct {
3273                fields: fields
3274                    .iter()
3275                    .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
3276                    .collect(),
3277            },
3278            TypeExpr::ImplTrait(bounds) => {
3279                Type::ImplTrait(bounds.iter().map(|b| self.convert_type(b)).collect())
3280            }
3281            TypeExpr::InlineEnum { variants } => {
3282                Type::InlineEnum(variants.iter().map(|v| v.name.name.clone()).collect())
3283            }
3284            TypeExpr::AssocTypeBinding { name, ty } => Type::AssocTypeBinding {
3285                name: name.name.clone(),
3286                ty: Box::new(self.convert_type(ty)),
3287            },
3288            TypeExpr::ConstExpr(_) => {
3289                // Const expressions in type position (const generics)
3290                // For now, treat as an inferred/opaque type
3291                Type::Var(TypeVar(0))
3292            }
3293            TypeExpr::QualifiedPath { self_type, trait_path, item_path } => {
3294                // Qualified path: <Type as Trait>::AssociatedType
3295                // For now, represent as a named type with a synthesized name
3296                let trait_part = trait_path.as_ref()
3297                    .map(|tp| tp.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::"))
3298                    .unwrap_or_default();
3299                let item_part = item_path.segments.iter().map(|s| s.ident.name.clone()).collect::<Vec<_>>().join("::");
3300                let name = if trait_part.is_empty() {
3301                    format!("<_>::{}", item_part)
3302                } else {
3303                    format!("<_ as {}>::{}", trait_part, item_part)
3304                };
3305                Type::Named {
3306                    name,
3307                    generics: vec![self.convert_type(self_type)],
3308                }
3309            }
3310        }
3311    }
3312
3313    /// Get errors
3314    pub fn errors(&self) -> &[TypeError] {
3315        &self.errors
3316    }
3317}
3318
3319impl Default for TypeChecker {
3320    fn default() -> Self {
3321        Self::new()
3322    }
3323}
3324
3325// Helper trait for Pattern
3326trait PatternExt {
3327    fn evidentiality(&self) -> Option<Evidentiality>;
3328    fn binding_name(&self) -> Option<String>;
3329    fn binding_span(&self) -> Option<Span>;
3330    fn is_mutable(&self) -> bool;
3331}
3332
3333impl PatternExt for Pattern {
3334    fn evidentiality(&self) -> Option<Evidentiality> {
3335        match self {
3336            Pattern::Ident { evidentiality, .. } => *evidentiality,
3337            _ => None,
3338        }
3339    }
3340
3341    fn binding_name(&self) -> Option<String> {
3342        match self {
3343            Pattern::Ident { name, .. } => Some(name.name.clone()),
3344            _ => None,
3345        }
3346    }
3347
3348    fn binding_span(&self) -> Option<Span> {
3349        match self {
3350            Pattern::Ident { name, .. } => Some(name.span),
3351            _ => None,
3352        }
3353    }
3354
3355    fn is_mutable(&self) -> bool {
3356        match self {
3357            Pattern::Ident { mutable, .. } => *mutable,
3358            _ => false,
3359        }
3360    }
3361}
3362
3363impl fmt::Display for Type {
3364    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3365        match self {
3366            Type::Unit => write!(f, "()"),
3367            Type::Bool => write!(f, "bool"),
3368            Type::Int(size) => write!(f, "{:?}", size),
3369            Type::Float(size) => write!(f, "{:?}", size),
3370            Type::Char => write!(f, "char"),
3371            Type::Str => write!(f, "str"),
3372            Type::Array { element, size } => {
3373                if let Some(n) = size {
3374                    write!(f, "[{}; {}]", element, n)
3375                } else {
3376                    write!(f, "[{}]", element)
3377                }
3378            }
3379            Type::Slice(inner) => write!(f, "[{}]", inner),
3380            Type::Tuple(elems) => {
3381                write!(f, "(")?;
3382                for (i, e) in elems.iter().enumerate() {
3383                    if i > 0 {
3384                        write!(f, ", ")?;
3385                    }
3386                    write!(f, "{}", e)?;
3387                }
3388                write!(f, ")")
3389            }
3390            Type::Named { name, generics } => {
3391                write!(f, "{}", name)?;
3392                if !generics.is_empty() {
3393                    write!(f, "<")?;
3394                    for (i, g) in generics.iter().enumerate() {
3395                        if i > 0 {
3396                            write!(f, ", ")?;
3397                        }
3398                        write!(f, "{}", g)?;
3399                    }
3400                    write!(f, ">")?;
3401                }
3402                Ok(())
3403            }
3404            Type::Function {
3405                params,
3406                return_type,
3407                is_async,
3408            } => {
3409                if *is_async {
3410                    write!(f, "async ")?;
3411                }
3412                write!(f, "fn(")?;
3413                for (i, p) in params.iter().enumerate() {
3414                    if i > 0 {
3415                        write!(f, ", ")?;
3416                    }
3417                    write!(f, "{}", p)?;
3418                }
3419                write!(f, ") -> {}", return_type)
3420            }
3421            Type::Ref { lifetime, mutable, inner } => {
3422                let lt = lifetime.as_ref().map(|l| format!("'{} ", l)).unwrap_or_default();
3423                write!(f, "&{}{}{}", lt, if *mutable { "mut " } else { "" }, inner)
3424            }
3425            Type::Ptr { mutable, inner } => {
3426                write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
3427            }
3428            Type::Evidential { inner, evidence } => {
3429                write!(f, "{}{}", inner, evidence.symbol())
3430            }
3431            Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
3432            Type::Var(v) => write!(f, "?{}", v.0),
3433            Type::Error => write!(f, "<error>"),
3434            Type::Never => write!(f, "!"),
3435            Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
3436            Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
3437            Type::Lifetime(name) => write!(f, "'{}", name),
3438            Type::TraitObject(bounds) => {
3439                write!(f, "dyn ")?;
3440                for (i, bound) in bounds.iter().enumerate() {
3441                    if i > 0 {
3442                        write!(f, " + ")?;
3443                    }
3444                    write!(f, "{}", bound)?;
3445                }
3446                Ok(())
3447            }
3448            Type::Hrtb { lifetimes, bound } => {
3449                write!(f, "for<")?;
3450                for (i, lt) in lifetimes.iter().enumerate() {
3451                    if i > 0 {
3452                        write!(f, ", ")?;
3453                    }
3454                    write!(f, "'{}", lt)?;
3455                }
3456                write!(f, "> {}", bound)
3457            }
3458            Type::InlineStruct { fields } => {
3459                write!(f, "struct {{ ")?;
3460                for (i, (name, ty)) in fields.iter().enumerate() {
3461                    if i > 0 {
3462                        write!(f, ", ")?;
3463                    }
3464                    write!(f, "{}: {}", name, ty)?;
3465                }
3466                write!(f, " }}")
3467            }
3468            Type::ImplTrait(bounds) => {
3469                write!(f, "impl ")?;
3470                for (i, bound) in bounds.iter().enumerate() {
3471                    if i > 0 {
3472                        write!(f, " + ")?;
3473                    }
3474                    write!(f, "{}", bound)?;
3475                }
3476                Ok(())
3477            }
3478            Type::InlineEnum(variants) => {
3479                write!(f, "enum {{ ")?;
3480                for (i, name) in variants.iter().enumerate() {
3481                    if i > 0 {
3482                        write!(f, ", ")?;
3483                    }
3484                    write!(f, "{}", name)?;
3485                }
3486                write!(f, " }}")
3487            }
3488            Type::AssocTypeBinding { name, ty } => {
3489                write!(f, "{} = {}", name, ty)
3490            }
3491        }
3492    }
3493}
3494
3495#[cfg(test)]
3496mod tests {
3497    use super::*;
3498    use crate::Parser;
3499
3500    fn check(source: &str) -> Result<(), Vec<TypeError>> {
3501        let mut parser = Parser::new(source);
3502        let file = parser.parse_file().expect("parse failed");
3503        let mut checker = TypeChecker::new();
3504        checker.check_file(&file)
3505    }
3506
3507    #[test]
3508    fn test_basic_types() {
3509        assert!(check("fn main() { let x: i64 = 42; }").is_ok());
3510        assert!(check("fn main() { let x: bool = true; }").is_ok());
3511        assert!(check("fn main() { let x: f64 = 3.14; }").is_ok());
3512    }
3513
3514    #[test]
3515    fn test_type_mismatch() {
3516        assert!(check("fn main() { let x: bool = 42; }").is_err());
3517    }
3518
3519    #[test]
3520    fn test_evidence_propagation() {
3521        // Evidence should propagate through operations
3522        assert!(check(
3523            r#"
3524            fn main() {
3525                let known: i64! = 42;
3526                let uncertain: i64? = 10;
3527                let result = known + uncertain;
3528            }
3529        "#
3530        )
3531        .is_ok());
3532    }
3533
3534    #[test]
3535    fn test_function_return() {
3536        let result = check(
3537            r#"
3538            fn add(a: i64, b: i64) -> i64 {
3539                return a + b;
3540            }
3541            fn main() {
3542                let x = add(1, 2);
3543            }
3544        "#,
3545        );
3546        if let Err(errors) = &result {
3547            for e in errors {
3548                eprintln!("Error: {}", e);
3549            }
3550        }
3551        assert!(result.is_ok());
3552    }
3553
3554    #[test]
3555    fn test_array_types() {
3556        assert!(check(
3557            r#"
3558            fn main() {
3559                let arr = [1, 2, 3];
3560                let x = arr[0];
3561            }
3562        "#
3563        )
3564        .is_ok());
3565    }
3566
3567    // ==========================================
3568    // Evidence Inference Tests
3569    // ==========================================
3570
3571    #[test]
3572    fn test_evidence_inference_from_initializer() {
3573        // Evidence should be inferred from initializer when not explicitly annotated
3574        assert!(check(
3575            r#"
3576            fn main() {
3577                let reported_val: i64~ = 42;
3578                // x should inherit ~ evidence from reported_val
3579                let x = reported_val + 1;
3580            }
3581        "#
3582        )
3583        .is_ok());
3584    }
3585
3586    #[test]
3587    fn test_evidence_inference_explicit_override() {
3588        // Explicit annotation should override inference
3589        assert!(check(
3590            r#"
3591            fn main() {
3592                let reported_val: i64~ = 42;
3593                // Explicit ! annotation - this would fail if we checked evidence properly
3594                // but the type system allows it as an override
3595                let x! = 42;
3596            }
3597        "#
3598        )
3599        .is_ok());
3600    }
3601
3602    #[test]
3603    fn test_if_else_evidence_join() {
3604        // Evidence from both branches should be joined
3605        assert!(check(
3606            r#"
3607            fn main() {
3608                let known_val: i64! = 1;
3609                let reported_val: i64~ = 2;
3610                let cond: bool = true;
3611                // Result should have ~ evidence (join of ! and ~)
3612                let result = if cond { known_val } else { reported_val };
3613            }
3614        "#
3615        )
3616        .is_ok());
3617    }
3618
3619    #[test]
3620    fn test_binary_op_evidence_propagation() {
3621        // Binary operations should join evidence levels
3622        assert!(check(
3623            r#"
3624            fn main() {
3625                let known: i64! = 1;
3626                let reported: i64~ = 2;
3627                // Result should have ~ evidence (max of ! and ~)
3628                let result = known + reported;
3629            }
3630        "#
3631        )
3632        .is_ok());
3633    }
3634
3635    #[test]
3636    fn test_match_evidence_join() {
3637        // Match arms should join evidence from all branches
3638        // Note: This test is structural - the type checker should handle it
3639        assert!(check(
3640            r#"
3641            fn main() {
3642                let x: i64 = 1;
3643            }
3644        "#
3645        )
3646        .is_ok());
3647    }
3648}