Skip to main content

palladium/typeck/
mod.rs

1// Type checker for Palladium
2// "Ensuring legends are logically sound"
3
4use crate::ast::{AssignTarget, UnaryOp, *};
5use crate::errors::{CompileError, Result};
6use std::collections::HashMap;
7
8mod suggestions;
9use suggestions::TypeErrorHelper;
10
11mod exhaustiveness;
12use exhaustiveness::{EnumInfo, ExhaustivenessChecker, VariantInfo};
13
14mod trait_resolution;
15use trait_resolution::TraitResolver;
16
17/// Type representation for type checker (wraps AST Type)
18#[derive(Debug, Clone, PartialEq)]
19pub enum CheckerType {
20    Unit,
21    String,
22    Int,
23    Bool,
24    Array(Box<CheckerType>, ArraySizeValue),
25    Function(Vec<CheckerType>, Box<CheckerType>),
26    Struct(String),
27    TypeParam(String),
28    Enum(String),
29    Generic {
30        name: String,
31        args: Vec<GenericArgValue>,
32    },
33}
34
35/// Array size value for type checking
36#[derive(Debug, Clone, PartialEq)]
37pub enum ArraySizeValue {
38    Literal(usize),
39    ConstParam(String),
40}
41
42impl std::fmt::Display for ArraySizeValue {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        match self {
45            ArraySizeValue::Literal(n) => write!(f, "{}", n),
46            ArraySizeValue::ConstParam(name) => write!(f, "{}", name),
47        }
48    }
49}
50
51/// Generic argument value for type checking
52#[derive(Debug, Clone, PartialEq)]
53pub enum GenericArgValue {
54    Type(CheckerType),
55    Const(ConstValueResolved),
56}
57
58/// Resolved const value
59#[derive(Debug, Clone, PartialEq)]
60pub enum ConstValueResolved {
61    Integer(i64),
62    ConstParam(String),
63}
64
65impl From<&crate::ast::Type> for CheckerType {
66    fn from(ast_type: &crate::ast::Type) -> Self {
67        match ast_type {
68            crate::ast::Type::Unit => CheckerType::Unit,
69            crate::ast::Type::String => CheckerType::String,
70            crate::ast::Type::I32 | crate::ast::Type::I64 => CheckerType::Int,
71            crate::ast::Type::Bool => CheckerType::Bool,
72            crate::ast::Type::U32 | crate::ast::Type::U64 => CheckerType::Int,
73            crate::ast::Type::Array(elem_type, size) => {
74                let size_value = match size {
75                    ArraySize::Literal(n) => ArraySizeValue::Literal(*n),
76                    ArraySize::ConstParam(name) => ArraySizeValue::ConstParam(name.clone()),
77                    ArraySize::Expr(_) => {
78                        // For now, we don't support expressions
79                        ArraySizeValue::Literal(0) // Placeholder
80                    }
81                };
82                CheckerType::Array(Box::new(CheckerType::from(elem_type.as_ref())), size_value)
83            }
84            crate::ast::Type::Custom(name) => CheckerType::Struct(name.clone()),
85            crate::ast::Type::TypeParam(name) => {
86                // Type parameters need proper handling through substitution
87                // For now, create a placeholder type that can be unified later
88                CheckerType::TypeParam(name.clone())
89            }
90            crate::ast::Type::Generic { name, args } => {
91                // Convert generic arguments properly
92                let checker_args: Vec<GenericArgValue> = args
93                    .iter()
94                    .map(|arg| match arg {
95                        GenericArg::Type(t) => GenericArgValue::Type(CheckerType::from(t)),
96                        GenericArg::Const(c) => GenericArgValue::Const(match c {
97                            ConstValue::Integer(n) => ConstValueResolved::Integer(*n),
98                            ConstValue::ConstParam(name) => {
99                                ConstValueResolved::ConstParam(name.clone())
100                            }
101                        }),
102                    })
103                    .collect();
104                CheckerType::Generic {
105                    name: name.clone(),
106                    args: checker_args,
107                }
108            }
109            crate::ast::Type::Reference { inner, .. } => {
110                // For now, treat references as the inner type
111                // TODO: Proper reference type handling
112                CheckerType::from(inner.as_ref())
113            }
114            crate::ast::Type::Future { output } => {
115                // Create a Future generic type
116                CheckerType::Generic {
117                    name: "Future".to_string(),
118                    args: vec![GenericArgValue::Type(CheckerType::from(output.as_ref()))],
119                }
120            }
121        }
122    }
123}
124
125impl std::fmt::Display for CheckerType {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        match self {
128            CheckerType::Unit => write!(f, "()"),
129            CheckerType::String => write!(f, "String"),
130            CheckerType::Int => write!(f, "Int"),
131            CheckerType::Bool => write!(f, "Bool"),
132            CheckerType::Array(elem_type, size) => match size {
133                ArraySizeValue::Literal(n) => write!(f, "[{}; {}]", elem_type, n),
134                ArraySizeValue::ConstParam(name) => write!(f, "[{}; {}]", elem_type, name),
135            },
136            CheckerType::Function(params, ret) => {
137                write!(f, "fn(")?;
138                for (i, param) in params.iter().enumerate() {
139                    if i > 0 {
140                        write!(f, ", ")?;
141                    }
142                    write!(f, "{}", param)?;
143                }
144                write!(f, ") -> {}", ret)
145            }
146            CheckerType::Struct(name) => write!(f, "{}", name),
147            CheckerType::TypeParam(name) => write!(f, "{}", name),
148            CheckerType::Enum(name) => write!(f, "{}", name),
149            CheckerType::Generic { name, args } => {
150                write!(f, "{}<", name)?;
151                for (i, arg) in args.iter().enumerate() {
152                    if i > 0 {
153                        write!(f, ", ")?;
154                    }
155                    match arg {
156                        GenericArgValue::Type(t) => write!(f, "{}", t)?,
157                        GenericArgValue::Const(c) => match c {
158                            ConstValueResolved::Integer(n) => write!(f, "{}", n)?,
159                            ConstValueResolved::ConstParam(name) => write!(f, "{}", name)?,
160                        },
161                    }
162                }
163                write!(f, ">")
164            }
165        }
166    }
167}
168
169/// Variable information including type and mutability
170#[derive(Debug, Clone)]
171struct VarInfo {
172    ty: CheckerType,
173    mutable: bool,
174}
175
176/// Symbol table for storing variable types with scope support
177#[derive(Debug, Clone)]
178struct SymbolTable {
179    scopes: Vec<HashMap<String, VarInfo>>,
180}
181
182impl SymbolTable {
183    fn new() -> Self {
184        Self {
185            scopes: vec![HashMap::new()], // Start with global scope
186        }
187    }
188
189    /// Enter a new scope
190    fn enter_scope(&mut self) {
191        self.scopes.push(HashMap::new());
192    }
193
194    /// Exit the current scope
195    fn exit_scope(&mut self) {
196        if self.scopes.len() > 1 {
197            self.scopes.pop();
198        }
199    }
200
201    /// Define a variable in the current scope
202    fn define(&mut self, name: String, ty: CheckerType, mutable: bool) -> Result<()> {
203        if let Some(scope) = self.scopes.last_mut() {
204            if scope.contains_key(&name) {
205                return Err(CompileError::Generic(format!(
206                    "Variable '{}' already defined in this scope",
207                    name
208                )));
209            }
210            scope.insert(name, VarInfo { ty, mutable });
211            Ok(())
212        } else {
213            Err(CompileError::Generic("No active scope".to_string()))
214        }
215    }
216
217    /// Look up a variable (searches all scopes from innermost to outermost)
218    fn lookup(&self, name: &str) -> Option<&VarInfo> {
219        for scope in self.scopes.iter().rev() {
220            if let Some(info) = scope.get(name) {
221                return Some(info);
222            }
223        }
224        None
225    }
226}
227
228/// Information about a generic function
229#[derive(Debug, Clone)]
230pub struct GenericFunction {
231    pub lifetime_params: Vec<String>,
232    pub type_params: Vec<String>,
233    pub params: Vec<(String, crate::ast::Type)>,
234    pub return_type: Option<crate::ast::Type>,
235    pub body: Vec<crate::ast::Stmt>,
236}
237
238/// Generic enum definition
239#[derive(Debug, Clone)]
240pub struct GenericEnum {
241    pub lifetime_params: Vec<String>,
242    pub type_params: Vec<String>,
243    pub variants: Vec<(String, crate::ast::EnumVariantData)>,
244}
245
246/// Generic struct definition
247#[derive(Debug, Clone)]
248pub struct GenericStruct {
249    pub lifetime_params: Vec<String>,
250    pub type_params: Vec<String>,
251    pub fields: Vec<(String, crate::ast::Type)>,
252}
253
254/// Generic type alias definition
255#[derive(Debug, Clone)]
256pub struct GenericTypeAlias {
257    pub lifetime_params: Vec<String>,
258    pub type_params: Vec<String>,
259    pub ty: crate::ast::Type,
260}
261
262/// Enum variant information
263#[derive(Debug, Clone)]
264struct EnumVariant {
265    name: String,
266    fields: EnumVariantFields,
267}
268
269#[derive(Debug, Clone)]
270enum EnumVariantFields {
271    Unit,
272    Tuple(Vec<CheckerType>),
273    Named(Vec<(String, CheckerType)>),
274}
275
276/// A concrete instantiation of a generic function
277#[derive(Debug, Clone, PartialEq, Eq, Hash)]
278struct FunctionInstantiation {
279    name: String,
280    type_args: Vec<String>, // Concrete types like "i64", "String"
281}
282
283/// A concrete instantiation of a generic struct
284#[derive(Debug, Clone, PartialEq, Eq, Hash)]
285pub struct StructInstantiation {
286    pub name: String,
287    pub type_args: Vec<String>, // Concrete types like "i64", "String"
288}
289
290pub struct TypeChecker {
291    /// Function signatures
292    functions: HashMap<String, CheckerType>,
293    /// Generic function definitions
294    generic_functions: HashMap<String, GenericFunction>,
295    /// Instantiated generic functions
296    instantiations: HashMap<FunctionInstantiation, CheckerType>,
297    /// Struct definitions
298    structs: HashMap<String, Vec<(String, CheckerType)>>,
299    /// Generic struct definitions
300    generic_structs: HashMap<String, GenericStruct>,
301    /// Trait resolver
302    trait_resolver: TraitResolver,
303    /// Instantiated generic structs
304    struct_instantiations: HashMap<StructInstantiation, CheckerType>,
305    /// Enum definitions with their variants
306    enums: HashMap<String, Vec<EnumVariant>>,
307    /// Generic enum definitions
308    generic_enums: HashMap<String, GenericEnum>,
309    /// Type alias definitions
310    type_aliases: HashMap<String, crate::ast::Type>,
311    /// Generic type alias definitions
312    generic_type_aliases: HashMap<String, GenericTypeAlias>,
313    /// Current function return type (for checking return statements)
314    current_function_return: Option<CheckerType>,
315    /// Symbol table for variables
316    symbols: SymbolTable,
317    /// Imported modules and their exported items
318    imported_modules: HashMap<String, crate::resolver::ModuleInfo>,
319    /// Loop depth counter (for break/continue validation)
320    loop_depth: usize,
321    /// Error helper for better suggestions
322    error_helper: TypeErrorHelper,
323    /// Unsafe block depth counter (for tracking unsafe context)
324    unsafe_depth: usize,
325}
326
327impl Default for TypeChecker {
328    fn default() -> Self {
329        Self::new()
330    }
331}
332
333impl TypeChecker {
334    pub fn new() -> Self {
335        let mut functions = HashMap::new();
336
337        // Built-in functions
338        functions.insert(
339            "print".to_string(),
340            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Unit)),
341        );
342
343        // print_int built-in function
344        functions.insert(
345            "print_int".to_string(),
346            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Unit)),
347        );
348
349        // String manipulation functions
350        functions.insert(
351            "string_len".to_string(),
352            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
353        );
354        functions.insert(
355            "string_concat".to_string(),
356            CheckerType::Function(
357                vec![CheckerType::String, CheckerType::String],
358                Box::new(CheckerType::String),
359            ),
360        );
361        functions.insert(
362            "string_eq".to_string(),
363            CheckerType::Function(
364                vec![CheckerType::String, CheckerType::String],
365                Box::new(CheckerType::Bool),
366            ),
367        );
368        functions.insert(
369            "string_char_at".to_string(),
370            CheckerType::Function(
371                vec![CheckerType::String, CheckerType::Int],
372                Box::new(CheckerType::Int),
373            ),
374        );
375        functions.insert(
376            "string_substring".to_string(),
377            CheckerType::Function(
378                vec![CheckerType::String, CheckerType::Int, CheckerType::Int],
379                Box::new(CheckerType::String),
380            ),
381        );
382        functions.insert(
383            "string_from_char".to_string(),
384            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::String)),
385        );
386        functions.insert(
387            "char_is_digit".to_string(),
388            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Bool)),
389        );
390        functions.insert(
391            "char_is_alpha".to_string(),
392            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Bool)),
393        );
394        functions.insert(
395            "char_is_whitespace".to_string(),
396            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Bool)),
397        );
398        functions.insert(
399            "string_to_int".to_string(),
400            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
401        );
402
403        // File I/O functions
404        functions.insert(
405            "file_open".to_string(),
406            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
407        );
408        functions.insert(
409            "file_read_all".to_string(),
410            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::String)),
411        );
412        functions.insert(
413            "file_read_line".to_string(),
414            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::String)),
415        );
416        functions.insert(
417            "file_write".to_string(),
418            CheckerType::Function(
419                vec![CheckerType::Int, CheckerType::String],
420                Box::new(CheckerType::Bool),
421            ),
422        );
423        functions.insert(
424            "file_close".to_string(),
425            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Bool)),
426        );
427        functions.insert(
428            "file_exists".to_string(),
429            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Bool)),
430        );
431        
432        // Enhanced I/O functions
433        functions.insert(
434            "path_exists".to_string(),
435            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Bool)),
436        );
437        functions.insert(
438            "path_is_file".to_string(),
439            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Bool)),
440        );
441        functions.insert(
442            "path_is_dir".to_string(),
443            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Bool)),
444        );
445        functions.insert(
446            "create_dir".to_string(),
447            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
448        );
449        functions.insert(
450            "create_dir_all".to_string(),
451            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
452        );
453        functions.insert(
454            "remove_file".to_string(),
455            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
456        );
457        functions.insert(
458            "remove_dir".to_string(),
459            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
460        );
461        functions.insert(
462            "remove_dir_all".to_string(),
463            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Int)),
464        );
465        functions.insert(
466            "read_file_to_string".to_string(),
467            CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::String)),
468        );
469        functions.insert(
470            "write_string_to_file".to_string(),
471            CheckerType::Function(vec![CheckerType::String, CheckerType::String], Box::new(CheckerType::Int)),
472        );
473        functions.insert(
474            "file_flush".to_string(),
475            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Int)),
476        );
477        functions.insert(
478            "file_seek".to_string(),
479            CheckerType::Function(vec![CheckerType::Int, CheckerType::Int, CheckerType::Int], Box::new(CheckerType::Int)),
480        );
481        
482        // Enhanced file operations with mode support
483        functions.insert(
484            "file_open_ex".to_string(),
485            CheckerType::Function(vec![CheckerType::String, CheckerType::Int], Box::new(CheckerType::Int)),
486        );
487        functions.insert(
488            "file_close_ex".to_string(),
489            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Int)),
490        );
491        functions.insert(
492            "file_read_ex".to_string(),
493            CheckerType::Function(vec![CheckerType::Int, CheckerType::String, CheckerType::Int], Box::new(CheckerType::Int)),
494        );
495        functions.insert(
496            "file_write_ex".to_string(),
497            CheckerType::Function(vec![CheckerType::Int, CheckerType::String, CheckerType::Int], Box::new(CheckerType::Int)),
498        );
499
500        // String operations
501        functions.insert(
502            "string_concat".to_string(),
503            CheckerType::Function(
504                vec![CheckerType::String, CheckerType::String],
505                Box::new(CheckerType::String),
506            ),
507        );
508        functions.insert(
509            "int_to_string".to_string(),
510            CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::String)),
511        );
512
513        Self {
514            functions,
515            generic_functions: HashMap::new(),
516            instantiations: HashMap::new(),
517            structs: HashMap::new(),
518            generic_structs: HashMap::new(),
519            trait_resolver: TraitResolver::new(),
520            struct_instantiations: HashMap::new(),
521            enums: HashMap::new(),
522            generic_enums: HashMap::new(),
523            type_aliases: HashMap::new(),
524            generic_type_aliases: HashMap::new(),
525            current_function_return: None,
526            symbols: SymbolTable::new(),
527            imported_modules: HashMap::new(),
528            loop_depth: 0,
529            error_helper: TypeErrorHelper::new(),
530            unsafe_depth: 0,
531        }
532    }
533
534    /// Set imported modules for type checking
535    pub fn set_imported_modules(&mut self, modules: HashMap<String, crate::resolver::ModuleInfo>) {
536        self.imported_modules = modules;
537
538        // Process imported functions and add them to our function table
539        for (module_name, module_info) in &self.imported_modules {
540            // For now, process all exported functions from the module
541            for item in &module_info.ast.items {
542                match item {
543                    crate::ast::Item::Function(func) => {
544                        // Only process exported (public) functions
545                        if matches!(func.visibility, crate::ast::Visibility::Public) {
546                            let qualified_name = format!("{}::{}", module_name, func.name);
547
548                            if !func.type_params.is_empty() {
549                                // Generic function
550                                let generic_func = GenericFunction {
551                                    lifetime_params: func.lifetime_params.clone(),
552                                    type_params: func.type_params.clone(),
553                                    params: func
554                                        .params
555                                        .iter()
556                                        .map(|p| (p.name.clone(), p.ty.clone()))
557                                        .collect(),
558                                    return_type: func.return_type.clone(),
559                                    body: func.body.clone(),
560                                };
561                                self.generic_functions
562                                    .insert(func.name.clone(), generic_func);
563                            } else {
564                                // Regular function
565                                let param_types: Vec<CheckerType> = func
566                                    .params
567                                    .iter()
568                                    .map(|param| CheckerType::from(&param.ty))
569                                    .collect();
570
571                                let return_type = func
572                                    .return_type
573                                    .as_ref()
574                                    .map(CheckerType::from)
575                                    .unwrap_or(CheckerType::Unit);
576
577                                let func_type =
578                                    CheckerType::Function(param_types, Box::new(return_type));
579
580                                // Add both qualified and unqualified names
581                                // Note: In a full implementation, we'd use a proper module resolution system
582                                self.functions.insert(func.name.clone(), func_type.clone());
583                                self.functions.insert(qualified_name, func_type);
584                            }
585                        }
586                    }
587                    crate::ast::Item::Struct(struct_def) => {
588                        if matches!(struct_def.visibility, crate::ast::Visibility::Public) {
589                            // Convert field types to CheckerType
590                            let fields: Vec<(String, CheckerType)> = struct_def
591                                .fields
592                                .iter()
593                                .map(|(name, ty)| (name.clone(), CheckerType::from(ty)))
594                                .collect();
595
596                            // Add both qualified and unqualified names
597                            self.structs.insert(struct_def.name.clone(), fields.clone());
598                            self.structs
599                                .insert(format!("{}::{}", module_name, struct_def.name), fields);
600                        }
601                    }
602                    crate::ast::Item::Enum(enum_def) => {
603                        // Assume all exported enums are public
604                        {
605                            // Store enum type information
606                            let enum_type = CheckerType::Enum(enum_def.name.clone());
607
608                            // Add variant constructors as functions
609                            for variant in &enum_def.variants {
610                                let variant_name = format!("{}::{}", enum_def.name, variant.name);
611                                let qualified_variant =
612                                    format!("{}::{}", module_name, variant_name);
613
614                                // Create constructor function type based on variant fields
615                                let func_type = match &variant.data {
616                                    crate::ast::EnumVariantData::Unit => {
617                                        // Unit variant: no parameters, returns enum type
618                                        CheckerType::Function(vec![], Box::new(enum_type.clone()))
619                                    }
620                                    crate::ast::EnumVariantData::Tuple(types) => {
621                                        // Tuple variant: parameters from tuple fields
622                                        let param_types: Vec<CheckerType> =
623                                            types.iter().map(CheckerType::from).collect();
624                                        CheckerType::Function(
625                                            param_types,
626                                            Box::new(enum_type.clone()),
627                                        )
628                                    }
629                                    crate::ast::EnumVariantData::Struct(fields) => {
630                                        // Named variant: parameters from named fields
631                                        let param_types: Vec<CheckerType> = fields
632                                            .iter()
633                                            .map(|(_, ty)| CheckerType::from(ty))
634                                            .collect();
635                                        CheckerType::Function(
636                                            param_types,
637                                            Box::new(enum_type.clone()),
638                                        )
639                                    }
640                                };
641
642                                // Register variant constructors
643                                self.functions
644                                    .insert(variant_name.clone(), func_type.clone());
645                                self.functions.insert(qualified_variant, func_type);
646                            }
647                        }
648                    }
649                    crate::ast::Item::Trait(trait_def) => {
650                        if matches!(trait_def.visibility, crate::ast::Visibility::Public) {
651                            // Store trait information
652                            // TODO: Implement trait tracking
653                        }
654                    }
655                    crate::ast::Item::Impl(_) => {
656                        // Impl blocks are processed separately
657                    }
658                    crate::ast::Item::TypeAlias(type_alias) => {
659                        if matches!(type_alias.visibility, crate::ast::Visibility::Public) {
660                            // Store type alias information
661                            let qualified_name = format!("{}::{}", module_name, type_alias.name);
662
663                            if !type_alias.type_params.is_empty() {
664                                // Generic type alias
665                                let generic_alias = GenericTypeAlias {
666                                    lifetime_params: type_alias.lifetime_params.clone(),
667                                    type_params: type_alias.type_params.clone(),
668                                    ty: type_alias.ty.clone(),
669                                };
670                                self.generic_type_aliases
671                                    .insert(type_alias.name.clone(), generic_alias.clone());
672                                self.generic_type_aliases
673                                    .insert(qualified_name, generic_alias);
674                            } else {
675                                // Regular type alias
676                                self.type_aliases
677                                    .insert(type_alias.name.clone(), type_alias.ty.clone());
678                                self.type_aliases
679                                    .insert(qualified_name, type_alias.ty.clone());
680                            }
681                        }
682                    }
683                    crate::ast::Item::Macro(_) => {
684                        // Macros are handled during expansion phase, skip here
685                    }
686                }
687            }
688        }
689    }
690
691    /// Type check a program
692    pub fn check(&mut self, program: &Program) -> Result<()> {
693        // First pass: collect all function signatures and struct definitions
694        for item in &program.items {
695            match item {
696                Item::Function(func) => {
697                    if !func.type_params.is_empty() {
698                        // This is a generic function - store it for later instantiation
699                        let generic_func = GenericFunction {
700                            lifetime_params: func.lifetime_params.clone(),
701                            type_params: func.type_params.clone(),
702                            params: func
703                                .params
704                                .iter()
705                                .map(|p| (p.name.clone(), p.ty.clone()))
706                                .collect(),
707                            return_type: func.return_type.clone(),
708                            body: func.body.clone(),
709                        };
710                        self.generic_functions
711                            .insert(func.name.clone(), generic_func);
712                    } else {
713                        // Regular function - process as before
714                        let param_types: Vec<CheckerType> = func
715                            .params
716                            .iter()
717                            .map(|param| self.ast_type_to_checker_type(&param.ty))
718                            .collect();
719
720                        let return_type = func
721                            .return_type
722                            .as_ref()
723                            .map(|t| self.ast_type_to_checker_type(t))
724                            .unwrap_or(CheckerType::Unit);
725
726                        let func_type = CheckerType::Function(param_types, Box::new(return_type));
727                        self.functions.insert(func.name.clone(), func_type);
728                    }
729                }
730                Item::Struct(struct_def) => {
731                    // Check if this is a generic struct
732                    if !struct_def.type_params.is_empty() || !struct_def.lifetime_params.is_empty()
733                    {
734                        // Store as generic struct
735                        let generic_struct = GenericStruct {
736                            lifetime_params: struct_def.lifetime_params.clone(),
737                            type_params: struct_def.type_params.clone(),
738                            fields: struct_def.fields.clone(),
739                        };
740                        self.generic_structs
741                            .insert(struct_def.name.clone(), generic_struct);
742                    } else {
743                        // Convert field types to CheckerType for non-generic structs
744                        let fields: Vec<(String, CheckerType)> = struct_def
745                            .fields
746                            .iter()
747                            .map(|(name, ty)| (name.clone(), CheckerType::from(ty)))
748                            .collect();
749
750                        self.structs.insert(struct_def.name.clone(), fields);
751                    }
752                }
753                Item::Enum(enum_def) => {
754                    // Check if this is a generic enum
755                    if !enum_def.type_params.is_empty() || !enum_def.lifetime_params.is_empty() {
756                        // Store as generic enum
757                        let generic_enum = GenericEnum {
758                            lifetime_params: enum_def.lifetime_params.clone(),
759                            type_params: enum_def.type_params.clone(),
760                            variants: enum_def
761                                .variants
762                                .iter()
763                                .map(|v| (v.name.clone(), v.data.clone()))
764                                .collect(),
765                        };
766                        self.generic_enums
767                            .insert(enum_def.name.clone(), generic_enum);
768                    } else {
769                        // Store enum variants for type checking
770                        let mut variants = Vec::new();
771
772                        for variant in &enum_def.variants {
773                            let variant_fields = match &variant.data {
774                                crate::ast::EnumVariantData::Unit => EnumVariantFields::Unit,
775                                crate::ast::EnumVariantData::Tuple(types) => {
776                                    let field_types: Vec<CheckerType> =
777                                        types.iter().map(CheckerType::from).collect();
778                                    EnumVariantFields::Tuple(field_types)
779                                }
780                                crate::ast::EnumVariantData::Struct(fields) => {
781                                    let named_fields: Vec<(String, CheckerType)> = fields
782                                        .iter()
783                                        .map(|(name, ty)| (name.clone(), CheckerType::from(ty)))
784                                        .collect();
785                                    EnumVariantFields::Named(named_fields)
786                                }
787                            };
788
789                            variants.push(EnumVariant {
790                                name: variant.name.clone(),
791                                fields: variant_fields,
792                            });
793
794                            // Also register variant constructors as functions
795                            let enum_type = CheckerType::Enum(enum_def.name.clone());
796                            let variant_name = format!("{}::{}", enum_def.name, variant.name);
797
798                            let func_type = match &variant.data {
799                                crate::ast::EnumVariantData::Unit => {
800                                    CheckerType::Function(vec![], Box::new(enum_type.clone()))
801                                }
802                                crate::ast::EnumVariantData::Tuple(types) => {
803                                    let param_types: Vec<CheckerType> =
804                                        types.iter().map(CheckerType::from).collect();
805                                    CheckerType::Function(param_types, Box::new(enum_type.clone()))
806                                }
807                                crate::ast::EnumVariantData::Struct(fields) => {
808                                    let param_types: Vec<CheckerType> = fields
809                                        .iter()
810                                        .map(|(_, ty)| CheckerType::from(ty))
811                                        .collect();
812                                    CheckerType::Function(param_types, Box::new(enum_type.clone()))
813                                }
814                            };
815
816                            self.functions.insert(variant_name, func_type);
817                        }
818
819                        self.enums.insert(enum_def.name.clone(), variants);
820                    }
821                }
822                Item::Trait(trait_def) => {
823                    // Register trait with the trait resolver
824                    self.trait_resolver.register_trait(trait_def)?;
825                }
826                Item::TypeAlias(type_alias) => {
827                    // Check if this is a generic type alias
828                    if !type_alias.type_params.is_empty() || !type_alias.lifetime_params.is_empty()
829                    {
830                        // Store as generic type alias
831                        let generic_alias = GenericTypeAlias {
832                            lifetime_params: type_alias.lifetime_params.clone(),
833                            type_params: type_alias.type_params.clone(),
834                            ty: type_alias.ty.clone(),
835                        };
836                        self.generic_type_aliases
837                            .insert(type_alias.name.clone(), generic_alias);
838                    } else {
839                        // Store regular type alias
840                        self.type_aliases
841                            .insert(type_alias.name.clone(), type_alias.ty.clone());
842                    }
843                }
844                Item::Impl(impl_block) => {
845                    // Register impl block with trait resolver
846                    self.trait_resolver.register_impl(impl_block)?;
847
848                    // If this is a trait impl, verify all required methods are implemented
849                    if let Some(Type::Custom(trait_name)) = &impl_block.trait_type {
850                        self.trait_resolver
851                            .check_trait_impl_complete(impl_block, trait_name)?;
852                    }
853
854                    // Register methods from impl blocks
855                    for method in &impl_block.methods {
856                        // Create qualified method name
857                        let method_name = if let Some(_trait_type) = &impl_block.trait_type {
858                            // Trait implementation method
859                            format!("{}::{}", impl_block.for_type, method.name)
860                        } else {
861                            // Inherent method
862                            format!("{}::{}", impl_block.for_type, method.name)
863                        };
864
865                        if !method.type_params.is_empty() {
866                            // Generic method - store for later instantiation
867                            let generic_func = GenericFunction {
868                                lifetime_params: method.lifetime_params.clone(),
869                                type_params: method.type_params.clone(),
870                                params: method
871                                    .params
872                                    .iter()
873                                    .map(|p| (p.name.clone(), p.ty.clone()))
874                                    .collect(),
875                                return_type: method.return_type.clone(),
876                                body: method.body.clone(),
877                            };
878                            self.generic_functions.insert(method_name, generic_func);
879                        } else {
880                            // Regular method
881                            let param_types: Vec<CheckerType> = method
882                                .params
883                                .iter()
884                                .map(|param| CheckerType::from(&param.ty))
885                                .collect();
886
887                            let return_type = method
888                                .return_type
889                                .as_ref()
890                                .map(CheckerType::from)
891                                .unwrap_or(CheckerType::Unit);
892
893                            let func_type =
894                                CheckerType::Function(param_types, Box::new(return_type));
895                            self.functions.insert(method_name, func_type);
896                        }
897                    }
898                }
899                Item::Macro(_) => {
900                    // Macros are handled during expansion phase, skip here
901                }
902            }
903        }
904
905        // Check for main function
906        if !self.functions.contains_key("main") {
907            return Err(TypeErrorHelper::missing_main());
908        }
909
910        // Second pass: type check function bodies
911        for item in &program.items {
912            match item {
913                Item::Function(func) => {
914                    self.check_function(func)?;
915                }
916                Item::Struct(_) => {
917                    // Structs are already processed in the first pass
918                }
919                Item::Enum(_) => {
920                    // Enums are already processed in the first pass
921                }
922                Item::Trait(_) => {
923                    // Traits are already processed in the first pass
924                    // TODO: Type check trait methods with bodies
925                }
926                Item::TypeAlias(_) => {
927                    // Type aliases are already processed in the first pass
928                    // No body to check
929                }
930                Item::Impl(impl_block) => {
931                    // Type check impl block methods
932                    for method in &impl_block.methods {
933                        self.check_function(method)?;
934                    }
935                }
936                Item::Macro(_) => {
937                    // Macros are handled during expansion phase, skip here
938                }
939            }
940        }
941
942        Ok(())
943    }
944
945    /// Convert AST type to CheckerType considering context (struct vs enum)
946    fn ast_type_to_checker_type(&self, ast_type: &crate::ast::Type) -> CheckerType {
947        match ast_type {
948            crate::ast::Type::Custom(name) => {
949                // First check if it's a type alias
950                if let Some(aliased_type) = self.type_aliases.get(name) {
951                    // Recursively resolve the aliased type
952                    return self.ast_type_to_checker_type(aliased_type);
953                }
954
955                // Check if it's an enum
956                if self.enums.contains_key(name) {
957                    CheckerType::Enum(name.clone())
958                } else {
959                    CheckerType::Struct(name.clone())
960                }
961            }
962            crate::ast::Type::Generic { name, args } => {
963                // First check if it's a generic type alias
964                if let Some(generic_alias) = self.generic_type_aliases.get(name) {
965                    // We have a generic type alias, substitute the type parameters
966                    if args.len() != generic_alias.type_params.len() {
967                        // For now, just return the generic type without substitution
968                        // TODO: Proper error handling for wrong number of type arguments
969                        let checker_args: Vec<GenericArgValue> = args
970                            .iter()
971                            .map(|arg| match arg {
972                                GenericArg::Type(t) => {
973                                    GenericArgValue::Type(self.ast_type_to_checker_type(t))
974                                }
975                                GenericArg::Const(c) => GenericArgValue::Const(match c {
976                                    ConstValue::Integer(n) => ConstValueResolved::Integer(*n),
977                                    ConstValue::ConstParam(name) => {
978                                        ConstValueResolved::ConstParam(name.clone())
979                                    }
980                                }),
981                            })
982                            .collect();
983                        return CheckerType::Generic {
984                            name: name.clone(),
985                            args: checker_args,
986                        };
987                    }
988
989                    // Create a substitution map for type parameters only
990                    let mut substitutions = std::collections::HashMap::new();
991                    let type_args: Vec<crate::ast::Type> = args
992                        .iter()
993                        .filter_map(|arg| match arg {
994                            GenericArg::Type(t) => Some(t.clone()),
995                            GenericArg::Const(_) => None, // TODO: handle const generics in aliases
996                        })
997                        .collect();
998
999                    for (param, arg) in generic_alias.type_params.iter().zip(type_args.iter()) {
1000                        substitutions.insert(param.clone(), arg.clone());
1001                    }
1002
1003                    // Substitute type parameters in the aliased type
1004                    let substituted_type =
1005                        self.substitute_type_params_map(&generic_alias.ty, &substitutions);
1006                    return self.ast_type_to_checker_type(&substituted_type);
1007                }
1008
1009                // Not a type alias, convert generic types normally
1010                let checker_args: Vec<GenericArgValue> = args
1011                    .iter()
1012                    .map(|arg| match arg {
1013                        GenericArg::Type(t) => {
1014                            GenericArgValue::Type(self.ast_type_to_checker_type(t))
1015                        }
1016                        GenericArg::Const(c) => GenericArgValue::Const(match c {
1017                            ConstValue::Integer(n) => ConstValueResolved::Integer(*n),
1018                            ConstValue::ConstParam(name) => {
1019                                ConstValueResolved::ConstParam(name.clone())
1020                            }
1021                        }),
1022                    })
1023                    .collect();
1024
1025                CheckerType::Generic {
1026                    name: name.clone(),
1027                    args: checker_args,
1028                }
1029            }
1030            _ => CheckerType::from(ast_type),
1031        }
1032    }
1033
1034    /// Type check a function
1035    fn check_function(&mut self, func: &Function) -> Result<()> {
1036        // Skip generic functions - they'll be checked when instantiated
1037        if !func.type_params.is_empty() {
1038            return Ok(());
1039        }
1040
1041        // Enter function scope
1042        self.symbols.enter_scope();
1043
1044        // Add function parameters to symbol table
1045        for param in &func.params {
1046            let checker_type = self.ast_type_to_checker_type(&param.ty);
1047            self.symbols
1048                .define(param.name.clone(), checker_type, param.mutable)?;
1049        }
1050
1051        // Set current function return type
1052        let base_return_type = func
1053            .return_type
1054            .as_ref()
1055            .map(|t| self.ast_type_to_checker_type(t))
1056            .unwrap_or(CheckerType::Unit);
1057
1058        // If function is async, wrap return type in Future
1059        let return_type = if func.is_async {
1060            CheckerType::Generic {
1061                name: "Future".to_string(),
1062                args: vec![GenericArgValue::Type(base_return_type)],
1063            }
1064        } else {
1065            base_return_type
1066        };
1067
1068        self.current_function_return = Some(return_type);
1069
1070        // Type check each statement in the body
1071        for stmt in &func.body {
1072            self.check_statement(stmt)?;
1073        }
1074
1075        // Exit function scope
1076        self.symbols.exit_scope();
1077        self.current_function_return = None;
1078        Ok(())
1079    }
1080
1081    /// Type check a statement
1082    fn check_statement(&mut self, stmt: &Stmt) -> Result<()> {
1083        match stmt {
1084            Stmt::Expr(expr) => {
1085                self.check_expression(expr)?;
1086                Ok(())
1087            }
1088            Stmt::Return(None) => {
1089                // Returning nothing is Unit type
1090                if self.current_function_return != Some(CheckerType::Unit) {
1091                    return Err(CompileError::TypeMismatch {
1092                        expected: "()".to_string(),
1093                        found: "return value".to_string(),
1094                        span: None,
1095                    });
1096                }
1097                Ok(())
1098            }
1099            Stmt::Return(Some(expr)) => {
1100                let expr_type = self.check_expression(expr)?;
1101                if let Some(expected) = &self.current_function_return {
1102                    if expr_type != *expected {
1103                        return Err(CompileError::TypeMismatch {
1104                            expected: expected.to_string(),
1105                            found: expr_type.to_string(),
1106                            span: None,
1107                        });
1108                    }
1109                }
1110                Ok(())
1111            }
1112            Stmt::Let {
1113                name,
1114                ty,
1115                value,
1116                mutable,
1117                ..
1118            } => {
1119                // Type check the value expression
1120                let value_type = self.check_expression(value)?;
1121
1122                // If type annotation is provided, check that it matches
1123                if let Some(annotated_type) = ty {
1124                    let expected_type = self.ast_type_to_checker_type(annotated_type);
1125                    if value_type != expected_type {
1126                        return Err(self.error_helper.type_mismatch(
1127                            &expected_type.to_string(),
1128                            &value_type.to_string(),
1129                            None,
1130                        ));
1131                    }
1132                    // Define variable with annotated type
1133                    self.symbols.define(name.clone(), expected_type, *mutable)?;
1134                } else {
1135                    // Define variable with inferred type
1136                    self.symbols.define(name.clone(), value_type, *mutable)?;
1137                }
1138
1139                Ok(())
1140            }
1141            Stmt::Assign { target, value, .. } => {
1142                match target {
1143                    AssignTarget::Ident(name) => {
1144                        // Look up the variable and clone necessary info
1145                        let (var_type, var_mutable) = {
1146                            match self.symbols.lookup(name) {
1147                                Some(var_info) => (var_info.ty.clone(), var_info.mutable),
1148                                None => {
1149                                    // Update error helper with available variables
1150                                    let available_vars = self.get_available_variables();
1151                                    self.error_helper.update_available(
1152                                        available_vars,
1153                                        vec![],
1154                                        vec![],
1155                                    );
1156                                    return Err(self.error_helper.undefined_variable(name, None));
1157                                }
1158                            }
1159                        };
1160
1161                        // Check if variable is mutable
1162                        if !var_mutable {
1163                            return Err(self.error_helper.immutable_assignment(name));
1164                        }
1165
1166                        // Type check the value expression
1167                        let value_type = self.check_expression(value)?;
1168
1169                        // Check that types match
1170                        if value_type != var_type {
1171                            return Err(self.error_helper.type_mismatch(
1172                                &var_type.to_string(),
1173                                &value_type.to_string(),
1174                                None,
1175                            ));
1176                        }
1177
1178                        Ok(())
1179                    }
1180                    AssignTarget::Index { array, index } => {
1181                        // Type check the array expression
1182                        let array_type = self.check_expression(array)?;
1183
1184                        // Type check the index expression (must be Int)
1185                        let index_type = self.check_expression(index)?;
1186                        if index_type != CheckerType::Int {
1187                            return Err(CompileError::TypeMismatch {
1188                                expected: "Int".to_string(),
1189                                found: index_type.to_string(),
1190                                span: None,
1191                            });
1192                        }
1193
1194                        // Extract element type from array type
1195                        let elem_type = match array_type {
1196                            CheckerType::Array(elem_type, _size) => elem_type.as_ref().clone(),
1197                            _ => {
1198                                return Err(CompileError::Generic(format!(
1199                                    "Cannot index into non-array type: {}",
1200                                    array_type
1201                                )));
1202                            }
1203                        };
1204
1205                        // Type check the value expression
1206                        let value_type = self.check_expression(value)?;
1207
1208                        // Check that types match
1209                        if value_type != elem_type {
1210                            return Err(CompileError::TypeMismatch {
1211                                expected: elem_type.to_string(),
1212                                found: value_type.to_string(),
1213                                span: None,
1214                            });
1215                        }
1216
1217                        Ok(())
1218                    }
1219                    AssignTarget::FieldAccess { object, field } => {
1220                        // Type check the object expression
1221                        let object_type = self.check_expression(object)?;
1222
1223                        let field_type = match &object_type {
1224                            // Handle non-generic structs
1225                            CheckerType::Struct(name) => {
1226                                // Look up the struct fields
1227                                let fields = self.structs.get(name).ok_or_else(|| {
1228                                    CompileError::Generic(format!("Unknown struct type: {}", name))
1229                                })?;
1230
1231                                // Find the field type
1232                                fields
1233                                    .iter()
1234                                    .find(|(fname, _)| fname == field)
1235                                    .map(|(_, ftype)| ftype.clone())
1236                                    .ok_or_else(|| {
1237                                        CompileError::Generic(format!(
1238                                            "Struct '{}' has no field '{}'",
1239                                            name, field
1240                                        ))
1241                                    })?
1242                            }
1243                            // Handle generic struct instances
1244                            CheckerType::Generic { name, args } => {
1245                                // Look up the generic struct definition
1246                                let generic_struct =
1247                                    self.generic_structs.get(name).ok_or_else(|| {
1248                                        CompileError::Generic(format!(
1249                                            "Unknown generic struct type: {}",
1250                                            name
1251                                        ))
1252                                    })?;
1253
1254                                // Find the field's declared type
1255                                let field_type = generic_struct
1256                                    .fields
1257                                    .iter()
1258                                    .find(|(fname, _)| fname == field)
1259                                    .map(|(_, ftype)| ftype)
1260                                    .ok_or_else(|| {
1261                                        CompileError::Generic(format!(
1262                                            "Struct '{}' has no field '{}'",
1263                                            name, field
1264                                        ))
1265                                    })?;
1266
1267                                // Extract type arguments only
1268                                let type_args: Vec<CheckerType> = args
1269                                    .iter()
1270                                    .filter_map(|arg| match arg {
1271                                        GenericArgValue::Type(t) => Some(t.clone()),
1272                                        GenericArgValue::Const(_) => None, // TODO: handle const generics
1273                                    })
1274                                    .collect();
1275
1276                                // Substitute type parameters in the field type
1277                                self.substitute_type_params(
1278                                    field_type,
1279                                    &generic_struct.type_params,
1280                                    &type_args,
1281                                )?
1282                            }
1283                            _ => {
1284                                return Err(CompileError::Generic(format!(
1285                                    "Cannot access field on non-struct type: {}",
1286                                    object_type
1287                                )));
1288                            }
1289                        };
1290
1291                        // Type check the value expression
1292                        let value_type = self.check_expression(value)?;
1293
1294                        // Check that types match
1295                        if value_type != field_type {
1296                            return Err(CompileError::TypeMismatch {
1297                                expected: field_type.to_string(),
1298                                found: value_type.to_string(),
1299                                span: None,
1300                            });
1301                        }
1302
1303                        Ok(())
1304                    }
1305                    AssignTarget::Deref { expr } => {
1306                        // Type check the expression being dereferenced
1307                        let _ptr_type = self.check_expression(expr)?;
1308                        // For now, we don't have proper reference types, so just check the value
1309                        let _value_type = self.check_expression(value)?;
1310                        // TODO: Check that ptr_type is actually a reference to value_type
1311                        Ok(())
1312                    }
1313                }
1314            }
1315            Stmt::If {
1316                condition,
1317                then_branch,
1318                else_branch,
1319                ..
1320            } => {
1321                // Type check the condition - must be Bool
1322                let cond_type = self.check_expression(condition)?;
1323                if cond_type != CheckerType::Bool {
1324                    return Err(CompileError::TypeMismatch {
1325                        expected: "Bool".to_string(),
1326                        found: cond_type.to_string(),
1327                        span: None,
1328                    });
1329                }
1330
1331                // Type check then branch in new scope
1332                self.symbols.enter_scope();
1333                for stmt in then_branch {
1334                    self.check_statement(stmt)?;
1335                }
1336                self.symbols.exit_scope();
1337
1338                // Type check else branch in new scope if it exists
1339                if let Some(else_stmts) = else_branch {
1340                    self.symbols.enter_scope();
1341                    for stmt in else_stmts {
1342                        self.check_statement(stmt)?;
1343                    }
1344                    self.symbols.exit_scope();
1345                }
1346
1347                Ok(())
1348            }
1349            Stmt::While {
1350                condition, body, ..
1351            } => {
1352                // Type check the condition - must be Bool
1353                let cond_type = self.check_expression(condition)?;
1354                if cond_type != CheckerType::Bool {
1355                    return Err(CompileError::TypeMismatch {
1356                        expected: "Bool".to_string(),
1357                        found: cond_type.to_string(),
1358                        span: None,
1359                    });
1360                }
1361
1362                // Type check body in new scope with incremented loop depth
1363                self.symbols.enter_scope();
1364                self.loop_depth += 1;
1365                for stmt in body {
1366                    self.check_statement(stmt)?;
1367                }
1368                self.loop_depth -= 1;
1369                self.symbols.exit_scope();
1370
1371                Ok(())
1372            }
1373            Stmt::For {
1374                var, iter, body, ..
1375            } => {
1376                // Type check the iterator expression
1377                let iter_type = self.check_expression(iter)?;
1378
1379                // Extract element type from array
1380                let elem_type = match iter_type {
1381                    CheckerType::Array(elem_type, _size) => elem_type.as_ref().clone(),
1382                    _ => {
1383                        return Err(CompileError::Generic(format!(
1384                            "For loop requires an array, found {}",
1385                            iter_type
1386                        )));
1387                    }
1388                };
1389
1390                // Enter new scope for loop body
1391                self.symbols.enter_scope();
1392                self.loop_depth += 1;
1393
1394                // Define loop variable with element type
1395                self.symbols.define(var.clone(), elem_type, false)?;
1396
1397                // Type check body
1398                for stmt in body {
1399                    self.check_statement(stmt)?;
1400                }
1401
1402                self.loop_depth -= 1;
1403                self.symbols.exit_scope();
1404
1405                Ok(())
1406            }
1407            Stmt::Break { .. } | Stmt::Continue { .. } => {
1408                // Check that we're inside a loop
1409                if self.loop_depth == 0 {
1410                    let keyword = if matches!(stmt, Stmt::Break { .. }) {
1411                        "break"
1412                    } else {
1413                        "continue"
1414                    };
1415                    return Err(self.error_helper.control_flow_outside_loop(keyword));
1416                }
1417                Ok(())
1418            }
1419            Stmt::Match {
1420                expr, arms, span, ..
1421            } => {
1422                // Type check the match expression
1423                let expr_type = self.check_expression(expr)?;
1424
1425                // For each arm, check the pattern matches the expression type
1426                // and type check the body
1427                for arm in arms {
1428                    // Check pattern compatibility with expression type
1429                    self.check_pattern(&arm.pattern, &expr_type)?;
1430
1431                    // Type check arm body in new scope
1432                    self.symbols.enter_scope();
1433
1434                    // Bind pattern variables if any
1435                    self.bind_pattern_variables(&arm.pattern, &expr_type)?;
1436
1437                    for stmt in &arm.body {
1438                        self.check_statement(stmt)?;
1439                    }
1440
1441                    self.symbols.exit_scope();
1442                }
1443
1444                // Pattern exhaustiveness checking
1445                if let CheckerType::Enum(enum_name) = &expr_type {
1446                    // Build enum info for exhaustiveness checker
1447                    let mut enum_infos = HashMap::new();
1448                    for (name, variants) in &self.enums {
1449                        let variant_infos: Vec<VariantInfo> = variants
1450                            .iter()
1451                            .map(|v| {
1452                                let arity = match &v.fields {
1453                                    EnumVariantFields::Unit => 0,
1454                                    EnumVariantFields::Tuple(types) => types.len(),
1455                                    EnumVariantFields::Named(fields) => fields.len(),
1456                                };
1457                                VariantInfo {
1458                                    name: v.name.clone(),
1459                                    arity,
1460                                }
1461                            })
1462                            .collect();
1463
1464                        enum_infos.insert(
1465                            name.clone(),
1466                            EnumInfo {
1467                                name: name.clone(),
1468                                variants: variant_infos,
1469                            },
1470                        );
1471                    }
1472
1473                    let exhaustiveness_checker = ExhaustivenessChecker::new(enum_infos);
1474                    let patterns: Vec<Pattern> =
1475                        arms.iter().map(|arm| arm.pattern.clone()).collect();
1476                    exhaustiveness_checker.check_match(enum_name, &patterns, *span)?;
1477                }
1478
1479                Ok(())
1480            }
1481            Stmt::Unsafe { body, .. } => {
1482                // Enter unsafe context
1483                self.unsafe_depth += 1;
1484
1485                // Type check body in new scope
1486                self.symbols.enter_scope();
1487                for stmt in body {
1488                    self.check_statement(stmt)?;
1489                }
1490                self.symbols.exit_scope();
1491
1492                // Exit unsafe context
1493                self.unsafe_depth -= 1;
1494
1495                Ok(())
1496            }
1497        }
1498    }
1499
1500    /// Substitute type parameters in a type with concrete types
1501    fn substitute_type_params(
1502        &self,
1503        ty: &crate::ast::Type,
1504        type_params: &[String],
1505        concrete_types: &[CheckerType],
1506    ) -> Result<CheckerType> {
1507        match ty {
1508            crate::ast::Type::TypeParam(name) => {
1509                // Find the index of this type parameter
1510                if let Some(idx) = type_params.iter().position(|p| p == name) {
1511                    if idx < concrete_types.len() {
1512                        Ok(concrete_types[idx].clone())
1513                    } else {
1514                        Err(CompileError::Generic(format!(
1515                            "Type parameter {} not found in substitution",
1516                            name
1517                        )))
1518                    }
1519                } else {
1520                    Err(CompileError::Generic(format!(
1521                        "Unknown type parameter: {}",
1522                        name
1523                    )))
1524                }
1525            }
1526            crate::ast::Type::Custom(name) => {
1527                // Check if this custom type is actually a type parameter
1528                if let Some(idx) = type_params.iter().position(|p| p == name) {
1529                    if idx < concrete_types.len() {
1530                        Ok(concrete_types[idx].clone())
1531                    } else {
1532                        Err(CompileError::Generic(format!(
1533                            "Type parameter {} not found in substitution",
1534                            name
1535                        )))
1536                    }
1537                } else {
1538                    // Not a type parameter, just a regular custom type
1539                    Ok(CheckerType::from(ty))
1540                }
1541            }
1542            // For other types, just convert normally
1543            _ => Ok(CheckerType::from(ty)),
1544        }
1545    }
1546
1547    /// Substitute type parameters in a type using a substitution map
1548    #[allow(clippy::only_used_in_recursion)]
1549    fn substitute_type_params_map(
1550        &self,
1551        ty: &crate::ast::Type,
1552        substitutions: &std::collections::HashMap<String, crate::ast::Type>,
1553    ) -> crate::ast::Type {
1554        match ty {
1555            crate::ast::Type::TypeParam(name) | crate::ast::Type::Custom(name) => {
1556                // Check if this is a type parameter that should be substituted
1557                if let Some(replacement) = substitutions.get(name) {
1558                    replacement.clone()
1559                } else {
1560                    ty.clone()
1561                }
1562            }
1563            crate::ast::Type::Generic { name, args } => {
1564                // Recursively substitute in generic type arguments
1565                let new_args: Vec<GenericArg> = args
1566                    .iter()
1567                    .map(|arg| match arg {
1568                        GenericArg::Type(t) => {
1569                            GenericArg::Type(self.substitute_type_params_map(t, substitutions))
1570                        }
1571                        GenericArg::Const(c) => GenericArg::Const(c.clone()), // TODO: substitute const params
1572                    })
1573                    .collect();
1574                crate::ast::Type::Generic {
1575                    name: name.clone(),
1576                    args: new_args,
1577                }
1578            }
1579            crate::ast::Type::Array(elem_type, size) => crate::ast::Type::Array(
1580                Box::new(self.substitute_type_params_map(elem_type, substitutions)),
1581                size.clone(),
1582            ),
1583            crate::ast::Type::Reference {
1584                lifetime,
1585                inner,
1586                mutable,
1587            } => crate::ast::Type::Reference {
1588                lifetime: lifetime.clone(),
1589                inner: Box::new(self.substitute_type_params_map(inner, substitutions)),
1590                mutable: *mutable,
1591            },
1592            // Other types don't contain type parameters
1593            _ => ty.clone(),
1594        }
1595    }
1596
1597    /// Type check an expression and return its type
1598    fn check_expression(&mut self, expr: &Expr) -> Result<CheckerType> {
1599        match expr {
1600            Expr::String(_) => Ok(CheckerType::String),
1601            Expr::Integer(_) => Ok(CheckerType::Int),
1602            Expr::Bool(_) => Ok(CheckerType::Bool),
1603            Expr::Ident(name) => {
1604                // First check if it's a variable
1605                if let Some(var_info) = self.symbols.lookup(name) {
1606                    return Ok(var_info.ty.clone());
1607                }
1608
1609                // Then check if it's a function
1610                match self.functions.get(name) {
1611                    Some(func_type) => Ok(func_type.clone()),
1612                    None => {
1613                        // Try to provide helpful suggestions
1614                        let available_vars = self.get_available_variables();
1615                        let available_funcs = self.get_available_functions();
1616
1617                        // Check if it might be a typo for a variable
1618                        if let Some(suggestion) =
1619                            crate::errors::suggestions::SuggestionEngine::suggest_similar_name(
1620                                name,
1621                                &available_vars,
1622                            )
1623                        {
1624                            return Err(CompileError::Generic(format!(
1625                                "Undefined variable: '{}'. Did you mean '{}'?",
1626                                name, suggestion
1627                            )));
1628                        }
1629
1630                        // Check if it might be a typo for a function
1631                        if let Some(suggestion) =
1632                            crate::errors::suggestions::SuggestionEngine::suggest_similar_name(
1633                                name,
1634                                &available_funcs,
1635                            )
1636                        {
1637                            return Err(CompileError::Generic(format!(
1638                                "Undefined function: '{}'. Did you mean '{}'?",
1639                                name, suggestion
1640                            )));
1641                        }
1642
1643                        // No good suggestion found
1644                        Err(CompileError::Generic(format!(
1645                            "Undefined variable or function: '{}'",
1646                            name
1647                        )))
1648                    }
1649                }
1650            }
1651            Expr::Call { func, args, .. } => {
1652                // Get function name (for v0.1, only direct calls)
1653                let func_name = match func.as_ref() {
1654                    Expr::Ident(name) => name,
1655                    _ => {
1656                        return Err(CompileError::Generic(
1657                            "Indirect function calls not yet supported".to_string(),
1658                        ))
1659                    }
1660                };
1661
1662                // First check if it's a generic function that needs instantiation
1663                if let Some(generic_func) = self.generic_functions.get(func_name).cloned() {
1664                    // Infer type arguments from the call
1665                    let type_args = self.infer_type_args(&generic_func, args)?;
1666
1667                    // Create instantiation key
1668                    let instantiation = FunctionInstantiation {
1669                        name: func_name.clone(),
1670                        type_args: type_args.clone(),
1671                    };
1672
1673                    // Check if we've already instantiated this combination
1674                    if let Some(func_type) = self.instantiations.get(&instantiation) {
1675                        return self.check_call_with_type(func_name, func_type.clone(), args);
1676                    }
1677
1678                    // Need to instantiate the generic function
1679                    let func_type = self.instantiate_generic_function(&generic_func, &type_args)?;
1680                    self.instantiations.insert(instantiation, func_type.clone());
1681
1682                    return self.check_call_with_type(func_name, func_type, args);
1683                }
1684
1685                // Look up regular function type
1686                let func_type = match self.functions.get(func_name) {
1687                    Some(ft) => ft.clone(),
1688                    None => {
1689                        // Update error helper with available functions
1690                        let available_funcs = self.get_available_functions();
1691                        self.error_helper
1692                            .update_available(vec![], available_funcs, vec![]);
1693                        return Err(self.error_helper.undefined_function(func_name, None));
1694                    }
1695                };
1696
1697                // Check function type
1698                match func_type {
1699                    CheckerType::Function(param_types, return_type) => {
1700                        // Check argument count
1701                        if args.len() != param_types.len() {
1702                            return Err(CompileError::ArgumentCountMismatch {
1703                                name: func_name.clone(),
1704                                expected: param_types.len(),
1705                                found: args.len(),
1706                                span: None,
1707                            });
1708                        }
1709
1710                        // Check argument types
1711                        for (arg, expected_type) in args.iter().zip(param_types.iter()) {
1712                            let arg_type = self.check_expression(arg)?;
1713                            if arg_type != *expected_type {
1714                                return Err(CompileError::TypeMismatch {
1715                                    expected: expected_type.to_string(),
1716                                    found: arg_type.to_string(),
1717                                    span: None,
1718                                });
1719                            }
1720                        }
1721
1722                        Ok(return_type.as_ref().clone())
1723                    }
1724                    _ => Err(CompileError::Generic(format!(
1725                        "{} is not a function",
1726                        func_name
1727                    ))),
1728                }
1729            }
1730            Expr::Binary {
1731                op, left, right, ..
1732            } => {
1733                let left_type = self.check_expression(left)?;
1734                let right_type = self.check_expression(right)?;
1735
1736                match op {
1737                    BinOp::Add => {
1738                        // Addition can work for both Int and String (concatenation)
1739                        match (&left_type, &right_type) {
1740                            (CheckerType::Int, CheckerType::Int) => Ok(CheckerType::Int),
1741                            (CheckerType::String, CheckerType::String) => Ok(CheckerType::String),
1742                            _ => {
1743                                // For Add, we expect both operands to have the same type
1744                                if left_type == CheckerType::String {
1745                                    Err(CompileError::TypeMismatch {
1746                                        expected: "String".to_string(),
1747                                        found: right_type.to_string(),
1748                                        span: None,
1749                                    })
1750                                } else if left_type == CheckerType::Int {
1751                                    Err(CompileError::TypeMismatch {
1752                                        expected: "Int".to_string(),
1753                                        found: right_type.to_string(),
1754                                        span: None,
1755                                    })
1756                                } else {
1757                                    Err(CompileError::TypeMismatch {
1758                                        expected: "Int or String".to_string(),
1759                                        found: left_type.to_string(),
1760                                        span: None,
1761                                    })
1762                                }
1763                            }
1764                        }
1765                    }
1766                    BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod => {
1767                        // Other arithmetic operations require both operands to be Int
1768                        if left_type != CheckerType::Int {
1769                            return Err(CompileError::TypeMismatch {
1770                                expected: "Int".to_string(),
1771                                found: left_type.to_string(),
1772                                span: None,
1773                            });
1774                        }
1775                        if right_type != CheckerType::Int {
1776                            return Err(CompileError::TypeMismatch {
1777                                expected: "Int".to_string(),
1778                                found: right_type.to_string(),
1779                                span: None,
1780                            });
1781                        }
1782                        Ok(CheckerType::Int)
1783                    }
1784                    BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge => {
1785                        // Comparison operations require same types
1786                        if left_type != right_type {
1787                            return Err(CompileError::TypeMismatch {
1788                                expected: left_type.to_string(),
1789                                found: right_type.to_string(),
1790                                span: None,
1791                            });
1792                        }
1793                        // Comparison operations return Bool
1794                        Ok(CheckerType::Bool)
1795                    }
1796                    BinOp::And | BinOp::Or => {
1797                        // Logical operations require both operands to be Bool
1798                        if left_type != CheckerType::Bool {
1799                            return Err(CompileError::TypeMismatch {
1800                                expected: "Bool".to_string(),
1801                                found: left_type.to_string(),
1802                                span: None,
1803                            });
1804                        }
1805                        if right_type != CheckerType::Bool {
1806                            return Err(CompileError::TypeMismatch {
1807                                expected: "Bool".to_string(),
1808                                found: right_type.to_string(),
1809                                span: None,
1810                            });
1811                        }
1812                        Ok(CheckerType::Bool)
1813                    }
1814                }
1815            }
1816            Expr::ArrayLiteral { elements, .. } => {
1817                if elements.is_empty() {
1818                    return Err(CompileError::Generic(
1819                        "Empty array literals are not supported (cannot infer type)".to_string(),
1820                    ));
1821                }
1822
1823                // Type check first element
1824                let elem_type = self.check_expression(&elements[0])?;
1825
1826                // Check that all elements have the same type
1827                for elem in &elements[1..] {
1828                    let elem_expr_type = self.check_expression(elem)?;
1829                    if elem_expr_type != elem_type {
1830                        return Err(CompileError::TypeMismatch {
1831                            expected: elem_type.to_string(),
1832                            found: elem_expr_type.to_string(),
1833                            span: None,
1834                        });
1835                    }
1836                }
1837
1838                Ok(CheckerType::Array(
1839                    Box::new(elem_type),
1840                    ArraySizeValue::Literal(elements.len()),
1841                ))
1842            }
1843            Expr::ArrayRepeat { value, count, .. } => {
1844                // Type check the value
1845                let elem_type = self.check_expression(value)?;
1846
1847                // Type check the count - must be an integer literal
1848                match count.as_ref() {
1849                    Expr::Integer(n) => {
1850                        if *n < 0 {
1851                            return Err(CompileError::Generic(
1852                                "Array size must be non-negative".to_string(),
1853                            ));
1854                        }
1855                        Ok(CheckerType::Array(
1856                            Box::new(elem_type),
1857                            ArraySizeValue::Literal(*n as usize),
1858                        ))
1859                    }
1860                    _ => Err(CompileError::Generic(
1861                        "Array repeat count must be an integer literal".to_string(),
1862                    )),
1863                }
1864            }
1865            Expr::Index { array, index, .. } => {
1866                // Type check the array expression
1867                let array_type = self.check_expression(array)?;
1868
1869                // Type check the index expression (must be Int)
1870                let index_type = self.check_expression(index)?;
1871                if index_type != CheckerType::Int {
1872                    return Err(CompileError::TypeMismatch {
1873                        expected: "Int".to_string(),
1874                        found: index_type.to_string(),
1875                        span: None,
1876                    });
1877                }
1878
1879                // Extract element type from array type
1880                match array_type {
1881                    CheckerType::Array(elem_type, _size) => Ok(elem_type.as_ref().clone()),
1882                    _ => Err(CompileError::Generic(format!(
1883                        "Cannot index into non-array type: {}",
1884                        array_type
1885                    ))),
1886                }
1887            }
1888            Expr::StructLiteral { name, fields, .. } => {
1889                // First check if this is a generic struct
1890                if let Some(generic_struct) = self.generic_structs.get(name).cloned() {
1891                    // For generic structs, we need to infer type parameters from field values
1892                    let mut type_substitutions: HashMap<String, CheckerType> = HashMap::new();
1893
1894                    // First pass: check that all provided fields are valid
1895                    for (field_name, _) in fields {
1896                        // Find the field's declared type in the generic struct
1897                        generic_struct
1898                            .fields
1899                            .iter()
1900                            .find(|(fname, _)| fname == field_name)
1901                            .ok_or_else(|| {
1902                                CompileError::Generic(format!(
1903                                    "Unknown field '{}' for struct '{}'",
1904                                    field_name, name
1905                                ))
1906                            })?;
1907                    }
1908
1909                    // Second pass: collect type constraints from field values
1910                    for (field_name, field_expr) in fields {
1911                        // Find the field's declared type in the generic struct
1912                        let field_type = generic_struct
1913                            .fields
1914                            .iter()
1915                            .find(|(fname, _)| fname == field_name)
1916                            .map(|(_, ftype)| ftype)
1917                            .unwrap(); // Safe because we checked in first pass
1918
1919                        // Type check the field expression
1920                        let provided_type = self.check_expression(field_expr)?;
1921
1922                        // If the field type is a type parameter, record the constraint
1923                        if let crate::ast::Type::TypeParam(param_name) = field_type {
1924                            if generic_struct.type_params.contains(param_name) {
1925                                // Check if we already have a constraint for this type parameter
1926                                if let Some(existing_type) = type_substitutions.get(param_name) {
1927                                    if *existing_type != provided_type {
1928                                        return Err(CompileError::Generic(format!(
1929                                            "Conflicting type constraints for type parameter '{}': {} vs {}",
1930                                            param_name, existing_type, provided_type
1931                                        )));
1932                                    }
1933                                } else {
1934                                    type_substitutions.insert(param_name.clone(), provided_type);
1935                                }
1936                            }
1937                        } else if let crate::ast::Type::Custom(type_name) = field_type {
1938                            // Check if it's a type parameter referenced as Custom type
1939                            if generic_struct.type_params.contains(type_name) {
1940                                if let Some(existing_type) = type_substitutions.get(type_name) {
1941                                    if *existing_type != provided_type {
1942                                        return Err(CompileError::Generic(format!(
1943                                            "Conflicting type constraints for type parameter '{}': {} vs {}",
1944                                            type_name, existing_type, provided_type
1945                                        )));
1946                                    }
1947                                } else {
1948                                    type_substitutions.insert(type_name.clone(), provided_type);
1949                                }
1950                            }
1951                        }
1952                        // TODO: Handle nested generic types like Box<T> where T needs to be inferred
1953                    }
1954
1955                    // Check that all type parameters have been inferred
1956                    let mut inferred_args = Vec::new();
1957                    for type_param in &generic_struct.type_params {
1958                        match type_substitutions.get(type_param) {
1959                            Some(inferred_type) => {
1960                                inferred_args.push(inferred_type.clone());
1961                            }
1962                            None => {
1963                                return Err(CompileError::Generic(format!(
1964                                    "Could not infer type parameter '{}' for struct '{}'",
1965                                    type_param, name
1966                                )));
1967                            }
1968                        }
1969                    }
1970
1971                    // Check that all required fields are provided
1972                    for (field_name, field_type) in &generic_struct.fields {
1973                        let provided_expr = fields
1974                            .iter()
1975                            .find(|(fname, _)| fname == field_name)
1976                            .map(|(_, expr)| expr)
1977                            .ok_or_else(|| {
1978                                CompileError::Generic(format!(
1979                                    "Missing field '{}' in struct literal",
1980                                    field_name
1981                                ))
1982                            })?;
1983
1984                        // Substitute type parameters in the field type
1985                        let concrete_checker_type = self.substitute_type_params(
1986                            field_type,
1987                            &generic_struct.type_params,
1988                            &inferred_args,
1989                        )?;
1990
1991                        // Type check the field with the concrete type
1992                        let provided_type = self.check_expression(provided_expr)?;
1993                        if provided_type != concrete_checker_type {
1994                            return Err(CompileError::TypeMismatch {
1995                                expected: concrete_checker_type.to_string(),
1996                                found: provided_type.to_string(),
1997                                span: None,
1998                            });
1999                        }
2000                    }
2001
2002                    // Track this instantiation for code generation
2003                    let type_arg_strings: Vec<String> = inferred_args
2004                        .iter()
2005                        .map(|ct| {
2006                            match ct {
2007                                CheckerType::Int => "i64".to_string(),
2008                                CheckerType::Bool => "bool".to_string(),
2009                                CheckerType::String => "String".to_string(),
2010                                CheckerType::Struct(name) => name.clone(),
2011                                CheckerType::Generic { name, args } => {
2012                                    // Handle nested generics like Box<Box<Int>>
2013                                    let arg_strs: Vec<String> = args
2014                                        .iter()
2015                                        .map(|a| match a {
2016                                            GenericArgValue::Type(t) => match t {
2017                                                CheckerType::Int => "i64".to_string(),
2018                                                CheckerType::Bool => "bool".to_string(),
2019                                                CheckerType::String => "String".to_string(),
2020                                                CheckerType::Struct(n) => n.clone(),
2021                                                _ => "Unknown".to_string(),
2022                                            },
2023                                            GenericArgValue::Const(c) => match c {
2024                                                ConstValueResolved::Integer(n) => n.to_string(),
2025                                                ConstValueResolved::ConstParam(name) => {
2026                                                    name.clone()
2027                                                }
2028                                            },
2029                                        })
2030                                        .collect();
2031                                    format!("{}<{}>", name, arg_strs.join(", "))
2032                                }
2033                                _ => "Unknown".to_string(),
2034                            }
2035                        })
2036                        .collect();
2037
2038                    let instantiation = StructInstantiation {
2039                        name: name.clone(),
2040                        type_args: type_arg_strings,
2041                    };
2042
2043                    let instantiated_type = CheckerType::Generic {
2044                        name: name.clone(),
2045                        args: inferred_args
2046                            .iter()
2047                            .map(|t| GenericArgValue::Type(t.clone()))
2048                            .collect(),
2049                    };
2050
2051                    self.struct_instantiations
2052                        .insert(instantiation, instantiated_type.clone());
2053
2054                    // Return the generic struct type with inferred type arguments
2055                    return Ok(instantiated_type);
2056                }
2057
2058                // Look up the non-generic struct definition
2059                let struct_fields = self
2060                    .structs
2061                    .get(name)
2062                    .ok_or_else(|| CompileError::Generic(format!("Unknown struct type: {}", name)))?
2063                    .clone();
2064
2065                // Check that all fields are provided and have correct types
2066                for (field_name, field_type) in &struct_fields {
2067                    let provided_expr = fields
2068                        .iter()
2069                        .find(|(fname, _)| fname == field_name)
2070                        .map(|(_, expr)| expr)
2071                        .ok_or_else(|| {
2072                            CompileError::Generic(format!(
2073                                "Missing field '{}' in struct literal",
2074                                field_name
2075                            ))
2076                        })?;
2077
2078                    let provided_type = self.check_expression(provided_expr)?;
2079                    if provided_type != *field_type {
2080                        return Err(CompileError::TypeMismatch {
2081                            expected: field_type.to_string(),
2082                            found: provided_type.to_string(),
2083                            span: None,
2084                        });
2085                    }
2086                }
2087
2088                // Check that no extra fields are provided
2089                for (provided_name, _) in fields {
2090                    if !struct_fields
2091                        .iter()
2092                        .any(|(fname, _)| fname == provided_name)
2093                    {
2094                        return Err(CompileError::Generic(format!(
2095                            "Unknown field '{}' for struct '{}'",
2096                            provided_name, name
2097                        )));
2098                    }
2099                }
2100
2101                Ok(CheckerType::Struct(name.clone()))
2102            }
2103            Expr::FieldAccess { object, field, .. } => {
2104                // Type check the object expression
2105                let object_type = self.check_expression(object)?;
2106
2107                match &object_type {
2108                    // Handle non-generic structs
2109                    CheckerType::Struct(name) => {
2110                        // Look up the struct fields
2111                        let fields = self.structs.get(name).ok_or_else(|| {
2112                            CompileError::Generic(format!("Unknown struct type: {}", name))
2113                        })?;
2114
2115                        // Find the field type
2116                        let field_type = fields
2117                            .iter()
2118                            .find(|(fname, _)| fname == field)
2119                            .map(|(_, ftype)| ftype.clone())
2120                            .ok_or_else(|| {
2121                                CompileError::Generic(format!(
2122                                    "Struct '{}' has no field '{}'",
2123                                    name, field
2124                                ))
2125                            })?;
2126
2127                        Ok(field_type)
2128                    }
2129                    // Handle generic struct instances
2130                    CheckerType::Generic { name, args } => {
2131                        // Look up the generic struct definition
2132                        let generic_struct = self.generic_structs.get(name).ok_or_else(|| {
2133                            CompileError::Generic(format!("Unknown generic struct type: {}", name))
2134                        })?;
2135
2136                        // Find the field's declared type
2137                        let field_type = generic_struct
2138                            .fields
2139                            .iter()
2140                            .find(|(fname, _)| fname == field)
2141                            .map(|(_, ftype)| ftype)
2142                            .ok_or_else(|| {
2143                                CompileError::Generic(format!(
2144                                    "Struct '{}' has no field '{}'",
2145                                    name, field
2146                                ))
2147                            })?;
2148
2149                        // Extract types from generic args
2150                        let concrete_types: Vec<CheckerType> = args
2151                            .iter()
2152                            .filter_map(|arg| match arg {
2153                                GenericArgValue::Type(t) => Some(t.clone()),
2154                                _ => None,
2155                            })
2156                            .collect();
2157
2158                        // Substitute type parameters in the field type
2159                        let concrete_field_type = self.substitute_type_params(
2160                            field_type,
2161                            &generic_struct.type_params,
2162                            &concrete_types,
2163                        )?;
2164
2165                        Ok(concrete_field_type)
2166                    }
2167                    _ => Err(CompileError::Generic(format!(
2168                        "Cannot access field on non-struct type: {}",
2169                        object_type
2170                    ))),
2171                }
2172            }
2173            Expr::EnumConstructor {
2174                enum_name,
2175                variant,
2176                data,
2177                ..
2178            } => {
2179                // Type check enum constructors
2180                // First check if the enum exists (could be generic or regular)
2181                if let Some(generic_enum) = self.generic_enums.get(enum_name).cloned() {
2182                    // Handle generic enum - infer type parameters from constructor arguments
2183                    let mut inferred_types = Vec::new();
2184
2185                    // Find the variant in the generic enum definition
2186                    let variant_data = generic_enum
2187                        .variants
2188                        .iter()
2189                        .find(|(v_name, _)| v_name == variant)
2190                        .map(|(_, data)| data)
2191                        .ok_or_else(|| {
2192                            CompileError::Generic(format!(
2193                                "Unknown variant {}::{}",
2194                                enum_name, variant
2195                            ))
2196                        })?;
2197
2198                    // Infer type parameters from constructor arguments
2199                    match (variant_data, data.as_ref()) {
2200                        (
2201                            crate::ast::EnumVariantData::Tuple(param_types),
2202                            Some(crate::ast::EnumConstructorData::Tuple(arg_exprs)),
2203                        ) => {
2204                            // For each type parameter in the variant, infer from arguments
2205                            for (param_type, arg_expr) in param_types.iter().zip(arg_exprs) {
2206                                let arg_type = self.check_expression(arg_expr)?;
2207
2208                                // If the parameter type is a type parameter, record the inferred type
2209                                let is_type_param = match param_type {
2210                                    crate::ast::Type::TypeParam(param_name) => Some(param_name),
2211                                    crate::ast::Type::Custom(param_name)
2212                                        if generic_enum.type_params.contains(param_name) =>
2213                                    {
2214                                        Some(param_name)
2215                                    }
2216                                    _ => None,
2217                                };
2218
2219                                if let Some(param_name) = is_type_param {
2220                                    // Find the index of this type parameter
2221                                    if let Some(idx) = generic_enum
2222                                        .type_params
2223                                        .iter()
2224                                        .position(|p| p == param_name)
2225                                    {
2226                                        // Ensure we have enough slots
2227                                        while inferred_types.len() <= idx {
2228                                            inferred_types.push(CheckerType::Unit);
2229                                            // placeholder
2230                                        }
2231                                        inferred_types[idx] = arg_type;
2232                                    }
2233                                }
2234                            }
2235                        }
2236                        _ => {
2237                            // For other cases, we can't infer yet
2238                            // Return a basic enum type for now
2239                        }
2240                    }
2241
2242                    // If we inferred any types, return a generic type
2243                    if !inferred_types.is_empty() {
2244                        return Ok(CheckerType::Generic {
2245                            name: enum_name.clone(),
2246                            args: inferred_types
2247                                .iter()
2248                                .map(|t| GenericArgValue::Type(t.clone()))
2249                                .collect(),
2250                        });
2251                    } else {
2252                        // No type parameters inferred, return basic enum
2253                        return Ok(CheckerType::Enum(enum_name.clone()));
2254                    }
2255                }
2256
2257                if !self.enums.contains_key(enum_name) {
2258                    return Err(CompileError::Generic(format!(
2259                        "Undefined enum type: {}",
2260                        enum_name
2261                    )));
2262                }
2263
2264                // Find the variant
2265                let variant_info = self.enums[enum_name]
2266                    .iter()
2267                    .find(|v| &v.name == variant)
2268                    .cloned()
2269                    .ok_or_else(|| {
2270                        CompileError::Generic(format!("Unknown variant {}::{}", enum_name, variant))
2271                    })?;
2272
2273                // Type check the constructor data based on variant fields
2274                match (&variant_info.fields, data.as_ref()) {
2275                    (EnumVariantFields::Unit, None) => {
2276                        // Unit variant with no data - correct
2277                    }
2278                    (EnumVariantFields::Unit, Some(_)) => {
2279                        // Unit variants shouldn't have constructor data
2280                        return Err(CompileError::Generic(format!(
2281                            "Unit variant {}::{} cannot have constructor data",
2282                            enum_name, variant
2283                        )));
2284                    }
2285                    (
2286                        EnumVariantFields::Tuple(expected_types),
2287                        Some(crate::ast::EnumConstructorData::Tuple(exprs)),
2288                    ) => {
2289                        // Check tuple constructor
2290                        if expected_types.len() != exprs.len() {
2291                            return Err(CompileError::Generic(format!(
2292                                "Wrong number of arguments for {}::{}: expected {}, found {}",
2293                                enum_name,
2294                                variant,
2295                                expected_types.len(),
2296                                exprs.len()
2297                            )));
2298                        }
2299
2300                        // Type check each expression
2301                        for (expected, expr) in expected_types.iter().zip(exprs) {
2302                            let expr_type = self.check_expression(expr)?;
2303                            if &expr_type != expected {
2304                                return Err(CompileError::TypeMismatch {
2305                                    expected: expected.to_string(),
2306                                    found: expr_type.to_string(),
2307                                    span: None,
2308                                });
2309                            }
2310                        }
2311                    }
2312                    (
2313                        EnumVariantFields::Named(expected_fields),
2314                        Some(crate::ast::EnumConstructorData::Struct(field_exprs)),
2315                    ) => {
2316                        // Check named constructor
2317                        if expected_fields.len() != field_exprs.len() {
2318                            return Err(CompileError::Generic(format!(
2319                                "Wrong number of fields for {}::{}: expected {}, found {}",
2320                                enum_name,
2321                                variant,
2322                                expected_fields.len(),
2323                                field_exprs.len()
2324                            )));
2325                        }
2326
2327                        // Type check each field
2328                        for (field_name, expr) in field_exprs {
2329                            let expected_type = expected_fields
2330                                .iter()
2331                                .find(|(name, _)| name == field_name)
2332                                .map(|(_, ty)| ty)
2333                                .ok_or_else(|| {
2334                                    CompileError::Generic(format!(
2335                                        "Unknown field {} in {}::{}",
2336                                        field_name, enum_name, variant
2337                                    ))
2338                                })?;
2339
2340                            let expr_type = self.check_expression(expr)?;
2341                            if &expr_type != expected_type {
2342                                return Err(CompileError::TypeMismatch {
2343                                    expected: expected_type.to_string(),
2344                                    found: expr_type.to_string(),
2345                                    span: None,
2346                                });
2347                            }
2348                        }
2349                    }
2350                    _ => {
2351                        return Err(CompileError::Generic(format!(
2352                            "Mismatched constructor style for {}::{}",
2353                            enum_name, variant
2354                        )));
2355                    }
2356                }
2357
2358                Ok(CheckerType::Enum(enum_name.clone()))
2359            }
2360            Expr::Range { start, end, .. } => {
2361                // Type check start and end expressions
2362                let start_type = self.check_expression(start)?;
2363                let end_type = self.check_expression(end)?;
2364
2365                // Both must be integers
2366                if start_type != CheckerType::Int {
2367                    return Err(CompileError::TypeMismatch {
2368                        expected: "Int".to_string(),
2369                        found: start_type.to_string(),
2370                        span: None,
2371                    });
2372                }
2373                if end_type != CheckerType::Int {
2374                    return Err(CompileError::TypeMismatch {
2375                        expected: "Int".to_string(),
2376                        found: end_type.to_string(),
2377                        span: None,
2378                    });
2379                }
2380
2381                // Range expressions have a special internal type
2382                // For now, we'll treat them as arrays when used in for loops
2383                Ok(CheckerType::Array(
2384                    Box::new(CheckerType::Int),
2385                    ArraySizeValue::Literal(0),
2386                ))
2387            }
2388            Expr::Unary { op, operand, .. } => {
2389                let operand_type = self.check_expression(operand)?;
2390
2391                match op {
2392                    UnaryOp::Neg => {
2393                        // Negation requires operand to be Int
2394                        if operand_type != CheckerType::Int {
2395                            return Err(CompileError::TypeMismatch {
2396                                expected: "Int".to_string(),
2397                                found: operand_type.to_string(),
2398                                span: None,
2399                            });
2400                        }
2401                        Ok(CheckerType::Int)
2402                    }
2403                    UnaryOp::Not => {
2404                        // Logical not requires operand to be Bool
2405                        if operand_type != CheckerType::Bool {
2406                            return Err(CompileError::TypeMismatch {
2407                                expected: "Bool".to_string(),
2408                                found: operand_type.to_string(),
2409                                span: None,
2410                            });
2411                        }
2412                        Ok(CheckerType::Bool)
2413                    }
2414                }
2415            }
2416            Expr::Reference {
2417                mutable: _, expr, ..
2418            } => {
2419                // Type check the inner expression
2420                let inner_type = self.check_expression(expr)?;
2421
2422                // For now, references have the same type as their inner value
2423                // TODO: Proper reference type handling
2424                Ok(inner_type)
2425            }
2426            Expr::Deref { expr, .. } => {
2427                // Type check the expression being dereferenced
2428                let expr_type = self.check_expression(expr)?;
2429
2430                // For now, assume dereference returns the same type
2431                // TODO: Proper reference type handling - should check that expr_type is a reference
2432                Ok(expr_type)
2433            }
2434            Expr::Question { expr, .. } => {
2435                // Type check the expression
2436                let expr_type = self.check_expression(expr)?;
2437
2438                // The expression must be a Result<T, E> type
2439                match &expr_type {
2440                    CheckerType::Generic { name, args } if name == "Result" && args.len() == 2 => {
2441                        // Extract the Ok type (T) and Error type (E) from Result<T, E>
2442                        let ok_type = &args[0];
2443                        let err_type = &args[1];
2444
2445                        // Check that the current function returns a Result type
2446                        if let Some(return_type) = &self.current_function_return {
2447                            match return_type {
2448                                CheckerType::Generic { name: ret_name, args: ret_args }
2449                                    if ret_name == "Result" && ret_args.len() == 2 => {
2450                                    // Check that error types match
2451                                    let ret_err_type = &ret_args[1];
2452                                    if err_type != ret_err_type {
2453                                        let ret_err_str = match ret_err_type {
2454                                            GenericArgValue::Type(t) => self.checker_type_to_string(t),
2455                                            GenericArgValue::Const(c) => match c {
2456                                                ConstValueResolved::Integer(n) => n.to_string(),
2457                                                ConstValueResolved::ConstParam(name) => name.clone(),
2458                                            }
2459                                        };
2460                                        let err_str = match err_type {
2461                                            GenericArgValue::Type(t) => self.checker_type_to_string(t),
2462                                            GenericArgValue::Const(c) => match c {
2463                                                ConstValueResolved::Integer(n) => n.to_string(),
2464                                                ConstValueResolved::ConstParam(name) => name.clone(),
2465                                            }
2466                                        };
2467                                        let ok_str = match ok_type {
2468                                            GenericArgValue::Type(t) => self.checker_type_to_string(t),
2469                                            GenericArgValue::Const(c) => match c {
2470                                                ConstValueResolved::Integer(n) => n.to_string(),
2471                                                ConstValueResolved::ConstParam(name) => name.clone(),
2472                                            }
2473                                        };
2474                                        return Err(CompileError::TypeMismatch {
2475                                            expected: format!("Result<_, {}>", ret_err_str),
2476                                            found: format!("Result<{}, {}>", ok_str, err_str),
2477                                            span: None,
2478                                        });
2479                                    }
2480
2481                                    // Return the Ok type
2482                                    match ok_type {
2483                                        GenericArgValue::Type(t) => Ok(t.clone()),
2484                                        _ => Err(CompileError::Generic("Expected type in Result".to_string()))
2485                                    }
2486                                }
2487                                _ => Err(CompileError::Generic(
2488                                    "The ? operator can only be used in functions that return Result".to_string()
2489                                ))
2490                            }
2491                        } else {
2492                            Err(CompileError::Generic(
2493                                "The ? operator can only be used inside a function".to_string(),
2494                            ))
2495                        }
2496                    }
2497                    CheckerType::Enum(name) if name == "Result" => {
2498                        // Handle non-generic Result (shouldn't happen in practice)
2499                        Err(CompileError::Generic(
2500                            "Result type must have generic parameters".to_string(),
2501                        ))
2502                    }
2503                    _ => Err(CompileError::TypeMismatch {
2504                        expected: "Result<T, E>".to_string(),
2505                        found: expr_type.to_string(),
2506                        span: None,
2507                    }),
2508                }
2509            }
2510            Expr::MacroInvocation { .. } => {
2511                // Macros should have been expanded before type checking
2512                Err(CompileError::Generic(
2513                    "Unexpected macro invocation in type checking - macros should be expanded before this phase".to_string()
2514                ))
2515            }
2516            Expr::Await { expr, .. } => {
2517                // Check that the expression is a Future type
2518                let expr_type = self.check_expression(expr)?;
2519                match &expr_type {
2520                    CheckerType::Generic { name, args } if name == "Future" && args.len() == 1 => {
2521                        // Extract the output type from Future<T>
2522                        if let GenericArgValue::Type(output_type) = &args[0] {
2523                            Ok(output_type.clone())
2524                        } else {
2525                            Err(CompileError::Generic("Invalid Future type".to_string()))
2526                        }
2527                    }
2528                    _ => Err(CompileError::TypeMismatch {
2529                        expected: "Future<T>".to_string(),
2530                        found: self.checker_type_to_string(&expr_type),
2531                        span: None,
2532                    }),
2533                }
2534            }
2535        }
2536    }
2537
2538    /// Check that a pattern is compatible with the given type
2539    fn check_pattern(&self, pattern: &Pattern, expected_type: &CheckerType) -> Result<()> {
2540        match pattern {
2541            Pattern::Wildcard => {
2542                // Wildcard matches any type
2543                Ok(())
2544            }
2545            Pattern::Ident(_) => {
2546                // Identifier pattern matches any type and binds it
2547                Ok(())
2548            }
2549            Pattern::EnumPattern {
2550                enum_name,
2551                variant: _,
2552                data: _,
2553            } => {
2554                // Check that the expected type matches the enum
2555                match expected_type {
2556                    CheckerType::Enum(name) if name == enum_name => Ok(()),
2557                    CheckerType::Generic { name, .. } if name == enum_name => Ok(()),
2558                    _ => Err(CompileError::TypeMismatch {
2559                        expected: format!("enum {}", enum_name),
2560                        found: expected_type.to_string(),
2561                        span: None,
2562                    }),
2563                }
2564            }
2565        }
2566    }
2567
2568    /// Bind variables from patterns to the symbol table
2569    fn bind_pattern_variables(
2570        &mut self,
2571        pattern: &Pattern,
2572        value_type: &CheckerType,
2573    ) -> Result<()> {
2574        match pattern {
2575            Pattern::Wildcard => {
2576                // No bindings
2577                Ok(())
2578            }
2579            Pattern::Ident(name) => {
2580                // Bind the identifier to the value type
2581                self.symbols.define(
2582                    name.clone(),
2583                    value_type.clone(),
2584                    false, // Pattern bindings are immutable by default
2585                )?;
2586                Ok(())
2587            }
2588            Pattern::EnumPattern {
2589                enum_name,
2590                variant,
2591                data,
2592                ..
2593            } => {
2594                // Bind variables from nested patterns
2595                if let Some(pattern_data) = data {
2596                    // Get enum variant info to determine field types
2597
2598                    // Handle both regular and generic enums
2599                    match value_type {
2600                        CheckerType::Enum(expected_enum) if expected_enum == enum_name => {
2601                            // Regular enum - check if it's actually a generic enum
2602                            if self.generic_enums.contains_key(enum_name) {
2603                                // This shouldn't happen - generic enums should have Generic type
2604                                return Err(CompileError::Generic(format!(
2605                                    "Generic enum {} used without type parameters",
2606                                    enum_name
2607                                )));
2608                            }
2609
2610                            // Handle regular enum
2611                            let variants = self
2612                                .enums
2613                                .get(enum_name)
2614                                .ok_or_else(|| {
2615                                    CompileError::Generic(format!(
2616                                        "Undefined enum type: {}",
2617                                        enum_name
2618                                    ))
2619                                })?
2620                                .clone();
2621
2622                            let variant_info = variants
2623                                .iter()
2624                                .find(|v| &v.name == variant)
2625                                .ok_or_else(|| {
2626                                    CompileError::Generic(format!(
2627                                        "Unknown variant {}::{}",
2628                                        enum_name, variant
2629                                    ))
2630                                })?
2631                                .clone();
2632
2633                            match (pattern_data, &variant_info.fields) {
2634                                (
2635                                    PatternData::Tuple(patterns),
2636                                    EnumVariantFields::Tuple(field_types),
2637                                ) => {
2638                                    // Bind each tuple pattern with its corresponding type
2639                                    if patterns.len() != field_types.len() {
2640                                        return Err(CompileError::Generic(format!(
2641                                            "Pattern has wrong number of fields for {}::{}",
2642                                            enum_name, variant
2643                                        )));
2644                                    }
2645
2646                                    for (pattern, field_type) in patterns.iter().zip(field_types) {
2647                                        self.bind_pattern_variables(pattern, field_type)?;
2648                                    }
2649                                }
2650                                (
2651                                    PatternData::Struct(field_patterns),
2652                                    EnumVariantFields::Named(expected_fields),
2653                                ) => {
2654                                    // Bind each struct field pattern with its type
2655                                    for (field_name, pattern) in field_patterns {
2656                                        let field_type = expected_fields
2657                                            .iter()
2658                                            .find(|(name, _)| name == field_name)
2659                                            .map(|(_, ty)| ty)
2660                                            .ok_or_else(|| {
2661                                                CompileError::Generic(format!(
2662                                                    "Unknown field {} in {}::{}",
2663                                                    field_name, enum_name, variant
2664                                                ))
2665                                            })?;
2666
2667                                        self.bind_pattern_variables(pattern, field_type)?;
2668                                    }
2669                                }
2670                                _ => {
2671                                    return Err(CompileError::Generic(format!(
2672                                        "Pattern structure doesn't match variant {}::{}",
2673                                        enum_name, variant
2674                                    )));
2675                                }
2676                            }
2677                        }
2678                        CheckerType::Generic { name, args } if name == enum_name => {
2679                            // Generic enum with type arguments
2680                            if let Some(generic_enum) = self.generic_enums.get(enum_name).cloned() {
2681                                // Find the variant
2682                                let variant_data = generic_enum
2683                                    .variants
2684                                    .iter()
2685                                    .find(|(v_name, _)| v_name == variant)
2686                                    .map(|(_, data)| data)
2687                                    .ok_or_else(|| {
2688                                        CompileError::Generic(format!(
2689                                            "Unknown variant {}::{}",
2690                                            enum_name, variant
2691                                        ))
2692                                    })?;
2693
2694                                // Bind pattern variables based on variant data
2695                                match (pattern_data, variant_data) {
2696                                    (
2697                                        PatternData::Tuple(patterns),
2698                                        crate::ast::EnumVariantData::Tuple(param_types),
2699                                    ) => {
2700                                        if patterns.len() != param_types.len() {
2701                                            return Err(CompileError::Generic(format!(
2702                                                "Pattern has wrong number of fields for {}::{}",
2703                                                enum_name, variant
2704                                            )));
2705                                        }
2706
2707                                        // For each pattern, determine its type by substituting type parameters
2708                                        let type_params = generic_enum.type_params.clone();
2709                                        for (pattern, param_type) in
2710                                            patterns.iter().zip(param_types)
2711                                        {
2712                                            // Extract types from generic args
2713                                            let concrete_types: Vec<CheckerType> = args
2714                                                .iter()
2715                                                .filter_map(|arg| match arg {
2716                                                    GenericArgValue::Type(t) => Some(t.clone()),
2717                                                    _ => None,
2718                                                })
2719                                                .collect();
2720                                            let concrete_type = self.substitute_type_params(
2721                                                param_type,
2722                                                &type_params,
2723                                                &concrete_types,
2724                                            )?;
2725                                            self.bind_pattern_variables(pattern, &concrete_type)?;
2726                                        }
2727                                        return Ok(());
2728                                    }
2729                                    _ => {
2730                                        // TODO: Handle other pattern types
2731                                        return Ok(());
2732                                    }
2733                                }
2734                            } else {
2735                                return Err(CompileError::Generic(format!(
2736                                    "Generic enum {} not found in definitions",
2737                                    enum_name
2738                                )));
2739                            }
2740                        }
2741                        _ => {
2742                            return Err(CompileError::TypeMismatch {
2743                                expected: format!("enum {}", enum_name),
2744                                found: value_type.to_string(),
2745                                span: None,
2746                            });
2747                        }
2748                    }
2749                }
2750                Ok(())
2751            }
2752        }
2753    }
2754
2755    /// Infer type arguments for a generic function call
2756    fn infer_type_args(
2757        &self,
2758        generic_func: &GenericFunction,
2759        args: &[Expr],
2760    ) -> Result<Vec<String>> {
2761        let mut type_map: HashMap<String, String> = HashMap::new();
2762
2763        // Check argument count
2764        if args.len() != generic_func.params.len() {
2765            return Err(CompileError::Generic(format!(
2766                "Function expects {} arguments, got {}",
2767                generic_func.params.len(),
2768                args.len()
2769            )));
2770        }
2771
2772        // Infer types from each argument
2773        for (arg_expr, (_param_name, param_type)) in args.iter().zip(&generic_func.params) {
2774            self.infer_from_expr_and_type(arg_expr, param_type, &mut type_map)?;
2775        }
2776
2777        // Make sure all type parameters were inferred
2778        let mut type_args = Vec::new();
2779        for type_param in &generic_func.type_params {
2780            match type_map.get(type_param) {
2781                Some(concrete_type) => type_args.push(concrete_type.clone()),
2782                None => {
2783                    return Err(CompileError::Generic(format!(
2784                        "Could not infer type parameter '{}' from function arguments",
2785                        type_param
2786                    )));
2787                }
2788            }
2789        }
2790
2791        Ok(type_args)
2792    }
2793
2794    /// Helper to infer type parameters from an expression and expected type
2795    fn infer_from_expr_and_type(
2796        &self,
2797        expr: &Expr,
2798        expected_type: &crate::ast::Type,
2799        type_map: &mut HashMap<String, String>,
2800    ) -> Result<()> {
2801        match expected_type {
2802            crate::ast::Type::TypeParam(param_name) => {
2803                // This is a type parameter - infer its type from the expression
2804                let expr_type = self.infer_expr_type(expr)?;
2805
2806                // Check if we already have a mapping for this type parameter
2807                if let Some(existing_type) = type_map.get(param_name) {
2808                    if existing_type != &expr_type {
2809                        return Err(CompileError::Generic(format!(
2810                            "Type parameter '{}' has conflicting types: '{}' and '{}'",
2811                            param_name, existing_type, expr_type
2812                        )));
2813                    }
2814                } else {
2815                    type_map.insert(param_name.clone(), expr_type);
2816                }
2817                Ok(())
2818            }
2819            crate::ast::Type::Array(elem_type, _size) => {
2820                // For arrays, we need to infer the element type
2821                match expr {
2822                    Expr::ArrayLiteral { elements, .. } => {
2823                        if !elements.is_empty() {
2824                            // Use first element to infer the type parameter
2825                            self.infer_from_expr_and_type(&elements[0], elem_type, type_map)?;
2826                        }
2827                    }
2828                    Expr::ArrayRepeat { value, .. } => {
2829                        // Use the repeated value to infer the type parameter
2830                        self.infer_from_expr_and_type(value, elem_type, type_map)?;
2831                    }
2832                    Expr::Ident(name) => {
2833                        // For identifiers, we need to look up their type and extract element type
2834                        if let Some(var_info) = self.symbols.lookup(name) {
2835                            if let CheckerType::Array(var_elem_type, _) = &var_info.ty {
2836                                // If elem_type is a type parameter, map it
2837                                if let crate::ast::Type::TypeParam(param_name) = elem_type.as_ref()
2838                                {
2839                                    let elem_type_str = self.checker_type_to_string(var_elem_type);
2840                                    type_map.insert(param_name.clone(), elem_type_str);
2841                                }
2842                            }
2843                        }
2844                    }
2845                    _ => {
2846                        // For other expressions, try to infer their type
2847                        if let crate::ast::Type::TypeParam(_) = elem_type.as_ref() {
2848                            self.infer_from_expr_and_type(expr, elem_type, type_map)?;
2849                        }
2850                    }
2851                }
2852                Ok(())
2853            }
2854            _ => {
2855                // Non-generic type - nothing to infer
2856                Ok(())
2857            }
2858        }
2859    }
2860
2861    /// Get a string representation of the expression's type for inference
2862    fn infer_expr_type(&self, expr: &Expr) -> Result<String> {
2863        match expr {
2864            Expr::String(_) => Ok("String".to_string()),
2865            Expr::Integer(_) => Ok("i64".to_string()), // Default to i64
2866            Expr::Bool(_) => Ok("bool".to_string()),
2867            Expr::Ident(name) => {
2868                // Look up variable type
2869                if let Some(var_info) = self.symbols.lookup(name) {
2870                    Ok(self.checker_type_to_string(&var_info.ty))
2871                } else {
2872                    Err(CompileError::Generic(format!("Unknown variable: {}", name)))
2873                }
2874            }
2875            Expr::ArrayLiteral { elements, .. } => {
2876                // Infer array type from elements
2877                if elements.is_empty() {
2878                    return Err(CompileError::Generic(
2879                        "Cannot infer type from empty array".to_string(),
2880                    ));
2881                }
2882
2883                // Get type of first element (assume all elements have same type)
2884                let elem_type_str = self.infer_expr_type(&elements[0])?;
2885                let size = elements.len();
2886                Ok(format!("[{}; {}]", elem_type_str, size))
2887            }
2888            Expr::ArrayRepeat { value, count, .. } => {
2889                // Infer array type from repeated value
2890                let elem_type_str = self.infer_expr_type(value)?;
2891
2892                // Extract count from expression (simplified - assumes integer literal)
2893                let size = match count.as_ref() {
2894                    Expr::Integer(n) => *n as usize,
2895                    _ => {
2896                        return Err(CompileError::Generic(
2897                            "Array size must be a constant integer".to_string(),
2898                        ))
2899                    }
2900                };
2901
2902                Ok(format!("[{}; {}]", elem_type_str, size))
2903            }
2904            _ => {
2905                // For other complex expressions, we'd need full type checking
2906                Err(CompileError::Generic(
2907                    "Cannot infer type from complex expression".to_string(),
2908                ))
2909            }
2910        }
2911    }
2912
2913    /// Convert CheckerType to string for type arguments
2914    #[allow(clippy::only_used_in_recursion)]
2915    fn checker_type_to_string(&self, ty: &CheckerType) -> String {
2916        match ty {
2917            CheckerType::Unit => "()".to_string(),
2918            CheckerType::String => "String".to_string(),
2919            CheckerType::Int => "i64".to_string(),
2920            CheckerType::Bool => "bool".to_string(),
2921            CheckerType::Array(elem, size) => {
2922                format!("[{}; {}]", self.checker_type_to_string(elem), size)
2923            }
2924            CheckerType::Struct(name) => name.clone(),
2925            CheckerType::TypeParam(name) => name.clone(),
2926            CheckerType::Enum(name) => name.clone(),
2927            CheckerType::Function(params, ret) => {
2928                let param_strs: Vec<String> = params
2929                    .iter()
2930                    .map(|p| self.checker_type_to_string(p))
2931                    .collect();
2932                format!(
2933                    "fn({}) -> {}",
2934                    param_strs.join(", "),
2935                    self.checker_type_to_string(ret)
2936                )
2937            }
2938            CheckerType::Generic { name, args } => {
2939                let arg_strs: Vec<String> = args
2940                    .iter()
2941                    .map(|a| match a {
2942                        GenericArgValue::Type(t) => self.checker_type_to_string(t),
2943                        GenericArgValue::Const(c) => match c {
2944                            ConstValueResolved::Integer(n) => n.to_string(),
2945                            ConstValueResolved::ConstParam(name) => name.clone(),
2946                        },
2947                    })
2948                    .collect();
2949                format!("{}<{}>", name, arg_strs.join(", "))
2950            }
2951        }
2952    }
2953
2954    /// Instantiate a generic function with concrete types
2955    fn instantiate_generic_function(
2956        &mut self,
2957        generic_func: &GenericFunction,
2958        type_args: &[String],
2959    ) -> Result<CheckerType> {
2960        // Create a substitution map
2961        let mut subst_map: HashMap<String, String> = HashMap::new();
2962        for (type_param, type_arg) in generic_func.type_params.iter().zip(type_args) {
2963            subst_map.insert(type_param.clone(), type_arg.clone());
2964        }
2965
2966        // Substitute types in parameters
2967        let mut param_types = Vec::new();
2968        for (_param_name, param_type) in &generic_func.params {
2969            let substituted_type = self.substitute_type(param_type, &subst_map)?;
2970            param_types.push(CheckerType::from(&substituted_type));
2971        }
2972
2973        // Substitute return type
2974        let return_type = match &generic_func.return_type {
2975            Some(ret_type) => {
2976                let substituted = self.substitute_type(ret_type, &subst_map)?;
2977                CheckerType::from(&substituted)
2978            }
2979            None => CheckerType::Unit,
2980        };
2981
2982        Ok(CheckerType::Function(param_types, Box::new(return_type)))
2983    }
2984
2985    /// Substitute type parameters in a type
2986    #[allow(clippy::only_used_in_recursion)]
2987    fn substitute_type(
2988        &self,
2989        ty: &crate::ast::Type,
2990        subst_map: &HashMap<String, String>,
2991    ) -> Result<crate::ast::Type> {
2992        match ty {
2993            crate::ast::Type::TypeParam(param_name) => {
2994                match subst_map.get(param_name) {
2995                    Some(concrete_type) => {
2996                        // Convert string back to Type
2997                        match concrete_type.as_str() {
2998                            "()" => Ok(crate::ast::Type::Unit),
2999                            "String" => Ok(crate::ast::Type::String),
3000                            "i64" => Ok(crate::ast::Type::I64),
3001                            "i32" => Ok(crate::ast::Type::I32),
3002                            "u64" => Ok(crate::ast::Type::U64),
3003                            "u32" => Ok(crate::ast::Type::U32),
3004                            "bool" => Ok(crate::ast::Type::Bool),
3005                            _ => Ok(crate::ast::Type::Custom(concrete_type.clone())),
3006                        }
3007                    }
3008                    None => Err(CompileError::Generic(format!(
3009                        "Type parameter '{}' not found in substitution map",
3010                        param_name
3011                    ))),
3012                }
3013            }
3014            crate::ast::Type::Array(elem_type, size) => {
3015                let substituted_elem = self.substitute_type(elem_type, subst_map)?;
3016                Ok(crate::ast::Type::Array(
3017                    Box::new(substituted_elem),
3018                    size.clone(),
3019                ))
3020            }
3021            crate::ast::Type::Reference {
3022                lifetime,
3023                mutable,
3024                inner,
3025            } => {
3026                let substituted_inner = self.substitute_type(inner, subst_map)?;
3027                Ok(crate::ast::Type::Reference {
3028                    lifetime: lifetime.clone(),
3029                    mutable: *mutable,
3030                    inner: Box::new(substituted_inner),
3031                })
3032            }
3033            _ => Ok(ty.clone()),
3034        }
3035    }
3036
3037    /// Check a function call with a known function type
3038    fn check_call_with_type(
3039        &mut self,
3040        func_name: &str,
3041        func_type: CheckerType,
3042        args: &[Expr],
3043    ) -> Result<CheckerType> {
3044        match func_type {
3045            CheckerType::Function(param_types, return_type) => {
3046                // Check argument count
3047                if args.len() != param_types.len() {
3048                    return Err(CompileError::Generic(format!(
3049                        "Function '{}' expects {} arguments, got {}",
3050                        func_name,
3051                        param_types.len(),
3052                        args.len()
3053                    )));
3054                }
3055
3056                // Type check each argument
3057                for (arg, expected_type) in args.iter().zip(&param_types) {
3058                    let arg_type = self.check_expression(arg)?;
3059                    if arg_type != *expected_type {
3060                        return Err(CompileError::TypeMismatch {
3061                            expected: expected_type.to_string(),
3062                            found: arg_type.to_string(),
3063                            span: None,
3064                        });
3065                    }
3066                }
3067
3068                Ok(*return_type)
3069            }
3070            _ => Err(CompileError::Generic(format!(
3071                "'{}' is not a function",
3072                func_name
3073            ))),
3074        }
3075    }
3076
3077    /// Get all generic function instantiations for code generation
3078    pub fn get_instantiations(&self) -> Vec<(String, Vec<String>, GenericFunction)> {
3079        let mut result = Vec::new();
3080
3081        for instantiation in self.instantiations.keys() {
3082            if let Some(generic_func) = self.generic_functions.get(&instantiation.name) {
3083                result.push((
3084                    instantiation.name.clone(),
3085                    instantiation.type_args.clone(),
3086                    generic_func.clone(),
3087                ));
3088            }
3089        }
3090
3091        result
3092    }
3093
3094    /// Get all generic struct instantiations for code generation
3095    pub fn get_struct_instantiations(&self) -> Vec<(String, Vec<String>, GenericStruct)> {
3096        let mut result = Vec::new();
3097
3098        for instantiation in self.struct_instantiations.keys() {
3099            if let Some(generic_struct) = self.generic_structs.get(&instantiation.name) {
3100                result.push((
3101                    instantiation.name.clone(),
3102                    instantiation.type_args.clone(),
3103                    generic_struct.clone(),
3104                ));
3105            }
3106        }
3107
3108        result
3109    }
3110
3111    /// Get all available variable names for suggestions
3112    fn get_available_variables(&self) -> Vec<String> {
3113        let mut vars = Vec::new();
3114        for scope in &self.symbols.scopes {
3115            for var_name in scope.keys() {
3116                vars.push(var_name.clone());
3117            }
3118        }
3119        vars
3120    }
3121
3122    /// Get all available function names for suggestions
3123    fn get_available_functions(&self) -> Vec<String> {
3124        let mut funcs: Vec<String> = self.functions.keys().cloned().collect();
3125        funcs.extend(self.generic_functions.keys().cloned());
3126        funcs
3127    }
3128
3129    /// Get all available type names for suggestions
3130    #[allow(dead_code)]
3131    fn get_available_types(&self) -> Vec<String> {
3132        let mut types = vec!["String".to_string(), "i64".to_string(), "bool".to_string()];
3133        types.extend(self.structs.keys().cloned());
3134        types.extend(self.enums.keys().cloned());
3135        types
3136    }
3137
3138    /// Check if we're currently in an unsafe context
3139    pub fn in_unsafe_context(&self) -> bool {
3140        self.unsafe_depth > 0
3141    }
3142}
3143
3144#[cfg(test)]
3145mod tests {
3146    use super::*;
3147    use crate::lexer::Lexer;
3148    use crate::parser::Parser;
3149
3150    #[test]
3151    fn test_type_check_hello_world() {
3152        let source = r#"
3153        fn main() {
3154            print("Hello, World!");
3155        }
3156        "#;
3157
3158        let mut lexer = Lexer::new(source);
3159        let tokens = lexer.collect_tokens().unwrap();
3160        let mut parser = Parser::new(tokens);
3161        let ast = parser.parse().unwrap();
3162
3163        let mut type_checker = TypeChecker::new();
3164        assert!(type_checker.check(&ast).is_ok());
3165    }
3166
3167    #[test]
3168    fn test_undefined_function() {
3169        let source = r#"
3170        fn main() {
3171            unknown_function();
3172        }
3173        "#;
3174
3175        let mut lexer = Lexer::new(source);
3176        let tokens = lexer.collect_tokens().unwrap();
3177        let mut parser = Parser::new(tokens);
3178        let ast = parser.parse().unwrap();
3179
3180        let mut type_checker = TypeChecker::new();
3181        let result = type_checker.check(&ast);
3182        assert!(result.is_err());
3183    }
3184
3185    #[test]
3186    fn test_let_binding() {
3187        let source = r#"
3188        fn main() {
3189            let x = 42;
3190            let y: i32 = 10;
3191            let message = "Hello";
3192        }
3193        "#;
3194
3195        let mut lexer = Lexer::new(source);
3196        let tokens = lexer.collect_tokens().unwrap();
3197        let mut parser = Parser::new(tokens);
3198        let ast = parser.parse().unwrap();
3199
3200        let mut type_checker = TypeChecker::new();
3201        assert!(type_checker.check(&ast).is_ok());
3202    }
3203
3204    #[test]
3205    fn test_variable_usage() {
3206        let source = r#"
3207        fn main() {
3208            let x = 42;
3209            let y = x;
3210        }
3211        "#;
3212
3213        let mut lexer = Lexer::new(source);
3214        let tokens = lexer.collect_tokens().unwrap();
3215        let mut parser = Parser::new(tokens);
3216        let ast = parser.parse().unwrap();
3217
3218        let mut type_checker = TypeChecker::new();
3219        assert!(type_checker.check(&ast).is_ok());
3220    }
3221
3222    #[test]
3223    fn test_undefined_variable() {
3224        let source = r#"
3225        fn main() {
3226            let x = y;
3227        }
3228        "#;
3229
3230        let mut lexer = Lexer::new(source);
3231        let tokens = lexer.collect_tokens().unwrap();
3232        let mut parser = Parser::new(tokens);
3233        let ast = parser.parse().unwrap();
3234
3235        let mut type_checker = TypeChecker::new();
3236        let result = type_checker.check(&ast);
3237        assert!(result.is_err());
3238    }
3239
3240    #[test]
3241    fn test_binary_operations() {
3242        let source = r#"
3243        fn main() {
3244            let x = 10 + 20;
3245            let y = x - 5;
3246            let z = y * 2;
3247            let w = z / 3;
3248        }
3249        "#;
3250
3251        let mut lexer = Lexer::new(source);
3252        let tokens = lexer.collect_tokens().unwrap();
3253        let mut parser = Parser::new(tokens);
3254        let ast = parser.parse().unwrap();
3255
3256        let mut type_checker = TypeChecker::new();
3257        assert!(type_checker.check(&ast).is_ok());
3258    }
3259
3260    #[test]
3261    fn test_type_mismatch_in_binary() {
3262        let source = r#"
3263        fn main() {
3264            let x = "hello" + 42;
3265        }
3266        "#;
3267
3268        let mut lexer = Lexer::new(source);
3269        let tokens = lexer.collect_tokens().unwrap();
3270        let mut parser = Parser::new(tokens);
3271        let ast = parser.parse().unwrap();
3272
3273        let mut type_checker = TypeChecker::new();
3274        let result = type_checker.check(&ast);
3275        assert!(result.is_err());
3276
3277        if let Err(CompileError::TypeMismatch {
3278            expected,
3279            found,
3280            span: _,
3281            ..
3282        }) = result
3283        {
3284            assert_eq!(expected, "String");
3285            assert_eq!(found, "Int");
3286        }
3287    }
3288
3289    #[test]
3290    fn test_type_annotation_mismatch() {
3291        let source = r#"
3292        fn main() {
3293            let x: i32 = "not an int";
3294        }
3295        "#;
3296
3297        let mut lexer = Lexer::new(source);
3298        let tokens = lexer.collect_tokens().unwrap();
3299        let mut parser = Parser::new(tokens);
3300        let ast = parser.parse().unwrap();
3301
3302        let mut type_checker = TypeChecker::new();
3303        let result = type_checker.check(&ast);
3304        assert!(result.is_err());
3305
3306        if let Err(CompileError::TypeMismatch {
3307            expected,
3308            found,
3309            span: _,
3310            ..
3311        }) = result
3312        {
3313            assert_eq!(expected, "Int");
3314            assert_eq!(found, "String");
3315        }
3316    }
3317
3318    #[test]
3319    fn test_variable_redefinition() {
3320        let source = r#"
3321        fn main() {
3322            let x = 42;
3323            let x = "redefined";
3324        }
3325        "#;
3326
3327        let mut lexer = Lexer::new(source);
3328        let tokens = lexer.collect_tokens().unwrap();
3329        let mut parser = Parser::new(tokens);
3330        let ast = parser.parse().unwrap();
3331
3332        let mut type_checker = TypeChecker::new();
3333        let result = type_checker.check(&ast);
3334        assert!(result.is_err());
3335    }
3336
3337    #[test]
3338    fn test_for_loop_type_checking() {
3339        let source = r#"
3340        fn main() {
3341            let arr = [1, 2, 3, 4, 5];
3342            for i in arr {
3343                print_int(i);
3344            }
3345        }
3346        "#;
3347
3348        let mut lexer = Lexer::new(source);
3349        let tokens = lexer.collect_tokens().unwrap();
3350        let mut parser = Parser::new(tokens);
3351        let ast = parser.parse().unwrap();
3352
3353        let mut type_checker = TypeChecker::new();
3354        assert!(type_checker.check(&ast).is_ok());
3355    }
3356
3357    #[test]
3358    fn test_for_loop_wrong_type() {
3359        let source = r#"
3360        fn main() {
3361            let x = 42;
3362            for i in x {
3363                print_int(i);
3364            }
3365        }
3366        "#;
3367
3368        let mut lexer = Lexer::new(source);
3369        let tokens = lexer.collect_tokens().unwrap();
3370        let mut parser = Parser::new(tokens);
3371        let ast = parser.parse().unwrap();
3372
3373        let mut type_checker = TypeChecker::new();
3374        let result = type_checker.check(&ast);
3375        assert!(result.is_err());
3376
3377        if let Err(CompileError::Generic(msg)) = result {
3378            assert!(msg.contains("For loop requires an array"));
3379        }
3380    }
3381
3382    #[test]
3383    fn test_break_continue_in_loops() {
3384        let source = r#"
3385        fn main() {
3386            let arr = [1, 2, 3, 4, 5];
3387            
3388            // Test break and continue in while loop
3389            let mut i = 0;
3390            while i < 10 {
3391                if i == 5 {
3392                    break;
3393                }
3394                if i == 3 {
3395                    i = i + 1;
3396                    continue;
3397                }
3398                i = i + 1;
3399            }
3400            
3401            // Test break and continue in for loop
3402            for n in arr {
3403                if n == 3 {
3404                    continue;
3405                }
3406                if n > 4 {
3407                    break;
3408                }
3409                print_int(n);
3410            }
3411        }
3412        "#;
3413
3414        let mut lexer = Lexer::new(source);
3415        let tokens = lexer.collect_tokens().unwrap();
3416        let mut parser = Parser::new(tokens);
3417        let ast = parser.parse().unwrap();
3418
3419        let mut type_checker = TypeChecker::new();
3420        assert!(type_checker.check(&ast).is_ok());
3421    }
3422
3423    #[test]
3424    fn test_string_len_typecheck() {
3425        let source = r#"
3426        fn main() {
3427            let s = "Hello";
3428            let len = string_len(s);
3429            print_int(len);
3430        }
3431        "#;
3432
3433        let mut lexer = Lexer::new(source);
3434        let tokens = lexer.collect_tokens().unwrap();
3435        let mut parser = Parser::new(tokens);
3436        let ast = parser.parse().unwrap();
3437
3438        let mut type_checker = TypeChecker::new();
3439        assert!(type_checker.check(&ast).is_ok());
3440    }
3441
3442    #[test]
3443    fn test_string_concat_typecheck() {
3444        let source = r#"
3445        fn main() {
3446            let s1 = "Hello";
3447            let s2 = " World";
3448            let s3 = string_concat(s1, s2);
3449            print(s3);
3450        }
3451        "#;
3452
3453        let mut lexer = Lexer::new(source);
3454        let tokens = lexer.collect_tokens().unwrap();
3455        let mut parser = Parser::new(tokens);
3456        let ast = parser.parse().unwrap();
3457
3458        let mut type_checker = TypeChecker::new();
3459        assert!(type_checker.check(&ast).is_ok());
3460    }
3461
3462    #[test]
3463    fn test_string_char_predicates() {
3464        let source = r#"
3465        fn main() {
3466            let c = 65;
3467            let is_alpha = char_is_alpha(c);
3468            let is_digit = char_is_digit(c);
3469            let is_space = char_is_whitespace(c);
3470            if is_alpha {
3471                print("Is alphabetic");
3472            }
3473        }
3474        "#;
3475
3476        let mut lexer = Lexer::new(source);
3477        let tokens = lexer.collect_tokens().unwrap();
3478        let mut parser = Parser::new(tokens);
3479        let ast = parser.parse().unwrap();
3480
3481        let mut type_checker = TypeChecker::new();
3482        assert!(type_checker.check(&ast).is_ok());
3483    }
3484
3485    #[test]
3486    fn test_string_type_errors() {
3487        let source = r#"
3488        fn main() {
3489            let n = 42;
3490            let len = string_len(n); // Error: expects string
3491        }
3492        "#;
3493
3494        let mut lexer = Lexer::new(source);
3495        let tokens = lexer.collect_tokens().unwrap();
3496        let mut parser = Parser::new(tokens);
3497        let ast = parser.parse().unwrap();
3498
3499        let mut type_checker = TypeChecker::new();
3500        assert!(type_checker.check(&ast).is_err());
3501    }
3502
3503    #[test]
3504    fn test_file_io_typecheck() {
3505        let source = r#"
3506        fn main() {
3507            let path = "test.txt";
3508            let exists = file_exists(path);
3509            if exists {
3510                let handle = file_open(path);
3511                let content = file_read_all(handle);
3512                file_close(handle);
3513            }
3514        }
3515        "#;
3516
3517        let mut lexer = Lexer::new(source);
3518        let tokens = lexer.collect_tokens().unwrap();
3519        let mut parser = Parser::new(tokens);
3520        let ast = parser.parse().unwrap();
3521
3522        let mut type_checker = TypeChecker::new();
3523        assert!(type_checker.check(&ast).is_ok());
3524    }
3525
3526    #[test]
3527    fn test_file_write_typecheck() {
3528        let source = r#"
3529        fn main() {
3530            let handle = file_open("output.txt");
3531            let success = file_write(handle, "test content");
3532            let closed = file_close(handle);
3533        }
3534        "#;
3535
3536        let mut lexer = Lexer::new(source);
3537        let tokens = lexer.collect_tokens().unwrap();
3538        let mut parser = Parser::new(tokens);
3539        let ast = parser.parse().unwrap();
3540
3541        let mut type_checker = TypeChecker::new();
3542        assert!(type_checker.check(&ast).is_ok());
3543    }
3544
3545    #[test]
3546    fn test_file_io_type_errors() {
3547        let source = r#"
3548        fn main() {
3549            let handle = file_open(123); // Error: expects string
3550        }
3551        "#;
3552
3553        let mut lexer = Lexer::new(source);
3554        let tokens = lexer.collect_tokens().unwrap();
3555        let mut parser = Parser::new(tokens);
3556        let ast = parser.parse().unwrap();
3557
3558        let mut type_checker = TypeChecker::new();
3559        assert!(type_checker.check(&ast).is_err());
3560    }
3561
3562    #[test]
3563    fn test_result_enum_definition() {
3564        let source = r#"
3565        enum Result {
3566            Ok(String),
3567            Err(String),
3568        }
3569        
3570        fn main() {
3571            let ok = Result::Ok("success");
3572            let err = Result::Err("failure");
3573            
3574            match ok {
3575                Result::Ok(_) => print("ok"),
3576                Result::Err(_) => print("err"),
3577            }
3578        }
3579        "#;
3580
3581        let mut lexer = Lexer::new(source);
3582        let tokens = lexer.collect_tokens().unwrap();
3583        let mut parser = Parser::new(tokens);
3584        let ast = parser.parse().unwrap();
3585
3586        let mut type_checker = TypeChecker::new();
3587        match type_checker.check(&ast) {
3588            Ok(_) => {}
3589            Err(e) => panic!("Type check failed: {}", e),
3590        }
3591    }
3592
3593    #[test]
3594    fn test_result_pattern_matching() {
3595        let source = r#"
3596        enum IntResult {
3597            Ok(i64),
3598            Err(String),
3599        }
3600        
3601        fn main() {
3602            let result = IntResult::Ok(42);
3603            
3604            match result {
3605                IntResult::Ok(_) => print("Success"),
3606                IntResult::Err(_) => print("Error"),
3607            }
3608        }
3609        "#;
3610
3611        let mut lexer = Lexer::new(source);
3612        let tokens = lexer.collect_tokens().unwrap();
3613        let mut parser = Parser::new(tokens);
3614        let ast = parser.parse().unwrap();
3615
3616        let mut type_checker = TypeChecker::new();
3617        assert!(type_checker.check(&ast).is_ok());
3618    }
3619
3620    #[test]
3621    fn test_multiple_result_types() {
3622        let source = r#"
3623        enum StringResult {
3624            Ok(String),
3625            Err(String),
3626        }
3627        
3628        enum FileResult {
3629            Ok(i64),
3630            Err(String),
3631        }
3632        
3633        fn main() {
3634            let s_result = StringResult::Ok("test");
3635            let f_result = FileResult::Err("not found");
3636            
3637            match s_result {
3638                StringResult::Ok(_) => {
3639                    print("string ok");
3640                }
3641                StringResult::Err(_) => {
3642                    print("string err");
3643                }
3644            }
3645            
3646            match f_result {
3647                FileResult::Ok(_) => {
3648                    print("file ok");
3649                }
3650                FileResult::Err(_) => {
3651                    print("file err");
3652                }
3653            }
3654        }
3655        "#;
3656
3657        let mut lexer = Lexer::new(source);
3658        let tokens = lexer.collect_tokens().unwrap();
3659        let mut parser = Parser::new(tokens);
3660        let ast = parser.parse().unwrap();
3661
3662        let mut type_checker = TypeChecker::new();
3663        assert!(type_checker.check(&ast).is_ok());
3664    }
3665
3666    #[test]
3667    fn test_exhaustive_enum_match() {
3668        let source = r#"
3669        enum Color {
3670            Red,
3671            Green,
3672            Blue,
3673        }
3674        
3675        fn main() {
3676            let c = Color::Red;
3677            
3678            match c {
3679                Color::Red => print("red"),
3680                Color::Green => print("green"),
3681                Color::Blue => print("blue"),
3682            }
3683        }
3684        "#;
3685
3686        let mut lexer = Lexer::new(source);
3687        let tokens = lexer.collect_tokens().unwrap();
3688        let mut parser = Parser::new(tokens);
3689        let ast = parser.parse().unwrap();
3690
3691        let mut type_checker = TypeChecker::new();
3692        assert!(type_checker.check(&ast).is_ok());
3693    }
3694
3695    #[test]
3696    fn test_non_exhaustive_enum_match() {
3697        let source = r#"
3698        enum Color {
3699            Red,
3700            Green,
3701            Blue,
3702        }
3703        
3704        fn main() {
3705            let c = Color::Red;
3706            
3707            match c {
3708                Color::Red => print("red"),
3709                Color::Green => print("green"),
3710                // Missing Blue!
3711            }
3712        }
3713        "#;
3714
3715        let mut lexer = Lexer::new(source);
3716        let tokens = lexer.collect_tokens().unwrap();
3717        let mut parser = Parser::new(tokens);
3718        let ast = parser.parse().unwrap();
3719
3720        let mut type_checker = TypeChecker::new();
3721        let result = type_checker.check(&ast);
3722        assert!(result.is_err());
3723
3724        if let Err(CompileError::NonExhaustiveMatch {
3725            missing_patterns, ..
3726        }) = result
3727        {
3728            assert!(missing_patterns.contains(&"Color::Blue".to_string()));
3729        } else {
3730            panic!("Expected NonExhaustiveMatch error");
3731        }
3732    }
3733
3734    #[test]
3735    fn test_wildcard_makes_match_exhaustive() {
3736        let source = r#"
3737        enum Color {
3738            Red,
3739            Green,
3740            Blue,
3741        }
3742        
3743        fn main() {
3744            let c = Color::Red;
3745            
3746            match c {
3747                Color::Red => print("red"),
3748                _ => print("other"),
3749            }
3750        }
3751        "#;
3752
3753        let mut lexer = Lexer::new(source);
3754        let tokens = lexer.collect_tokens().unwrap();
3755        let mut parser = Parser::new(tokens);
3756        let ast = parser.parse().unwrap();
3757
3758        let mut type_checker = TypeChecker::new();
3759        assert!(type_checker.check(&ast).is_ok());
3760    }
3761
3762    #[test]
3763    fn test_unreachable_pattern_after_wildcard() {
3764        let source = r#"
3765        enum Color {
3766            Red,
3767            Green,
3768            Blue,
3769        }
3770        
3771        fn main() {
3772            let c = Color::Red;
3773            
3774            match c {
3775                Color::Red => print("red"),
3776                _ => print("any"),
3777                Color::Blue => print("blue"), // Unreachable!
3778            }
3779        }
3780        "#;
3781
3782        let mut lexer = Lexer::new(source);
3783        let tokens = lexer.collect_tokens().unwrap();
3784        let mut parser = Parser::new(tokens);
3785        let ast = parser.parse().unwrap();
3786
3787        let mut type_checker = TypeChecker::new();
3788        let result = type_checker.check(&ast);
3789        assert!(result.is_err());
3790
3791        if let Err(CompileError::UnreachablePattern { .. }) = result {
3792            // Expected
3793        } else {
3794            panic!("Expected UnreachablePattern error");
3795        }
3796    }
3797}