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        mutable: bool,
49        inner: Box<Type>,
50    },
51    Ptr {
52        mutable: bool,
53        inner: Box<Type>,
54    },
55
56    /// Evidential wrapper - the core of Sigil's type system
57    Evidential {
58        inner: Box<Type>,
59        evidence: EvidenceLevel,
60    },
61
62    /// Cyclic type (modular arithmetic)
63    Cycle {
64        modulus: usize,
65    },
66
67    /// SIMD vector type
68    Simd {
69        element: Box<Type>,
70        lanes: u8,
71    },
72
73    /// Atomic type
74    Atomic(Box<Type>),
75
76    /// Type variable for inference
77    Var(TypeVar),
78
79    /// Error type (for error recovery)
80    Error,
81
82    /// Never type (diverging)
83    Never,
84}
85
86/// Integer sizes
87#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum IntSize {
89    I8,
90    I16,
91    I32,
92    I64,
93    I128,
94    U8,
95    U16,
96    U32,
97    U64,
98    U128,
99    ISize,
100    USize,
101}
102
103/// Float sizes
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum FloatSize {
106    F32,
107    F64,
108}
109
110/// Evidence levels in the type system.
111///
112/// Evidence forms a lattice:
113///   Known (!) < Uncertain (?) < Reported (~) < Paradox (‽)
114///
115/// Operations combine evidence levels using join (⊔):
116///   a + b : join(evidence(a), evidence(b))
117#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
118pub enum EvidenceLevel {
119    /// Direct knowledge - computed locally, verified
120    Known, // !
121    /// Uncertain - inferred, possible, not verified
122    Uncertain, // ?
123    /// Reported - from external source, hearsay
124    Reported, // ~
125    /// Paradox - contradictory information
126    Paradox, // ‽
127}
128
129impl EvidenceLevel {
130    /// Join two evidence levels (least upper bound in lattice)
131    pub fn join(self, other: Self) -> Self {
132        std::cmp::max(self, other)
133    }
134
135    /// Meet two evidence levels (greatest lower bound)
136    pub fn meet(self, other: Self) -> Self {
137        std::cmp::min(self, other)
138    }
139
140    /// Convert from AST representation
141    pub fn from_ast(e: Evidentiality) -> Self {
142        match e {
143            Evidentiality::Known => EvidenceLevel::Known,
144            Evidentiality::Uncertain => EvidenceLevel::Uncertain,
145            Evidentiality::Reported => EvidenceLevel::Reported,
146            Evidentiality::Paradox => EvidenceLevel::Paradox,
147        }
148    }
149
150    /// Symbol representation
151    pub fn symbol(&self) -> &'static str {
152        match self {
153            EvidenceLevel::Known => "!",
154            EvidenceLevel::Uncertain => "?",
155            EvidenceLevel::Reported => "~",
156            EvidenceLevel::Paradox => "‽",
157        }
158    }
159
160    /// Human-readable name
161    pub fn name(&self) -> &'static str {
162        match self {
163            EvidenceLevel::Known => "known",
164            EvidenceLevel::Uncertain => "uncertain",
165            EvidenceLevel::Reported => "reported",
166            EvidenceLevel::Paradox => "paradox",
167        }
168    }
169
170    /// Check if this evidence level can satisfy a required level.
171    ///
172    /// Evidence is covariant: you can pass more certain data where less certain is expected.
173    /// Known (!) can satisfy any requirement.
174    /// Reported (~) can only satisfy Reported or Paradox requirements.
175    ///
176    /// Returns true if `self` (actual) can be used where `required` is expected.
177    pub fn satisfies(self, required: Self) -> bool {
178        // More certain evidence (lower in lattice) can satisfy less certain requirements
179        // Known <= Uncertain <= Reported <= Paradox
180        self <= required
181    }
182}
183
184/// Type variable for inference
185#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
186pub struct TypeVar(pub u32);
187
188/// Type error
189#[derive(Debug, Clone)]
190pub struct TypeError {
191    pub message: String,
192    pub span: Option<Span>,
193    pub notes: Vec<String>,
194}
195
196impl TypeError {
197    pub fn new(message: impl Into<String>) -> Self {
198        Self {
199            message: message.into(),
200            span: None,
201            notes: Vec::new(),
202        }
203    }
204
205    pub fn with_span(mut self, span: Span) -> Self {
206        self.span = Some(span);
207        self
208    }
209
210    pub fn with_note(mut self, note: impl Into<String>) -> Self {
211        self.notes.push(note.into());
212        self
213    }
214}
215
216impl fmt::Display for TypeError {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        write!(f, "{}", self.message)?;
219        if let Some(span) = self.span {
220            write!(f, " at {}", span)?;
221        }
222        for note in &self.notes {
223            write!(f, "\n  note: {}", note)?;
224        }
225        Ok(())
226    }
227}
228
229/// Type environment for scoped lookups
230#[derive(Debug, Clone)]
231pub struct TypeEnv {
232    /// Variable bindings: name -> (type, evidence)
233    bindings: HashMap<String, (Type, EvidenceLevel)>,
234    /// Parent scope
235    parent: Option<Rc<RefCell<TypeEnv>>>,
236}
237
238impl TypeEnv {
239    pub fn new() -> Self {
240        Self {
241            bindings: HashMap::new(),
242            parent: None,
243        }
244    }
245
246    pub fn with_parent(parent: Rc<RefCell<TypeEnv>>) -> Self {
247        Self {
248            bindings: HashMap::new(),
249            parent: Some(parent),
250        }
251    }
252
253    /// Define a new binding
254    pub fn define(&mut self, name: String, ty: Type, evidence: EvidenceLevel) {
255        self.bindings.insert(name, (ty, evidence));
256    }
257
258    /// Look up a binding
259    pub fn lookup(&self, name: &str) -> Option<(Type, EvidenceLevel)> {
260        if let Some(binding) = self.bindings.get(name) {
261            Some(binding.clone())
262        } else if let Some(ref parent) = self.parent {
263            parent.borrow().lookup(name)
264        } else {
265            None
266        }
267    }
268}
269
270impl Default for TypeEnv {
271    fn default() -> Self {
272        Self::new()
273    }
274}
275
276/// Type definitions (structs, enums, type aliases)
277#[derive(Debug, Clone)]
278pub enum TypeDef {
279    Struct {
280        generics: Vec<String>,
281        fields: Vec<(String, Type)>,
282    },
283    Enum {
284        generics: Vec<String>,
285        variants: Vec<(String, Option<Vec<Type>>)>,
286    },
287    Alias {
288        generics: Vec<String>,
289        target: Type,
290    },
291}
292
293/// The type checker
294pub struct TypeChecker {
295    /// Type environment stack
296    env: Rc<RefCell<TypeEnv>>,
297    /// Type definitions
298    types: HashMap<String, TypeDef>,
299    /// Function signatures
300    functions: HashMap<String, Type>,
301    /// Type variable counter
302    next_var: u32,
303    /// Inferred type variable substitutions
304    substitutions: HashMap<TypeVar, Type>,
305    /// Collected errors
306    errors: Vec<TypeError>,
307}
308
309impl TypeChecker {
310    pub fn new() -> Self {
311        let mut checker = Self {
312            env: Rc::new(RefCell::new(TypeEnv::new())),
313            types: HashMap::new(),
314            functions: HashMap::new(),
315            next_var: 0,
316            substitutions: HashMap::new(),
317            errors: Vec::new(),
318        };
319
320        // Register built-in types and functions
321        checker.register_builtins();
322        checker
323    }
324
325    fn register_builtins(&mut self) {
326        // Helper to create a function type
327        let func = |params: Vec<Type>, ret: Type| Type::Function {
328            params,
329            return_type: Box::new(ret),
330            is_async: false,
331        };
332
333        // Type variable for generic functions
334        let any = Type::Var(TypeVar(9999)); // Use high number to avoid conflicts
335
336        // ===================
337        // Core I/O
338        // ===================
339        // print accepts any type (polymorphic)
340        self.functions
341            .insert("print".to_string(), func(vec![any.clone()], Type::Unit));
342        self.functions
343            .insert("println".to_string(), func(vec![any.clone()], Type::Unit));
344        self.functions
345            .insert("input".to_string(), func(vec![], Type::Str));
346        self.functions
347            .insert("input_line".to_string(), func(vec![], Type::Str));
348
349        // ===================
350        // Type inspection
351        // ===================
352        self.functions
353            .insert("type_of".to_string(), func(vec![any.clone()], Type::Str));
354        self.functions.insert(
355            "len".to_string(),
356            func(vec![any.clone()], Type::Int(IntSize::USize)),
357        );
358
359        // ===================
360        // String functions
361        // ===================
362        self.functions
363            .insert("str".to_string(), func(vec![any.clone()], Type::Str));
364        self.functions
365            .insert("upper".to_string(), func(vec![Type::Str], Type::Str));
366        self.functions
367            .insert("lower".to_string(), func(vec![Type::Str], Type::Str));
368        self.functions
369            .insert("trim".to_string(), func(vec![Type::Str], Type::Str));
370        self.functions.insert(
371            "split".to_string(),
372            func(
373                vec![Type::Str, Type::Str],
374                Type::Array {
375                    element: Box::new(Type::Str),
376                    size: None,
377                },
378            ),
379        );
380        self.functions.insert(
381            "join".to_string(),
382            func(
383                vec![
384                    Type::Array {
385                        element: Box::new(Type::Str),
386                        size: None,
387                    },
388                    Type::Str,
389                ],
390                Type::Str,
391            ),
392        );
393        self.functions.insert(
394            "contains".to_string(),
395            func(vec![Type::Str, Type::Str], Type::Bool),
396        );
397        self.functions.insert(
398            "starts_with".to_string(),
399            func(vec![Type::Str, Type::Str], Type::Bool),
400        );
401        self.functions.insert(
402            "ends_with".to_string(),
403            func(vec![Type::Str, Type::Str], Type::Bool),
404        );
405        self.functions.insert(
406            "replace".to_string(),
407            func(vec![Type::Str, Type::Str, Type::Str], Type::Str),
408        );
409        self.functions.insert(
410            "char_at".to_string(),
411            func(vec![Type::Str, Type::Int(IntSize::I64)], Type::Str),
412        );
413        self.functions.insert(
414            "substring".to_string(),
415            func(
416                vec![Type::Str, Type::Int(IntSize::I64), Type::Int(IntSize::I64)],
417                Type::Str,
418            ),
419        );
420
421        // ===================
422        // Math functions
423        // ===================
424        let f64_ty = Type::Float(FloatSize::F64);
425        let i64_ty = Type::Int(IntSize::I64);
426
427        self.functions.insert(
428            "abs".to_string(),
429            func(vec![f64_ty.clone()], f64_ty.clone()),
430        );
431        self.functions.insert(
432            "sqrt".to_string(),
433            func(vec![f64_ty.clone()], f64_ty.clone()),
434        );
435        self.functions.insert(
436            "sin".to_string(),
437            func(vec![f64_ty.clone()], f64_ty.clone()),
438        );
439        self.functions.insert(
440            "cos".to_string(),
441            func(vec![f64_ty.clone()], f64_ty.clone()),
442        );
443        self.functions.insert(
444            "tan".to_string(),
445            func(vec![f64_ty.clone()], f64_ty.clone()),
446        );
447        self.functions.insert(
448            "floor".to_string(),
449            func(vec![f64_ty.clone()], f64_ty.clone()),
450        );
451        self.functions.insert(
452            "ceil".to_string(),
453            func(vec![f64_ty.clone()], f64_ty.clone()),
454        );
455        self.functions.insert(
456            "round".to_string(),
457            func(vec![f64_ty.clone()], f64_ty.clone()),
458        );
459        self.functions.insert(
460            "pow".to_string(),
461            func(vec![f64_ty.clone(), f64_ty.clone()], f64_ty.clone()),
462        );
463        self.functions.insert(
464            "log".to_string(),
465            func(vec![f64_ty.clone()], f64_ty.clone()),
466        );
467        self.functions.insert(
468            "exp".to_string(),
469            func(vec![f64_ty.clone()], f64_ty.clone()),
470        );
471        self.functions.insert(
472            "min".to_string(),
473            func(vec![any.clone(), any.clone()], any.clone()),
474        );
475        self.functions.insert(
476            "max".to_string(),
477            func(vec![any.clone(), any.clone()], any.clone()),
478        );
479
480        // ===================
481        // Array/Collection functions
482        // ===================
483        self.functions
484            .insert("sum".to_string(), func(vec![any.clone()], f64_ty.clone()));
485        self.functions
486            .insert("avg".to_string(), func(vec![any.clone()], f64_ty.clone()));
487        self.functions.insert(
488            "push".to_string(),
489            func(vec![any.clone(), any.clone()], Type::Unit),
490        );
491        self.functions
492            .insert("pop".to_string(), func(vec![any.clone()], any.clone()));
493        self.functions
494            .insert("first".to_string(), func(vec![any.clone()], any.clone()));
495        self.functions
496            .insert("last".to_string(), func(vec![any.clone()], any.clone()));
497        self.functions
498            .insert("reverse".to_string(), func(vec![any.clone()], any.clone()));
499        self.functions
500            .insert("sort".to_string(), func(vec![any.clone()], any.clone()));
501        self.functions.insert(
502            "range".to_string(),
503            func(
504                vec![i64_ty.clone(), i64_ty.clone()],
505                Type::Array {
506                    element: Box::new(i64_ty.clone()),
507                    size: None,
508                },
509            ),
510        );
511
512        // ===================
513        // Assertions (for testing)
514        // ===================
515        self.functions
516            .insert("assert".to_string(), func(vec![Type::Bool], Type::Unit));
517        self.functions.insert(
518            "assert_eq".to_string(),
519            func(vec![any.clone(), any.clone()], Type::Unit),
520        );
521        self.functions.insert(
522            "assert_ne".to_string(),
523            func(vec![any.clone(), any.clone()], Type::Unit),
524        );
525        self.functions.insert(
526            "assert_lt".to_string(),
527            func(vec![any.clone(), any.clone()], Type::Unit),
528        );
529        self.functions.insert(
530            "assert_le".to_string(),
531            func(vec![any.clone(), any.clone()], Type::Unit),
532        );
533        self.functions.insert(
534            "assert_gt".to_string(),
535            func(vec![any.clone(), any.clone()], Type::Unit),
536        );
537        self.functions.insert(
538            "assert_ge".to_string(),
539            func(vec![any.clone(), any.clone()], Type::Unit),
540        );
541        self.functions.insert(
542            "assert_true".to_string(),
543            func(vec![Type::Bool], Type::Unit),
544        );
545        self.functions.insert(
546            "assert_false".to_string(),
547            func(vec![Type::Bool], Type::Unit),
548        );
549        self.functions.insert(
550            "assert_null".to_string(),
551            func(vec![any.clone()], Type::Unit),
552        );
553        self.functions.insert(
554            "assert_not_null".to_string(),
555            func(vec![any.clone()], Type::Unit),
556        );
557        self.functions.insert(
558            "assert_contains".to_string(),
559            func(vec![any.clone(), any.clone()], Type::Unit),
560        );
561        self.functions.insert(
562            "assert_len".to_string(),
563            func(vec![any.clone(), i64_ty.clone()], Type::Unit),
564        );
565
566        // ===================
567        // Random
568        // ===================
569        self.functions
570            .insert("random".to_string(), func(vec![], f64_ty.clone()));
571        self.functions.insert(
572            "random_int".to_string(),
573            func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
574        );
575        self.functions
576            .insert("shuffle".to_string(), func(vec![any.clone()], any.clone()));
577
578        // ===================
579        // Time
580        // ===================
581        self.functions
582            .insert("now".to_string(), func(vec![], f64_ty.clone()));
583        self.functions
584            .insert("sleep".to_string(), func(vec![f64_ty.clone()], Type::Unit));
585
586        // ===================
587        // Conversion
588        // ===================
589        self.functions
590            .insert("int".to_string(), func(vec![any.clone()], i64_ty.clone()));
591        self.functions
592            .insert("float".to_string(), func(vec![any.clone()], f64_ty.clone()));
593        self.functions
594            .insert("bool".to_string(), func(vec![any.clone()], Type::Bool));
595
596        // ===================
597        // Error handling
598        // ===================
599        self.functions
600            .insert("panic".to_string(), func(vec![Type::Str], Type::Never));
601        self.functions
602            .insert("todo".to_string(), func(vec![], Type::Never));
603        self.functions
604            .insert("unreachable".to_string(), func(vec![], Type::Never));
605
606        // ===================
607        // Evidentiality functions
608        // ===================
609        // Create known evidence (!)
610        self.functions.insert(
611            "known".to_string(),
612            func(
613                vec![any.clone()],
614                Type::Evidential {
615                    inner: Box::new(any.clone()),
616                    evidence: EvidenceLevel::Known,
617                },
618            ),
619        );
620        // Create uncertain evidence (?)
621        self.functions.insert(
622            "uncertain".to_string(),
623            func(
624                vec![any.clone()],
625                Type::Evidential {
626                    inner: Box::new(any.clone()),
627                    evidence: EvidenceLevel::Uncertain,
628                },
629            ),
630        );
631        // Create reported evidence (~)
632        self.functions.insert(
633            "reported".to_string(),
634            func(
635                vec![any.clone()],
636                Type::Evidential {
637                    inner: Box::new(any.clone()),
638                    evidence: EvidenceLevel::Reported,
639                },
640            ),
641        );
642        // Get evidence level as string
643        self.functions.insert(
644            "evidence_of".to_string(),
645            func(vec![any.clone()], Type::Str),
646        );
647        // Validate reported -> uncertain
648        self.functions.insert(
649            "validate".to_string(),
650            func(
651                vec![any.clone()],
652                Type::Evidential {
653                    inner: Box::new(any.clone()),
654                    evidence: EvidenceLevel::Uncertain,
655                },
656            ),
657        );
658        // Verify uncertain -> known
659        self.functions.insert(
660            "verify".to_string(),
661            func(
662                vec![any.clone()],
663                Type::Evidential {
664                    inner: Box::new(any.clone()),
665                    evidence: EvidenceLevel::Known,
666                },
667            ),
668        );
669
670        // ===================
671        // Poly-cultural math (cycles, music theory)
672        // ===================
673        // MIDI note to frequency (A4 = 440Hz)
674        self.functions.insert(
675            "freq".to_string(),
676            func(vec![i64_ty.clone()], f64_ty.clone()),
677        );
678        // Octave calculation (12-tone equal temperament)
679        self.functions.insert(
680            "octave".to_string(),
681            func(vec![i64_ty.clone()], i64_ty.clone()),
682        );
683        // Note within octave (0-11)
684        self.functions.insert(
685            "pitch_class".to_string(),
686            func(vec![i64_ty.clone()], i64_ty.clone()),
687        );
688        // Modular arithmetic (cycles)
689        self.functions.insert(
690            "mod_cycle".to_string(),
691            func(vec![i64_ty.clone(), i64_ty.clone()], i64_ty.clone()),
692        );
693    }
694
695    /// Fresh type variable
696    fn fresh_var(&mut self) -> Type {
697        let var = TypeVar(self.next_var);
698        self.next_var += 1;
699        Type::Var(var)
700    }
701
702    /// Freshen a type by replacing all type variables with fresh ones
703    /// This is used for polymorphic built-in functions
704    fn freshen(&mut self, ty: &Type) -> Type {
705        let mut mapping = std::collections::HashMap::new();
706        self.freshen_inner(ty, &mut mapping)
707    }
708
709    fn freshen_inner(
710        &mut self,
711        ty: &Type,
712        mapping: &mut std::collections::HashMap<u32, Type>,
713    ) -> Type {
714        match ty {
715            Type::Var(TypeVar(id)) => {
716                if let Some(fresh) = mapping.get(id) {
717                    fresh.clone()
718                } else {
719                    let fresh = self.fresh_var();
720                    mapping.insert(*id, fresh.clone());
721                    fresh
722                }
723            }
724            Type::Array { element, size } => Type::Array {
725                element: Box::new(self.freshen_inner(element, mapping)),
726                size: *size,
727            },
728            Type::Slice(inner) => Type::Slice(Box::new(self.freshen_inner(inner, mapping))),
729            Type::Ref { mutable, inner } => Type::Ref {
730                mutable: *mutable,
731                inner: Box::new(self.freshen_inner(inner, mapping)),
732            },
733            Type::Tuple(elems) => Type::Tuple(
734                elems
735                    .iter()
736                    .map(|e| self.freshen_inner(e, mapping))
737                    .collect(),
738            ),
739            Type::Function {
740                params,
741                return_type,
742                is_async,
743            } => Type::Function {
744                params: params
745                    .iter()
746                    .map(|p| self.freshen_inner(p, mapping))
747                    .collect(),
748                return_type: Box::new(self.freshen_inner(return_type, mapping)),
749                is_async: *is_async,
750            },
751            Type::Evidential { inner, evidence } => Type::Evidential {
752                inner: Box::new(self.freshen_inner(inner, mapping)),
753                evidence: *evidence,
754            },
755            Type::Named { name, generics } => Type::Named {
756                name: name.clone(),
757                generics: generics
758                    .iter()
759                    .map(|g| self.freshen_inner(g, mapping))
760                    .collect(),
761            },
762            // Primitive types don't contain type variables
763            _ => ty.clone(),
764        }
765    }
766
767    /// Push a new scope
768    fn push_scope(&mut self) {
769        let new_env = TypeEnv::with_parent(self.env.clone());
770        self.env = Rc::new(RefCell::new(new_env));
771    }
772
773    /// Pop current scope
774    fn pop_scope(&mut self) {
775        let parent = self.env.borrow().parent.clone();
776        if let Some(p) = parent {
777            self.env = p;
778        }
779    }
780
781    /// Record an error
782    fn error(&mut self, err: TypeError) {
783        self.errors.push(err);
784    }
785
786    /// Check if actual evidence can satisfy expected evidence requirement.
787    /// Returns Ok(()) if compatible, Err with helpful message if not.
788    fn check_evidence(
789        &mut self,
790        expected: EvidenceLevel,
791        actual: EvidenceLevel,
792        context: &str,
793    ) -> bool {
794        if actual.satisfies(expected) {
795            true
796        } else {
797            let mut err = TypeError::new(format!(
798                "evidence mismatch {}: expected {} ({}), found {} ({})",
799                context,
800                expected.name(),
801                expected.symbol(),
802                actual.name(),
803                actual.symbol(),
804            ));
805
806            // Add helpful notes based on the specific mismatch
807            match (expected, actual) {
808                (EvidenceLevel::Known, EvidenceLevel::Reported) => {
809                    err = err.with_note(
810                        "reported data (~) cannot be used where known data (!) is required",
811                    );
812                    err = err.with_note(
813                        "help: use |validate!{...} to verify and promote evidence level",
814                    );
815                }
816                (EvidenceLevel::Known, EvidenceLevel::Uncertain) => {
817                    err = err.with_note(
818                        "uncertain data (?) cannot be used where known data (!) is required",
819                    );
820                    err = err.with_note(
821                        "help: use pattern matching or unwrap to handle the uncertainty",
822                    );
823                }
824                (EvidenceLevel::Uncertain, EvidenceLevel::Reported) => {
825                    err = err.with_note(
826                        "reported data (~) cannot be used where uncertain data (?) is required",
827                    );
828                    err = err.with_note("help: use |validate?{...} to verify external data");
829                }
830                _ => {
831                    err = err.with_note(format!(
832                        "evidence lattice: known (!) < uncertain (?) < reported (~) < paradox (‽)"
833                    ));
834                }
835            }
836
837            self.error(err);
838            false
839        }
840    }
841
842    /// Extract evidence level from a type, defaulting to Known
843    fn get_evidence(&self, ty: &Type) -> EvidenceLevel {
844        match ty {
845            Type::Evidential { evidence, .. } => *evidence,
846            _ => EvidenceLevel::Known,
847        }
848    }
849
850    /// Check a source file
851    pub fn check_file(&mut self, file: &SourceFile) -> Result<(), Vec<TypeError>> {
852        // First pass: collect type definitions
853        for item in &file.items {
854            self.collect_type_def(&item.node);
855        }
856
857        // Second pass: collect function signatures
858        for item in &file.items {
859            self.collect_fn_sig(&item.node);
860        }
861
862        // Third pass: check function bodies
863        for item in &file.items {
864            self.check_item(&item.node);
865        }
866
867        if self.errors.is_empty() {
868            Ok(())
869        } else {
870            Err(std::mem::take(&mut self.errors))
871        }
872    }
873
874    /// Collect type definitions (first pass)
875    fn collect_type_def(&mut self, item: &Item) {
876        match item {
877            Item::Struct(s) => {
878                let generics = s
879                    .generics
880                    .as_ref()
881                    .map(|g| {
882                        g.params
883                            .iter()
884                            .filter_map(|p| {
885                                if let GenericParam::Type { name, .. } = p {
886                                    Some(name.name.clone())
887                                } else {
888                                    None
889                                }
890                            })
891                            .collect()
892                    })
893                    .unwrap_or_default();
894
895                let fields = match &s.fields {
896                    StructFields::Named(fs) => fs
897                        .iter()
898                        .map(|f| (f.name.name.clone(), self.convert_type(&f.ty)))
899                        .collect(),
900                    StructFields::Tuple(ts) => ts
901                        .iter()
902                        .enumerate()
903                        .map(|(i, t)| (i.to_string(), self.convert_type(t)))
904                        .collect(),
905                    StructFields::Unit => vec![],
906                };
907
908                self.types
909                    .insert(s.name.name.clone(), TypeDef::Struct { generics, fields });
910            }
911            Item::Enum(e) => {
912                let generics = e
913                    .generics
914                    .as_ref()
915                    .map(|g| {
916                        g.params
917                            .iter()
918                            .filter_map(|p| {
919                                if let GenericParam::Type { name, .. } = p {
920                                    Some(name.name.clone())
921                                } else {
922                                    None
923                                }
924                            })
925                            .collect()
926                    })
927                    .unwrap_or_default();
928
929                let variants = e
930                    .variants
931                    .iter()
932                    .map(|v| {
933                        let fields = match &v.fields {
934                            StructFields::Tuple(ts) => {
935                                Some(ts.iter().map(|t| self.convert_type(t)).collect())
936                            }
937                            StructFields::Named(fs) => {
938                                Some(fs.iter().map(|f| self.convert_type(&f.ty)).collect())
939                            }
940                            StructFields::Unit => None,
941                        };
942                        (v.name.name.clone(), fields)
943                    })
944                    .collect();
945
946                self.types
947                    .insert(e.name.name.clone(), TypeDef::Enum { generics, variants });
948            }
949            Item::TypeAlias(t) => {
950                let generics = t
951                    .generics
952                    .as_ref()
953                    .map(|g| {
954                        g.params
955                            .iter()
956                            .filter_map(|p| {
957                                if let GenericParam::Type { name, .. } = p {
958                                    Some(name.name.clone())
959                                } else {
960                                    None
961                                }
962                            })
963                            .collect()
964                    })
965                    .unwrap_or_default();
966
967                let target = self.convert_type(&t.ty);
968                self.types
969                    .insert(t.name.name.clone(), TypeDef::Alias { generics, target });
970            }
971            _ => {}
972        }
973    }
974
975    /// Collect function signatures (second pass)
976    fn collect_fn_sig(&mut self, item: &Item) {
977        if let Item::Function(f) = item {
978            let params: Vec<Type> = f.params.iter().map(|p| self.convert_type(&p.ty)).collect();
979
980            let return_type = f
981                .return_type
982                .as_ref()
983                .map(|t| self.convert_type(t))
984                .unwrap_or(Type::Unit);
985
986            let fn_type = Type::Function {
987                params,
988                return_type: Box::new(return_type),
989                is_async: f.is_async,
990            };
991
992            self.functions.insert(f.name.name.clone(), fn_type);
993        }
994    }
995
996    /// Check an item (third pass)
997    fn check_item(&mut self, item: &Item) {
998        match item {
999            Item::Function(f) => self.check_function(f),
1000            Item::Const(c) => {
1001                let declared = self.convert_type(&c.ty);
1002                let inferred = self.infer_expr(&c.value);
1003                if !self.unify(&declared, &inferred) {
1004                    self.error(
1005                        TypeError::new(format!(
1006                            "type mismatch in const '{}': expected {:?}, found {:?}",
1007                            c.name.name, declared, inferred
1008                        ))
1009                        .with_span(c.name.span),
1010                    );
1011                }
1012            }
1013            Item::Static(s) => {
1014                let declared = self.convert_type(&s.ty);
1015                let inferred = self.infer_expr(&s.value);
1016                if !self.unify(&declared, &inferred) {
1017                    self.error(
1018                        TypeError::new(format!(
1019                            "type mismatch in static '{}': expected {:?}, found {:?}",
1020                            s.name.name, declared, inferred
1021                        ))
1022                        .with_span(s.name.span),
1023                    );
1024                }
1025            }
1026            _ => {}
1027        }
1028    }
1029
1030    /// Check a function body
1031    fn check_function(&mut self, func: &Function) {
1032        self.push_scope();
1033
1034        // Bind parameters with evidence inference
1035        for param in &func.params {
1036            let ty = self.convert_type(&param.ty);
1037            // Infer parameter evidence from type annotation if present,
1038            // otherwise from pattern annotation, otherwise default to Known
1039            let type_evidence = self.get_evidence(&ty);
1040            let evidence = param
1041                .pattern
1042                .evidentiality()
1043                .map(EvidenceLevel::from_ast)
1044                .unwrap_or(type_evidence);
1045
1046            if let Some(name) = param.pattern.binding_name() {
1047                self.env.borrow_mut().define(name, ty, evidence);
1048            }
1049        }
1050
1051        // Check body
1052        if let Some(ref body) = func.body {
1053            let body_type = self.check_block(body);
1054
1055            // Check return type
1056            let expected_return = func
1057                .return_type
1058                .as_ref()
1059                .map(|t| self.convert_type(t))
1060                .unwrap_or(Type::Unit);
1061
1062            // Check structural type compatibility
1063            if !self.unify(&expected_return, &body_type) {
1064                self.error(
1065                    TypeError::new(format!(
1066                        "return type mismatch in '{}': expected {:?}, found {:?}",
1067                        func.name.name, expected_return, body_type
1068                    ))
1069                    .with_span(func.name.span),
1070                );
1071            }
1072
1073            // Evidence inference for return types:
1074            // - If return type has explicit evidence annotation → check compatibility
1075            // - If no explicit annotation → infer evidence from body
1076            // - For public functions, warn if evidence should be annotated at module boundary
1077            let has_explicit_evidence = self.type_has_explicit_evidence(func.return_type.as_ref());
1078            let actual_evidence = self.get_evidence(&body_type);
1079
1080            if has_explicit_evidence {
1081                // Explicit annotation: check compatibility
1082                let expected_evidence = self.get_evidence(&expected_return);
1083                self.check_evidence(
1084                    expected_evidence,
1085                    actual_evidence,
1086                    &format!("in return type of '{}'", func.name.name),
1087                );
1088            } else {
1089                // No explicit annotation: infer from body
1090                // For public functions at module boundaries, suggest annotation
1091                if func.visibility == Visibility::Public && actual_evidence > EvidenceLevel::Known {
1092                    self.error(
1093                        TypeError::new(format!(
1094                            "public function '{}' returns {} ({}) data but has no explicit evidence annotation",
1095                            func.name.name,
1096                            actual_evidence.name(),
1097                            actual_evidence.symbol(),
1098                        ))
1099                        .with_span(func.name.span)
1100                        .with_note("help: add explicit evidence annotation to the return type")
1101                        .with_note(format!(
1102                            "example: fn {}(...) -> {}{} {{ ... }}",
1103                            func.name.name,
1104                            expected_return,
1105                            actual_evidence.symbol()
1106                        )),
1107                    );
1108                }
1109                // Inference succeeds - the body's evidence becomes the function's evidence
1110            }
1111        }
1112
1113        self.pop_scope();
1114    }
1115
1116    /// Check if a type expression has an explicit evidence annotation
1117    fn type_has_explicit_evidence(&self, ty: Option<&TypeExpr>) -> bool {
1118        match ty {
1119            Some(TypeExpr::Evidential { .. }) => true,
1120            Some(TypeExpr::Reference { inner, .. })
1121            | Some(TypeExpr::Pointer { inner, .. })
1122            | Some(TypeExpr::Slice(inner))
1123            | Some(TypeExpr::Array { element: inner, .. }) => {
1124                self.type_has_explicit_evidence(Some(inner.as_ref()))
1125            }
1126            Some(TypeExpr::Tuple(elements)) => elements
1127                .iter()
1128                .any(|e| self.type_has_explicit_evidence(Some(e))),
1129            _ => false,
1130        }
1131    }
1132
1133    /// Check a block and return its type
1134    fn check_block(&mut self, block: &Block) -> Type {
1135        self.push_scope();
1136
1137        let mut diverges = false;
1138        for stmt in &block.stmts {
1139            let stmt_ty = self.check_stmt(stmt);
1140            if matches!(stmt_ty, Type::Never) {
1141                diverges = true;
1142            }
1143        }
1144
1145        let result = if let Some(ref expr) = block.expr {
1146            self.infer_expr(expr)
1147        } else if diverges {
1148            Type::Never
1149        } else {
1150            Type::Unit
1151        };
1152
1153        self.pop_scope();
1154        result
1155    }
1156
1157    /// Check a statement and return its type (Never if it diverges)
1158    fn check_stmt(&mut self, stmt: &Stmt) -> Type {
1159        match stmt {
1160            Stmt::Let { pattern, ty, init } => {
1161                let declared_ty = ty.as_ref().map(|t| self.convert_type(t));
1162                let init_ty = init.as_ref().map(|e| self.infer_expr(e));
1163
1164                let final_ty = match (&declared_ty, &init_ty) {
1165                    (Some(d), Some(i)) => {
1166                        if !self.unify(d, i) {
1167                            self.error(TypeError::new(format!(
1168                                "type mismatch in let binding: expected {:?}, found {:?}",
1169                                d, i
1170                            )));
1171                        }
1172                        d.clone()
1173                    }
1174                    (Some(d), None) => d.clone(),
1175                    (None, Some(i)) => i.clone(),
1176                    (None, None) => self.fresh_var(),
1177                };
1178
1179                // Evidence inference: explicit annotation takes precedence,
1180                // otherwise infer from initializer expression.
1181                // This reduces annotation burden while maintaining safety:
1182                // - `let x = network_call()` → x is automatically ~
1183                // - `let x! = validated_data` → explicit ! annotation honored
1184                let evidence = pattern
1185                    .evidentiality()
1186                    .map(EvidenceLevel::from_ast)
1187                    .unwrap_or_else(|| {
1188                        // Infer evidence from initializer type
1189                        init_ty
1190                            .as_ref()
1191                            .map(|ty| self.get_evidence(ty))
1192                            .unwrap_or(EvidenceLevel::Known)
1193                    });
1194
1195                if let Some(name) = pattern.binding_name() {
1196                    self.env.borrow_mut().define(name, final_ty, evidence);
1197                }
1198                Type::Unit
1199            }
1200            Stmt::Expr(e) | Stmt::Semi(e) => self.infer_expr(e),
1201            Stmt::Item(item) => {
1202                self.check_item(item);
1203                Type::Unit
1204            }
1205        }
1206    }
1207
1208    /// Infer the type of an expression
1209    pub fn infer_expr(&mut self, expr: &Expr) -> Type {
1210        match expr {
1211            Expr::Literal(lit) => self.infer_literal(lit),
1212
1213            Expr::Path(path) => {
1214                if path.segments.len() == 1 {
1215                    let name = &path.segments[0].ident.name;
1216                    if let Some((ty, _)) = self.env.borrow().lookup(name) {
1217                        return ty;
1218                    }
1219                    if let Some(ty) = self.functions.get(name).cloned() {
1220                        // Freshen polymorphic types to get fresh type variables
1221                        return self.freshen(&ty);
1222                    }
1223                }
1224                self.error(TypeError::new(format!("undefined: {:?}", path)));
1225                Type::Error
1226            }
1227
1228            Expr::Binary { left, op, right } => {
1229                let lt = self.infer_expr(left);
1230                let rt = self.infer_expr(right);
1231                self.infer_binary_op(op, &lt, &rt)
1232            }
1233
1234            Expr::Unary { op, expr } => {
1235                let inner = self.infer_expr(expr);
1236                self.infer_unary_op(op, &inner)
1237            }
1238
1239            Expr::Call { func, args } => {
1240                let fn_type = self.infer_expr(func);
1241                let arg_types: Vec<Type> = args.iter().map(|a| self.infer_expr(a)).collect();
1242
1243                if let Type::Function {
1244                    params,
1245                    return_type,
1246                    ..
1247                } = fn_type
1248                {
1249                    // Check argument count
1250                    if params.len() != arg_types.len() {
1251                        self.error(TypeError::new(format!(
1252                            "expected {} arguments, found {}",
1253                            params.len(),
1254                            arg_types.len()
1255                        )));
1256                    }
1257
1258                    // Check argument types and evidence levels
1259                    for (i, (param, arg)) in params.iter().zip(arg_types.iter()).enumerate() {
1260                        // First check structural type compatibility
1261                        if !self.unify(param, arg) {
1262                            self.error(TypeError::new(format!(
1263                                "argument type mismatch: expected {:?}, found {:?}",
1264                                param, arg
1265                            )));
1266                        }
1267
1268                        // Check evidence compatibility only for non-polymorphic parameters.
1269                        // Type variables (used in polymorphic functions like print, len, etc.)
1270                        // accept arguments of any evidence level.
1271                        if !matches!(param, Type::Var(_)) {
1272                            let expected_evidence = self.get_evidence(param);
1273                            let actual_evidence = self.get_evidence(arg);
1274                            self.check_evidence(
1275                                expected_evidence,
1276                                actual_evidence,
1277                                &format!("in argument {}", i + 1),
1278                            );
1279                        }
1280                    }
1281
1282                    *return_type
1283                } else {
1284                    self.error(TypeError::new("cannot call non-function"));
1285                    Type::Error
1286                }
1287            }
1288
1289            Expr::Array(elements) => {
1290                if elements.is_empty() {
1291                    Type::Array {
1292                        element: Box::new(self.fresh_var()),
1293                        size: Some(0),
1294                    }
1295                } else {
1296                    let elem_ty = self.infer_expr(&elements[0]);
1297                    for elem in &elements[1..] {
1298                        let t = self.infer_expr(elem);
1299                        if !self.unify(&elem_ty, &t) {
1300                            self.error(TypeError::new("array elements must have same type"));
1301                        }
1302                    }
1303                    Type::Array {
1304                        element: Box::new(elem_ty),
1305                        size: Some(elements.len()),
1306                    }
1307                }
1308            }
1309
1310            Expr::Tuple(elements) => {
1311                Type::Tuple(elements.iter().map(|e| self.infer_expr(e)).collect())
1312            }
1313
1314            Expr::Block(block) => self.check_block(block),
1315
1316            Expr::If {
1317                condition,
1318                then_branch,
1319                else_branch,
1320            } => {
1321                let cond_ty = self.infer_expr(condition);
1322                if !self.unify(&Type::Bool, &cond_ty) {
1323                    self.error(TypeError::new("if condition must be bool"));
1324                }
1325
1326                let then_ty = self.check_block(then_branch);
1327
1328                if let Some(else_expr) = else_branch {
1329                    // Else branch can be another expr (e.g., if-else chain) or a block
1330                    let else_ty = match else_expr.as_ref() {
1331                        Expr::Block(block) => self.check_block(block),
1332                        other => self.infer_expr(other),
1333                    };
1334                    if !self.unify(&then_ty, &else_ty) {
1335                        self.error(TypeError::new("if branches must have same type"));
1336                    }
1337
1338                    // Evidence inference for control flow:
1339                    // Join evidence from both branches (pessimistic - takes least certain)
1340                    // This ensures that if either branch produces uncertain data,
1341                    // the result is marked as uncertain.
1342                    let then_ev = self.get_evidence(&then_ty);
1343                    let else_ev = self.get_evidence(&else_ty);
1344                    let joined_ev = then_ev.join(else_ev);
1345
1346                    let (inner_ty, _) = self.strip_evidence(&then_ty);
1347                    if joined_ev > EvidenceLevel::Known {
1348                        Type::Evidential {
1349                            inner: Box::new(inner_ty),
1350                            evidence: joined_ev,
1351                        }
1352                    } else {
1353                        inner_ty
1354                    }
1355                } else {
1356                    Type::Unit
1357                }
1358            }
1359
1360            Expr::Pipe { expr, operations } => {
1361                let mut current = self.infer_expr(expr);
1362
1363                for op in operations {
1364                    current = self.infer_pipe_op(op, &current);
1365                }
1366
1367                current
1368            }
1369
1370            Expr::Index { expr, index } => {
1371                let coll_ty = self.infer_expr(expr);
1372                let idx_ty = self.infer_expr(index);
1373
1374                match coll_ty {
1375                    Type::Array { element, .. } | Type::Slice(element) => {
1376                        if !matches!(idx_ty, Type::Int(_)) {
1377                            self.error(TypeError::new("index must be integer"));
1378                        }
1379                        *element
1380                    }
1381                    _ => {
1382                        self.error(TypeError::new("cannot index non-array"));
1383                        Type::Error
1384                    }
1385                }
1386            }
1387
1388            Expr::Return(val) => {
1389                if let Some(e) = val {
1390                    self.infer_expr(e);
1391                }
1392                Type::Never
1393            }
1394
1395            // Mark expression with evidence
1396            Expr::Evidential {
1397                expr,
1398                evidentiality,
1399            } => {
1400                let inner = self.infer_expr(expr);
1401                Type::Evidential {
1402                    inner: Box::new(inner),
1403                    evidence: EvidenceLevel::from_ast(*evidentiality),
1404                }
1405            }
1406
1407            // Match expression with evidence-aware dispatch
1408            Expr::Match { expr, arms } => {
1409                let scrutinee = self.infer_expr(expr);
1410                let scrutinee_ev = self.get_evidence(&scrutinee);
1411
1412                if arms.is_empty() {
1413                    return Type::Never; // Empty match is diverging
1414                }
1415
1416                // Check all arms and collect their types
1417                let mut arm_types: Vec<Type> = Vec::new();
1418                let mut max_evidence = EvidenceLevel::Known;
1419
1420                for arm in arms {
1421                    self.push_scope();
1422
1423                    // Bind pattern variables with scrutinee's evidence level
1424                    // This propagates evidence through pattern matching
1425                    self.bind_pattern(&arm.pattern, &scrutinee, scrutinee_ev);
1426
1427                    // Check guard if present
1428                    if let Some(ref guard) = arm.guard {
1429                        let guard_ty = self.infer_expr(guard);
1430                        if !self.unify(&Type::Bool, &guard_ty) {
1431                            self.error(TypeError::new("match guard must be bool"));
1432                        }
1433                    }
1434
1435                    // Infer arm body type
1436                    let body_ty = self.infer_expr(&arm.body);
1437                    let body_ev = self.get_evidence(&body_ty);
1438
1439                    // Join evidence from all arms (pessimistic)
1440                    max_evidence = max_evidence.join(body_ev);
1441                    arm_types.push(body_ty);
1442
1443                    self.pop_scope();
1444                }
1445
1446                // Unify all arm types
1447                let first_ty = &arm_types[0];
1448                for (i, ty) in arm_types.iter().enumerate().skip(1) {
1449                    if !self.unify(first_ty, ty) {
1450                        self.error(TypeError::new(format!(
1451                            "match arm {} has incompatible type",
1452                            i + 1
1453                        )));
1454                    }
1455                }
1456
1457                // Result has joined evidence from all arms
1458                let (inner_ty, _) = self.strip_evidence(first_ty);
1459                if max_evidence > EvidenceLevel::Known {
1460                    Type::Evidential {
1461                        inner: Box::new(inner_ty),
1462                        evidence: max_evidence,
1463                    }
1464                } else {
1465                    inner_ty
1466                }
1467            }
1468
1469            _ => {
1470                // Handle other expression types
1471                self.fresh_var()
1472            }
1473        }
1474    }
1475
1476    /// Infer type from literal
1477    fn infer_literal(&self, lit: &Literal) -> Type {
1478        match lit {
1479            Literal::Int { .. } => Type::Int(IntSize::I64),
1480            Literal::Float { .. } => Type::Float(FloatSize::F64),
1481            Literal::Bool(_) => Type::Bool,
1482            Literal::Char(_) => Type::Char,
1483            Literal::String(_) => Type::Str,
1484            Literal::MultiLineString(_) => Type::Str,
1485            Literal::RawString(_) => Type::Str,
1486            Literal::ByteString(bytes) => Type::Array {
1487                element: Box::new(Type::Int(IntSize::U8)),
1488                size: Some(bytes.len()),
1489            },
1490            Literal::InterpolatedString { .. } => Type::Str,
1491            Literal::SigilStringSql(_) => Type::Str,
1492            Literal::SigilStringRoute(_) => Type::Str,
1493            Literal::Null => Type::Unit, // null has unit type
1494            Literal::Empty => Type::Unit,
1495            Literal::Infinity => Type::Float(FloatSize::F64),
1496            Literal::Circle => Type::Float(FloatSize::F64),
1497        }
1498    }
1499
1500    /// Infer type of binary operation
1501    fn infer_binary_op(&mut self, op: &BinOp, left: &Type, right: &Type) -> Type {
1502        // Extract evidence levels for propagation
1503        let (left_inner, left_ev) = self.strip_evidence(left);
1504        let (right_inner, right_ev) = self.strip_evidence(right);
1505
1506        let result_ty = match op {
1507            // Arithmetic: numeric -> numeric
1508            BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::Pow => {
1509                if !self.unify(&left_inner, &right_inner) {
1510                    self.error(TypeError::new("arithmetic operands must have same type"));
1511                }
1512                left_inner
1513            }
1514
1515            // Comparison: any -> bool
1516            BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
1517                if !self.unify(&left_inner, &right_inner) {
1518                    self.error(TypeError::new("comparison operands must have same type"));
1519                }
1520                Type::Bool
1521            }
1522
1523            // Logical: bool -> bool
1524            BinOp::And | BinOp::Or => {
1525                if !self.unify(&Type::Bool, &left_inner) {
1526                    self.error(TypeError::new("logical operand must be bool"));
1527                }
1528                if !self.unify(&Type::Bool, &right_inner) {
1529                    self.error(TypeError::new("logical operand must be bool"));
1530                }
1531                Type::Bool
1532            }
1533
1534            // Bitwise: int -> int
1535            BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor | BinOp::Shl | BinOp::Shr => left_inner,
1536
1537            // String concatenation
1538            BinOp::Concat => {
1539                if !self.unify(&Type::Str, &left_inner) {
1540                    self.error(TypeError::new("concat operand must be string"));
1541                }
1542                Type::Str
1543            }
1544        };
1545
1546        // Combine evidence levels
1547        let combined_ev = left_ev.join(right_ev);
1548
1549        // Wrap result in evidence if either operand had evidence
1550        if combined_ev > EvidenceLevel::Known {
1551            Type::Evidential {
1552                inner: Box::new(result_ty),
1553                evidence: combined_ev,
1554            }
1555        } else {
1556            result_ty
1557        }
1558    }
1559
1560    /// Infer type of unary operation
1561    fn infer_unary_op(&mut self, op: &UnaryOp, inner: &Type) -> Type {
1562        let (inner_ty, evidence) = self.strip_evidence(inner);
1563
1564        let result = match op {
1565            UnaryOp::Neg => inner_ty,
1566            UnaryOp::Not => {
1567                if !self.unify(&Type::Bool, &inner_ty) {
1568                    self.error(TypeError::new("! operand must be bool"));
1569                }
1570                Type::Bool
1571            }
1572            UnaryOp::Ref => Type::Ref {
1573                mutable: false,
1574                inner: Box::new(inner_ty),
1575            },
1576            UnaryOp::RefMut => Type::Ref {
1577                mutable: true,
1578                inner: Box::new(inner_ty),
1579            },
1580            UnaryOp::Deref => {
1581                if let Type::Ref { inner, .. } | Type::Ptr { inner, .. } = inner_ty {
1582                    *inner
1583                } else {
1584                    self.error(TypeError::new("cannot dereference non-pointer"));
1585                    Type::Error
1586                }
1587            }
1588        };
1589
1590        // Preserve evidence
1591        if evidence > EvidenceLevel::Known {
1592            Type::Evidential {
1593                inner: Box::new(result),
1594                evidence,
1595            }
1596        } else {
1597            result
1598        }
1599    }
1600
1601    /// Infer type of pipe operation
1602    fn infer_pipe_op(&mut self, op: &PipeOp, input: &Type) -> Type {
1603        let (inner, evidence) = self.strip_evidence(input);
1604
1605        let result = match op {
1606            // Transform: [T] -> [U] where body: T -> U
1607            PipeOp::Transform(_body) => {
1608                if let Type::Array { element, size } = inner {
1609                    Type::Array { element, size }
1610                } else if let Type::Slice(element) = inner {
1611                    Type::Slice(element)
1612                } else {
1613                    self.error(TypeError::new("transform requires array or slice"));
1614                    Type::Error
1615                }
1616            }
1617
1618            // Filter: [T] -> [T]
1619            PipeOp::Filter(_pred) => inner,
1620
1621            // Sort: [T] -> [T]
1622            PipeOp::Sort(_) => inner,
1623
1624            // Reduce: [T] -> T
1625            PipeOp::Reduce(_) => {
1626                if let Type::Array { element, .. } | Type::Slice(element) = inner {
1627                    *element
1628                } else {
1629                    self.error(TypeError::new("reduce requires array or slice"));
1630                    Type::Error
1631                }
1632            }
1633            PipeOp::ReduceSum | PipeOp::ReduceProd | PipeOp::ReduceMin | PipeOp::ReduceMax => {
1634                // Numeric reductions return the element type
1635                if let Type::Array { element, .. } | Type::Slice(element) = inner {
1636                    match element.as_ref() {
1637                        Type::Int(_) | Type::Float(_) => *element,
1638                        _ => {
1639                            self.error(TypeError::new("numeric reduction requires numeric array"));
1640                            Type::Error
1641                        }
1642                    }
1643                } else {
1644                    self.error(TypeError::new("reduction requires array or slice"));
1645                    Type::Error
1646                }
1647            }
1648            PipeOp::ReduceConcat => {
1649                // Concat returns string or array depending on element type
1650                if let Type::Array { element, .. } | Type::Slice(element) = inner {
1651                    match element.as_ref() {
1652                        Type::Str => Type::Str,
1653                        Type::Array { .. } => *element,
1654                        _ => {
1655                            self.error(TypeError::new(
1656                                "concat reduction requires array of strings or arrays",
1657                            ));
1658                            Type::Error
1659                        }
1660                    }
1661                } else {
1662                    self.error(TypeError::new("concat reduction requires array or slice"));
1663                    Type::Error
1664                }
1665            }
1666            PipeOp::ReduceAll | PipeOp::ReduceAny => {
1667                // Boolean reductions return bool
1668                if let Type::Array { element, .. } | Type::Slice(element) = inner {
1669                    match element.as_ref() {
1670                        Type::Bool => Type::Bool,
1671                        _ => {
1672                            self.error(TypeError::new(
1673                                "boolean reduction requires array of booleans",
1674                            ));
1675                            Type::Error
1676                        }
1677                    }
1678                } else {
1679                    self.error(TypeError::new("boolean reduction requires array or slice"));
1680                    Type::Error
1681                }
1682            }
1683
1684            // Match morpheme: |match{ Pattern => expr, ... }
1685            PipeOp::Match(arms) => {
1686                // All arms should return the same type
1687                if arms.is_empty() {
1688                    self.error(TypeError::new("match expression has no arms"));
1689                    Type::Error
1690                } else {
1691                    // Infer type from first arm, other arms should match
1692                    let result_type = self.infer_expr(&arms[0].body);
1693                    for arm in arms.iter().skip(1) {
1694                        let arm_type = self.infer_expr(&arm.body);
1695                        self.unify(&result_type, &arm_type);
1696                    }
1697                    result_type
1698                }
1699            }
1700
1701            // Try/Error transformation: |? or |?{mapper}
1702            PipeOp::TryMap(_) => {
1703                // Unwraps Result<T, E> to T or Option<T> to T
1704                // For now, return a fresh type variable
1705                // (proper implementation would extract inner type from Result/Option)
1706                self.fresh_var()
1707            }
1708
1709            // Method call
1710            PipeOp::Method { name, args: _ } => {
1711                // Look up method
1712                if let Some(fn_ty) = self.functions.get(&name.name).cloned() {
1713                    // Freshen to get fresh type variables for polymorphic functions
1714                    let fresh_ty = self.freshen(&fn_ty);
1715                    if let Type::Function { return_type, .. } = fresh_ty {
1716                        *return_type
1717                    } else {
1718                        Type::Error
1719                    }
1720                } else {
1721                    // Could be a method on the type
1722                    self.fresh_var()
1723                }
1724            }
1725
1726            // Named operation (morpheme)
1727            PipeOp::Named { prefix, body: _ } => {
1728                // Named operations like |sum, |product
1729                if let Some(first) = prefix.first() {
1730                    match first.name.as_str() {
1731                        "sum" | "product" => {
1732                            if let Type::Array { element, .. } | Type::Slice(element) = inner {
1733                                *element
1734                            } else {
1735                                self.error(TypeError::new("sum/product requires array"));
1736                                Type::Error
1737                            }
1738                        }
1739                        _ => self.fresh_var(),
1740                    }
1741                } else {
1742                    self.fresh_var()
1743                }
1744            }
1745
1746            // Await: unwrap future
1747            PipeOp::Await => {
1748                // Future<T> -> T
1749                inner
1750            }
1751
1752            // Access morphemes: [T] -> T (return element type)
1753            PipeOp::First
1754            | PipeOp::Last
1755            | PipeOp::Middle
1756            | PipeOp::Choice
1757            | PipeOp::Nth(_)
1758            | PipeOp::Next => {
1759                if let Type::Array { element, .. } | Type::Slice(element) = inner {
1760                    *element
1761                } else if let Type::Tuple(elements) = inner {
1762                    // For tuple, return Any since elements might be different types
1763                    if let Some(first) = elements.first() {
1764                        first.clone()
1765                    } else {
1766                        Type::Unit
1767                    }
1768                } else {
1769                    self.error(TypeError::new(
1770                        "access morpheme requires array, slice, or tuple",
1771                    ));
1772                    Type::Error
1773                }
1774            }
1775
1776            // Parallel morpheme: ∥ - wraps another operation
1777            // Type is determined by the inner operation
1778            PipeOp::Parallel(inner_op) => self.infer_pipe_op(inner_op, input),
1779
1780            // GPU morpheme: ⊛ - wraps another operation for GPU execution
1781            // Type is determined by the inner operation
1782            PipeOp::Gpu(inner_op) => self.infer_pipe_op(inner_op, input),
1783
1784            // ==========================================
1785            // Protocol Operations - Sigil-native networking
1786            // All protocol results have Reported evidentiality
1787            // ==========================================
1788
1789            // Send: connection -> response (with Reported evidence)
1790            PipeOp::Send(_) => {
1791                // Returns response object with Reported evidentiality
1792                Type::Evidential {
1793                    inner: Box::new(self.fresh_var()),
1794                    evidence: EvidenceLevel::Reported,
1795                }
1796            }
1797
1798            // Recv: connection -> data (with Reported evidence)
1799            PipeOp::Recv => {
1800                // Returns received data with Reported evidentiality
1801                Type::Evidential {
1802                    inner: Box::new(self.fresh_var()),
1803                    evidence: EvidenceLevel::Reported,
1804                }
1805            }
1806
1807            // Stream: connection -> Stream<T> (elements have Reported evidence)
1808            PipeOp::Stream(_) => {
1809                // Returns a stream type
1810                self.fresh_var()
1811            }
1812
1813            // Connect: url/config -> connection
1814            PipeOp::Connect(_) => {
1815                // Returns connection object
1816                self.fresh_var()
1817            }
1818
1819            // Close: connection -> ()
1820            PipeOp::Close => Type::Unit,
1821
1822            // Header: request -> request (adds header)
1823            PipeOp::Header { .. } => inner,
1824
1825            // Body: request -> request (sets body)
1826            PipeOp::Body(_) => inner,
1827
1828            // Timeout: request -> request (sets timeout)
1829            PipeOp::Timeout(_) => inner,
1830
1831            // Retry: request -> request (sets retry policy)
1832            PipeOp::Retry { .. } => inner,
1833
1834            // ==========================================
1835            // Evidence Promotion Operations
1836            // ==========================================
1837
1838            // Validate: T~ -> T! (promotes with validation)
1839            PipeOp::Validate {
1840                predicate: _,
1841                target_evidence,
1842            } => {
1843                // Check that the predicate returns bool
1844                // (We'd need to infer the closure type properly, skipping for now)
1845
1846                let target_ev = EvidenceLevel::from_ast(*target_evidence);
1847
1848                // Validation can only promote evidence (make more certain)
1849                if evidence < target_ev {
1850                    self.error(
1851                        TypeError::new(format!(
1852                            "cannot demote evidence from {} ({}) to {} ({}) using validate",
1853                            evidence.name(),
1854                            evidence.symbol(),
1855                            target_ev.name(),
1856                            target_ev.symbol()
1857                        ))
1858                        .with_note("validate! can only promote evidence to a more certain level"),
1859                    );
1860                }
1861
1862                // Return inner type with promoted evidence
1863                return Type::Evidential {
1864                    inner: Box::new(inner.clone()),
1865                    evidence: target_ev,
1866                };
1867            }
1868
1869            // Assume: T~ -> T! (explicit trust with audit trail)
1870            PipeOp::Assume {
1871                reason: _,
1872                target_evidence,
1873            } => {
1874                let target_ev = EvidenceLevel::from_ast(*target_evidence);
1875
1876                // Assumption always succeeds but should be logged/audited
1877                // In a real implementation, this would record for security review
1878
1879                if evidence < target_ev {
1880                    self.error(
1881                        TypeError::new(format!(
1882                            "assume! cannot demote evidence from {} ({}) to {} ({})",
1883                            evidence.name(),
1884                            evidence.symbol(),
1885                            target_ev.name(),
1886                            target_ev.symbol()
1887                        ))
1888                        .with_note("assume! is for promoting evidence, not demoting"),
1889                    );
1890                }
1891
1892                // Return inner type with assumed evidence
1893                return Type::Evidential {
1894                    inner: Box::new(inner.clone()),
1895                    evidence: target_ev,
1896                };
1897            }
1898
1899            // AssertEvidence: compile-time evidence check
1900            PipeOp::AssertEvidence(expected_ast) => {
1901                let expected = EvidenceLevel::from_ast(*expected_ast);
1902
1903                if !evidence.satisfies(expected) {
1904                    self.error(
1905                        TypeError::new(format!(
1906                            "evidence assertion failed: expected {} ({}) or more certain, found {} ({})",
1907                            expected.name(), expected.symbol(),
1908                            evidence.name(), evidence.symbol()
1909                        ))
1910                        .with_note("use |validate!{...} or |assume! to promote evidence before assertion")
1911                    );
1912                }
1913
1914                // Return the same type (this is just an assertion)
1915                return input.clone();
1916            }
1917
1918            // ==========================================
1919            // Scope Functions (Kotlin-inspired)
1920            // ==========================================
1921
1922            // Also: execute side effect, return original value unchanged
1923            // T -> T (side effect executed but value preserved)
1924            PipeOp::Also(_) => {
1925                // The closure is executed for side effects only
1926                // Return type is same as input, evidence preserved
1927                return input.clone();
1928            }
1929
1930            // Apply: mutate value in place, return modified value
1931            // T -> T (value may be mutated)
1932            PipeOp::Apply(_) => {
1933                // The closure can mutate the value
1934                // Return type is same as input, evidence preserved
1935                return input.clone();
1936            }
1937
1938            // TakeIf: return Some(value) if predicate true, None otherwise
1939            // T -> Option<T>
1940            PipeOp::TakeIf(_) => {
1941                // Returns Option wrapping the input type
1942                // Evidence is preserved in the inner type
1943                return Type::Named {
1944                    name: "Option".to_string(),
1945                    generics: vec![input.clone()],
1946                };
1947            }
1948
1949            // TakeUnless: return Some(value) if predicate false, None otherwise
1950            // T -> Option<T>
1951            PipeOp::TakeUnless(_) => {
1952                // Returns Option wrapping the input type
1953                // Evidence is preserved in the inner type
1954                return Type::Named {
1955                    name: "Option".to_string(),
1956                    generics: vec![input.clone()],
1957                };
1958            }
1959
1960            // Let: transform value (alias for Transform/tau)
1961            // T -> U
1962            PipeOp::Let(func) => {
1963                // Same as Transform - applies function and returns result
1964                let _ = self.infer_expr(func);
1965                self.fresh_var() // Result type depends on function
1966            }
1967
1968            // Mathematical & APL-Inspired Operations
1969            PipeOp::All(_) | PipeOp::Any(_) => Type::Bool,
1970            PipeOp::Compose(f) => {
1971                let _ = self.infer_expr(f);
1972                self.fresh_var()
1973            }
1974            PipeOp::Zip(other) => {
1975                let _ = self.infer_expr(other);
1976                self.fresh_var() // Array of tuples
1977            }
1978            PipeOp::Scan(f) => {
1979                let _ = self.infer_expr(f);
1980                self.fresh_var() // Array of accumulated values
1981            }
1982            PipeOp::Diff => self.fresh_var(), // Array of differences
1983            PipeOp::Gradient(var) => {
1984                let _ = self.infer_expr(var);
1985                self.fresh_var() // Gradient value
1986            }
1987            PipeOp::SortAsc | PipeOp::SortDesc | PipeOp::Reverse => {
1988                inner.clone() // Same type, reordered
1989            }
1990            PipeOp::Cycle(n) | PipeOp::Windows(n) | PipeOp::Chunks(n) => {
1991                let _ = self.infer_expr(n);
1992                self.fresh_var() // Array type
1993            }
1994            PipeOp::Flatten | PipeOp::Unique => self.fresh_var(),
1995            PipeOp::Enumerate => self.fresh_var(), // Array of (index, value) tuples
1996        };
1997
1998        // Preserve evidence through pipe
1999        if evidence > EvidenceLevel::Known {
2000            Type::Evidential {
2001                inner: Box::new(result),
2002                evidence,
2003            }
2004        } else {
2005            result
2006        }
2007    }
2008
2009    /// Strip evidence wrapper, returning (inner_type, evidence_level)
2010    fn strip_evidence(&self, ty: &Type) -> (Type, EvidenceLevel) {
2011        match ty {
2012            Type::Evidential { inner, evidence } => (*inner.clone(), *evidence),
2013            _ => (ty.clone(), EvidenceLevel::Known),
2014        }
2015    }
2016
2017    /// Bind pattern variables with the given type and evidence level.
2018    /// This propagates evidence through pattern matching.
2019    fn bind_pattern(&mut self, pattern: &Pattern, ty: &Type, evidence: EvidenceLevel) {
2020        let (inner_ty, ty_ev) = self.strip_evidence(ty);
2021        // Use the more restrictive evidence level
2022        let final_ev = evidence.join(ty_ev);
2023
2024        match pattern {
2025            Pattern::Ident {
2026                name,
2027                evidentiality,
2028                ..
2029            } => {
2030                // Explicit evidence annotation overrides inference
2031                let ev = evidentiality
2032                    .map(EvidenceLevel::from_ast)
2033                    .unwrap_or(final_ev);
2034                self.env
2035                    .borrow_mut()
2036                    .define(name.name.clone(), inner_ty, ev);
2037            }
2038            Pattern::Tuple(patterns) => {
2039                if let Type::Tuple(types) = &inner_ty {
2040                    for (pat, ty) in patterns.iter().zip(types.iter()) {
2041                        self.bind_pattern(pat, ty, final_ev);
2042                    }
2043                }
2044            }
2045            Pattern::Struct { fields, .. } => {
2046                // For struct patterns, we'd need field type info
2047                // For now, bind with fresh vars
2048                for field in fields {
2049                    let fresh = self.fresh_var();
2050                    if let Some(ref pat) = field.pattern {
2051                        self.bind_pattern(pat, &fresh, final_ev);
2052                    } else {
2053                        self.env
2054                            .borrow_mut()
2055                            .define(field.name.name.clone(), fresh, final_ev);
2056                    }
2057                }
2058            }
2059            Pattern::TupleStruct { fields, .. } => {
2060                for pat in fields {
2061                    let fresh = self.fresh_var();
2062                    self.bind_pattern(pat, &fresh, final_ev);
2063                }
2064            }
2065            Pattern::Slice(patterns) => {
2066                let elem_ty = if let Type::Array { element, .. } | Type::Slice(element) = &inner_ty
2067                {
2068                    *element.clone()
2069                } else {
2070                    self.fresh_var()
2071                };
2072                for pat in patterns {
2073                    self.bind_pattern(pat, &elem_ty, final_ev);
2074                }
2075            }
2076            Pattern::Or(patterns) => {
2077                // For or-patterns, bind the same variables from any branch
2078                // (they should all have the same bindings)
2079                if let Some(first) = patterns.first() {
2080                    self.bind_pattern(first, ty, evidence);
2081                }
2082            }
2083            Pattern::Wildcard | Pattern::Rest | Pattern::Literal(_) | Pattern::Range { .. } => {
2084                // These don't introduce bindings
2085            }
2086        }
2087    }
2088
2089    /// Attempt to unify two types
2090    fn unify(&mut self, a: &Type, b: &Type) -> bool {
2091        match (a, b) {
2092            // Same types
2093            (Type::Unit, Type::Unit) |
2094            (Type::Bool, Type::Bool) |
2095            (Type::Char, Type::Char) |
2096            (Type::Str, Type::Str) |
2097            (Type::Never, Type::Never) |
2098            (Type::Error, _) |
2099            (_, Type::Error) |
2100            // Never (bottom type) unifies with anything
2101            (Type::Never, _) |
2102            (_, Type::Never) => true,
2103
2104            (Type::Int(a), Type::Int(b)) => a == b,
2105            (Type::Float(a), Type::Float(b)) => a == b,
2106
2107            // Arrays
2108            (Type::Array { element: a, size: sa }, Type::Array { element: b, size: sb }) => {
2109                (sa == sb || sa.is_none() || sb.is_none()) && self.unify(a, b)
2110            }
2111
2112            // Slices
2113            (Type::Slice(a), Type::Slice(b)) => self.unify(a, b),
2114
2115            // Tuples
2116            (Type::Tuple(a), Type::Tuple(b)) if a.len() == b.len() => {
2117                a.iter().zip(b.iter()).all(|(x, y)| self.unify(x, y))
2118            }
2119
2120            // References
2121            (Type::Ref { mutable: ma, inner: a }, Type::Ref { mutable: mb, inner: b }) => {
2122                ma == mb && self.unify(a, b)
2123            }
2124
2125            // Functions
2126            (Type::Function { params: pa, return_type: ra, is_async: aa },
2127             Type::Function { params: pb, return_type: rb, is_async: ab }) => {
2128                aa == ab && pa.len() == pb.len() &&
2129                pa.iter().zip(pb.iter()).all(|(x, y)| self.unify(x, y)) &&
2130                self.unify(ra, rb)
2131            }
2132
2133            // Named types
2134            (Type::Named { name: na, generics: ga }, Type::Named { name: nb, generics: gb }) => {
2135                na == nb && ga.len() == gb.len() &&
2136                ga.iter().zip(gb.iter()).all(|(x, y)| self.unify(x, y))
2137            }
2138
2139            // Evidential types: inner must unify, evidence can differ
2140            (Type::Evidential { inner: a, .. }, Type::Evidential { inner: b, .. }) => {
2141                self.unify(a, b)
2142            }
2143            (Type::Evidential { inner: a, .. }, b) => {
2144                self.unify(a, b)
2145            }
2146            (a, Type::Evidential { inner: b, .. }) => {
2147                self.unify(a, b)
2148            }
2149
2150            // Type variables
2151            (Type::Var(v), t) => {
2152                if let Some(resolved) = self.substitutions.get(v) {
2153                    let resolved = resolved.clone();
2154                    self.unify(&resolved, t)
2155                } else {
2156                    self.substitutions.insert(*v, t.clone());
2157                    true
2158                }
2159            }
2160            (t, Type::Var(v)) => {
2161                if let Some(resolved) = self.substitutions.get(v) {
2162                    let resolved = resolved.clone();
2163                    self.unify(t, &resolved)
2164                } else {
2165                    self.substitutions.insert(*v, t.clone());
2166                    true
2167                }
2168            }
2169
2170            // Cycles
2171            (Type::Cycle { modulus: a }, Type::Cycle { modulus: b }) => a == b,
2172
2173            _ => false,
2174        }
2175    }
2176
2177    /// Convert AST type to internal type
2178    fn convert_type(&self, ty: &TypeExpr) -> Type {
2179        match ty {
2180            TypeExpr::Path(path) => {
2181                if path.segments.len() == 1 {
2182                    let name = &path.segments[0].ident.name;
2183                    match name.as_str() {
2184                        "bool" => return Type::Bool,
2185                        "char" => return Type::Char,
2186                        "str" | "String" => return Type::Str,
2187                        "i8" => return Type::Int(IntSize::I8),
2188                        "i16" => return Type::Int(IntSize::I16),
2189                        "i32" => return Type::Int(IntSize::I32),
2190                        "i64" => return Type::Int(IntSize::I64),
2191                        "i128" => return Type::Int(IntSize::I128),
2192                        "isize" => return Type::Int(IntSize::ISize),
2193                        "u8" => return Type::Int(IntSize::U8),
2194                        "u16" => return Type::Int(IntSize::U16),
2195                        "u32" => return Type::Int(IntSize::U32),
2196                        "u64" => return Type::Int(IntSize::U64),
2197                        "u128" => return Type::Int(IntSize::U128),
2198                        "usize" => return Type::Int(IntSize::USize),
2199                        "f32" => return Type::Float(FloatSize::F32),
2200                        "f64" => return Type::Float(FloatSize::F64),
2201                        _ => {}
2202                    }
2203                }
2204
2205                let name = path
2206                    .segments
2207                    .iter()
2208                    .map(|s| s.ident.name.clone())
2209                    .collect::<Vec<_>>()
2210                    .join("::");
2211
2212                let generics = path
2213                    .segments
2214                    .last()
2215                    .and_then(|s| s.generics.as_ref())
2216                    .map(|gs| gs.iter().map(|t| self.convert_type(t)).collect())
2217                    .unwrap_or_default();
2218
2219                Type::Named { name, generics }
2220            }
2221
2222            TypeExpr::Reference { mutable, inner } => Type::Ref {
2223                mutable: *mutable,
2224                inner: Box::new(self.convert_type(inner)),
2225            },
2226
2227            TypeExpr::Pointer { mutable, inner } => Type::Ptr {
2228                mutable: *mutable,
2229                inner: Box::new(self.convert_type(inner)),
2230            },
2231
2232            TypeExpr::Array { element, size: _ } => {
2233                Type::Array {
2234                    element: Box::new(self.convert_type(element)),
2235                    size: None, // Could evaluate const expr
2236                }
2237            }
2238
2239            TypeExpr::Slice(inner) => Type::Slice(Box::new(self.convert_type(inner))),
2240
2241            TypeExpr::Tuple(elements) => {
2242                Type::Tuple(elements.iter().map(|t| self.convert_type(t)).collect())
2243            }
2244
2245            TypeExpr::Function {
2246                params,
2247                return_type,
2248            } => Type::Function {
2249                params: params.iter().map(|t| self.convert_type(t)).collect(),
2250                return_type: Box::new(
2251                    return_type
2252                        .as_ref()
2253                        .map(|t| self.convert_type(t))
2254                        .unwrap_or(Type::Unit),
2255                ),
2256                is_async: false,
2257            },
2258
2259            TypeExpr::Evidential {
2260                inner,
2261                evidentiality,
2262                error_type,
2263            } => {
2264                // If error_type is specified, this is sugar for Result<T, E>
2265                // For now, lower as evidential type; full expansion to Result comes later
2266                let _ = error_type; // TODO: expand T?[E] to Result<T, E> with evidence
2267                Type::Evidential {
2268                    inner: Box::new(self.convert_type(inner)),
2269                    evidence: EvidenceLevel::from_ast(*evidentiality),
2270                }
2271            }
2272
2273            TypeExpr::Cycle { modulus: _ } => {
2274                Type::Cycle { modulus: 12 } // Default, should evaluate
2275            }
2276
2277            TypeExpr::Simd { element, lanes } => {
2278                let elem_ty = self.convert_type(element);
2279                Type::Simd {
2280                    element: Box::new(elem_ty),
2281                    lanes: *lanes,
2282                }
2283            }
2284
2285            TypeExpr::Atomic(inner) => {
2286                let inner_ty = self.convert_type(inner);
2287                Type::Atomic(Box::new(inner_ty))
2288            }
2289
2290            TypeExpr::Never => Type::Never,
2291            TypeExpr::Infer => Type::Var(TypeVar(0)), // Fresh var
2292        }
2293    }
2294
2295    /// Get errors
2296    pub fn errors(&self) -> &[TypeError] {
2297        &self.errors
2298    }
2299}
2300
2301impl Default for TypeChecker {
2302    fn default() -> Self {
2303        Self::new()
2304    }
2305}
2306
2307// Helper trait for Pattern
2308trait PatternExt {
2309    fn evidentiality(&self) -> Option<Evidentiality>;
2310    fn binding_name(&self) -> Option<String>;
2311}
2312
2313impl PatternExt for Pattern {
2314    fn evidentiality(&self) -> Option<Evidentiality> {
2315        match self {
2316            Pattern::Ident { evidentiality, .. } => *evidentiality,
2317            _ => None,
2318        }
2319    }
2320
2321    fn binding_name(&self) -> Option<String> {
2322        match self {
2323            Pattern::Ident { name, .. } => Some(name.name.clone()),
2324            _ => None,
2325        }
2326    }
2327}
2328
2329impl fmt::Display for Type {
2330    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2331        match self {
2332            Type::Unit => write!(f, "()"),
2333            Type::Bool => write!(f, "bool"),
2334            Type::Int(size) => write!(f, "{:?}", size),
2335            Type::Float(size) => write!(f, "{:?}", size),
2336            Type::Char => write!(f, "char"),
2337            Type::Str => write!(f, "str"),
2338            Type::Array { element, size } => {
2339                if let Some(n) = size {
2340                    write!(f, "[{}; {}]", element, n)
2341                } else {
2342                    write!(f, "[{}]", element)
2343                }
2344            }
2345            Type::Slice(inner) => write!(f, "[{}]", inner),
2346            Type::Tuple(elems) => {
2347                write!(f, "(")?;
2348                for (i, e) in elems.iter().enumerate() {
2349                    if i > 0 {
2350                        write!(f, ", ")?;
2351                    }
2352                    write!(f, "{}", e)?;
2353                }
2354                write!(f, ")")
2355            }
2356            Type::Named { name, generics } => {
2357                write!(f, "{}", name)?;
2358                if !generics.is_empty() {
2359                    write!(f, "<")?;
2360                    for (i, g) in generics.iter().enumerate() {
2361                        if i > 0 {
2362                            write!(f, ", ")?;
2363                        }
2364                        write!(f, "{}", g)?;
2365                    }
2366                    write!(f, ">")?;
2367                }
2368                Ok(())
2369            }
2370            Type::Function {
2371                params,
2372                return_type,
2373                is_async,
2374            } => {
2375                if *is_async {
2376                    write!(f, "async ")?;
2377                }
2378                write!(f, "fn(")?;
2379                for (i, p) in params.iter().enumerate() {
2380                    if i > 0 {
2381                        write!(f, ", ")?;
2382                    }
2383                    write!(f, "{}", p)?;
2384                }
2385                write!(f, ") -> {}", return_type)
2386            }
2387            Type::Ref { mutable, inner } => {
2388                write!(f, "&{}{}", if *mutable { "mut " } else { "" }, inner)
2389            }
2390            Type::Ptr { mutable, inner } => {
2391                write!(f, "*{}{}", if *mutable { "mut " } else { "const " }, inner)
2392            }
2393            Type::Evidential { inner, evidence } => {
2394                write!(f, "{}{}", inner, evidence.symbol())
2395            }
2396            Type::Cycle { modulus } => write!(f, "Cycle<{}>", modulus),
2397            Type::Var(v) => write!(f, "?{}", v.0),
2398            Type::Error => write!(f, "<error>"),
2399            Type::Never => write!(f, "!"),
2400            Type::Simd { element, lanes } => write!(f, "simd<{}, {}>", element, lanes),
2401            Type::Atomic(inner) => write!(f, "atomic<{}>", inner),
2402        }
2403    }
2404}
2405
2406#[cfg(test)]
2407mod tests {
2408    use super::*;
2409    use crate::Parser;
2410
2411    fn check(source: &str) -> Result<(), Vec<TypeError>> {
2412        let mut parser = Parser::new(source);
2413        let file = parser.parse_file().expect("parse failed");
2414        let mut checker = TypeChecker::new();
2415        checker.check_file(&file)
2416    }
2417
2418    #[test]
2419    fn test_basic_types() {
2420        assert!(check("fn main() { let x: i64 = 42; }").is_ok());
2421        assert!(check("fn main() { let x: bool = true; }").is_ok());
2422        assert!(check("fn main() { let x: f64 = 3.14; }").is_ok());
2423    }
2424
2425    #[test]
2426    fn test_type_mismatch() {
2427        assert!(check("fn main() { let x: bool = 42; }").is_err());
2428    }
2429
2430    #[test]
2431    fn test_evidence_propagation() {
2432        // Evidence should propagate through operations
2433        assert!(check(
2434            r#"
2435            fn main() {
2436                let known: i64! = 42;
2437                let uncertain: i64? = 10;
2438                let result = known + uncertain;
2439            }
2440        "#
2441        )
2442        .is_ok());
2443    }
2444
2445    #[test]
2446    fn test_function_return() {
2447        let result = check(
2448            r#"
2449            fn add(a: i64, b: i64) -> i64 {
2450                return a + b;
2451            }
2452            fn main() {
2453                let x = add(1, 2);
2454            }
2455        "#,
2456        );
2457        if let Err(errors) = &result {
2458            for e in errors {
2459                eprintln!("Error: {}", e);
2460            }
2461        }
2462        assert!(result.is_ok());
2463    }
2464
2465    #[test]
2466    fn test_array_types() {
2467        assert!(check(
2468            r#"
2469            fn main() {
2470                let arr = [1, 2, 3];
2471                let x = arr[0];
2472            }
2473        "#
2474        )
2475        .is_ok());
2476    }
2477
2478    // ==========================================
2479    // Evidence Inference Tests
2480    // ==========================================
2481
2482    #[test]
2483    fn test_evidence_inference_from_initializer() {
2484        // Evidence should be inferred from initializer when not explicitly annotated
2485        assert!(check(
2486            r#"
2487            fn main() {
2488                let reported_val: i64~ = 42;
2489                // x should inherit ~ evidence from reported_val
2490                let x = reported_val + 1;
2491            }
2492        "#
2493        )
2494        .is_ok());
2495    }
2496
2497    #[test]
2498    fn test_evidence_inference_explicit_override() {
2499        // Explicit annotation should override inference
2500        assert!(check(
2501            r#"
2502            fn main() {
2503                let reported_val: i64~ = 42;
2504                // Explicit ! annotation - this would fail if we checked evidence properly
2505                // but the type system allows it as an override
2506                let x! = 42;
2507            }
2508        "#
2509        )
2510        .is_ok());
2511    }
2512
2513    #[test]
2514    fn test_if_else_evidence_join() {
2515        // Evidence from both branches should be joined
2516        assert!(check(
2517            r#"
2518            fn main() {
2519                let known_val: i64! = 1;
2520                let reported_val: i64~ = 2;
2521                let cond: bool = true;
2522                // Result should have ~ evidence (join of ! and ~)
2523                let result = if cond { known_val } else { reported_val };
2524            }
2525        "#
2526        )
2527        .is_ok());
2528    }
2529
2530    #[test]
2531    fn test_binary_op_evidence_propagation() {
2532        // Binary operations should join evidence levels
2533        assert!(check(
2534            r#"
2535            fn main() {
2536                let known: i64! = 1;
2537                let reported: i64~ = 2;
2538                // Result should have ~ evidence (max of ! and ~)
2539                let result = known + reported;
2540            }
2541        "#
2542        )
2543        .is_ok());
2544    }
2545
2546    #[test]
2547    fn test_match_evidence_join() {
2548        // Match arms should join evidence from all branches
2549        // Note: This test is structural - the type checker should handle it
2550        assert!(check(
2551            r#"
2552            fn main() {
2553                let x: i64 = 1;
2554            }
2555        "#
2556        )
2557        .is_ok());
2558    }
2559}