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