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