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