1use 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#[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#[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#[derive(Debug, Clone, PartialEq)]
53pub enum GenericArgValue {
54 Type(CheckerType),
55 Const(ConstValueResolved),
56}
57
58#[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 ArraySizeValue::Literal(0) }
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 CheckerType::TypeParam(name.clone())
89 }
90 crate::ast::Type::Generic { name, args } => {
91 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 CheckerType::from(inner.as_ref())
113 }
114 crate::ast::Type::Future { output } => {
115 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#[derive(Debug, Clone)]
171struct VarInfo {
172 ty: CheckerType,
173 mutable: bool,
174}
175
176#[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()], }
187 }
188
189 fn enter_scope(&mut self) {
191 self.scopes.push(HashMap::new());
192 }
193
194 fn exit_scope(&mut self) {
196 if self.scopes.len() > 1 {
197 self.scopes.pop();
198 }
199 }
200
201 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 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#[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#[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#[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#[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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
278struct FunctionInstantiation {
279 name: String,
280 type_args: Vec<String>, }
282
283#[derive(Debug, Clone, PartialEq, Eq, Hash)]
285pub struct StructInstantiation {
286 pub name: String,
287 pub type_args: Vec<String>, }
289
290pub struct TypeChecker {
291 functions: HashMap<String, CheckerType>,
293 generic_functions: HashMap<String, GenericFunction>,
295 instantiations: HashMap<FunctionInstantiation, CheckerType>,
297 structs: HashMap<String, Vec<(String, CheckerType)>>,
299 generic_structs: HashMap<String, GenericStruct>,
301 trait_resolver: TraitResolver,
303 struct_instantiations: HashMap<StructInstantiation, CheckerType>,
305 enums: HashMap<String, Vec<EnumVariant>>,
307 generic_enums: HashMap<String, GenericEnum>,
309 type_aliases: HashMap<String, crate::ast::Type>,
311 generic_type_aliases: HashMap<String, GenericTypeAlias>,
313 current_function_return: Option<CheckerType>,
315 symbols: SymbolTable,
317 imported_modules: HashMap<String, crate::resolver::ModuleInfo>,
319 loop_depth: usize,
321 error_helper: TypeErrorHelper,
323 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 functions.insert(
339 "print".to_string(),
340 CheckerType::Function(vec![CheckerType::String], Box::new(CheckerType::Unit)),
341 );
342
343 functions.insert(
345 "print_int".to_string(),
346 CheckerType::Function(vec![CheckerType::Int], Box::new(CheckerType::Unit)),
347 );
348
349 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 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 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 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 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 pub fn set_imported_modules(&mut self, modules: HashMap<String, crate::resolver::ModuleInfo>) {
536 self.imported_modules = modules;
537
538 for (module_name, module_info) in &self.imported_modules {
540 for item in &module_info.ast.items {
542 match item {
543 crate::ast::Item::Function(func) => {
544 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 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 let param_types: Vec<CheckerType> = func
566 .params
567 .iter()
568 .map(|param| CheckerType::from(¶m.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 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 let fields: Vec<(String, CheckerType)> = struct_def
591 .fields
592 .iter()
593 .map(|(name, ty)| (name.clone(), CheckerType::from(ty)))
594 .collect();
595
596 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 {
605 let enum_type = CheckerType::Enum(enum_def.name.clone());
607
608 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 let func_type = match &variant.data {
616 crate::ast::EnumVariantData::Unit => {
617 CheckerType::Function(vec![], Box::new(enum_type.clone()))
619 }
620 crate::ast::EnumVariantData::Tuple(types) => {
621 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 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 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 }
654 }
655 crate::ast::Item::Impl(_) => {
656 }
658 crate::ast::Item::TypeAlias(type_alias) => {
659 if matches!(type_alias.visibility, crate::ast::Visibility::Public) {
660 let qualified_name = format!("{}::{}", module_name, type_alias.name);
662
663 if !type_alias.type_params.is_empty() {
664 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 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 }
686 }
687 }
688 }
689 }
690
691 pub fn check(&mut self, program: &Program) -> Result<()> {
693 for item in &program.items {
695 match item {
696 Item::Function(func) => {
697 if !func.type_params.is_empty() {
698 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 let param_types: Vec<CheckerType> = func
715 .params
716 .iter()
717 .map(|param| self.ast_type_to_checker_type(¶m.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 if !struct_def.type_params.is_empty() || !struct_def.lifetime_params.is_empty()
733 {
734 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 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 if !enum_def.type_params.is_empty() || !enum_def.lifetime_params.is_empty() {
756 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 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 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 self.trait_resolver.register_trait(trait_def)?;
825 }
826 Item::TypeAlias(type_alias) => {
827 if !type_alias.type_params.is_empty() || !type_alias.lifetime_params.is_empty()
829 {
830 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 self.type_aliases
841 .insert(type_alias.name.clone(), type_alias.ty.clone());
842 }
843 }
844 Item::Impl(impl_block) => {
845 self.trait_resolver.register_impl(impl_block)?;
847
848 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 for method in &impl_block.methods {
856 let method_name = if let Some(_trait_type) = &impl_block.trait_type {
858 format!("{}::{}", impl_block.for_type, method.name)
860 } else {
861 format!("{}::{}", impl_block.for_type, method.name)
863 };
864
865 if !method.type_params.is_empty() {
866 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 let param_types: Vec<CheckerType> = method
882 .params
883 .iter()
884 .map(|param| CheckerType::from(¶m.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 }
902 }
903 }
904
905 if !self.functions.contains_key("main") {
907 return Err(TypeErrorHelper::missing_main());
908 }
909
910 for item in &program.items {
912 match item {
913 Item::Function(func) => {
914 self.check_function(func)?;
915 }
916 Item::Struct(_) => {
917 }
919 Item::Enum(_) => {
920 }
922 Item::Trait(_) => {
923 }
926 Item::TypeAlias(_) => {
927 }
930 Item::Impl(impl_block) => {
931 for method in &impl_block.methods {
933 self.check_function(method)?;
934 }
935 }
936 Item::Macro(_) => {
937 }
939 }
940 }
941
942 Ok(())
943 }
944
945 fn ast_type_to_checker_type(&self, ast_type: &crate::ast::Type) -> CheckerType {
947 match ast_type {
948 crate::ast::Type::Custom(name) => {
949 if let Some(aliased_type) = self.type_aliases.get(name) {
951 return self.ast_type_to_checker_type(aliased_type);
953 }
954
955 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 if let Some(generic_alias) = self.generic_type_aliases.get(name) {
965 if args.len() != generic_alias.type_params.len() {
967 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 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, })
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 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 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 fn check_function(&mut self, func: &Function) -> Result<()> {
1036 if !func.type_params.is_empty() {
1038 return Ok(());
1039 }
1040
1041 self.symbols.enter_scope();
1043
1044 for param in &func.params {
1046 let checker_type = self.ast_type_to_checker_type(¶m.ty);
1047 self.symbols
1048 .define(param.name.clone(), checker_type, param.mutable)?;
1049 }
1050
1051 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 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 for stmt in &func.body {
1072 self.check_statement(stmt)?;
1073 }
1074
1075 self.symbols.exit_scope();
1077 self.current_function_return = None;
1078 Ok(())
1079 }
1080
1081 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 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 let value_type = self.check_expression(value)?;
1121
1122 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 self.symbols.define(name.clone(), expected_type, *mutable)?;
1134 } else {
1135 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 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 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 if !var_mutable {
1163 return Err(self.error_helper.immutable_assignment(name));
1164 }
1165
1166 let value_type = self.check_expression(value)?;
1168
1169 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 let array_type = self.check_expression(array)?;
1183
1184 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 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 let value_type = self.check_expression(value)?;
1207
1208 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 let object_type = self.check_expression(object)?;
1222
1223 let field_type = match &object_type {
1224 CheckerType::Struct(name) => {
1226 let fields = self.structs.get(name).ok_or_else(|| {
1228 CompileError::Generic(format!("Unknown struct type: {}", name))
1229 })?;
1230
1231 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 CheckerType::Generic { name, args } => {
1245 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 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 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, })
1274 .collect();
1275
1276 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 let value_type = self.check_expression(value)?;
1293
1294 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 let _ptr_type = self.check_expression(expr)?;
1308 let _value_type = self.check_expression(value)?;
1310 Ok(())
1312 }
1313 }
1314 }
1315 Stmt::If {
1316 condition,
1317 then_branch,
1318 else_branch,
1319 ..
1320 } => {
1321 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 self.symbols.enter_scope();
1333 for stmt in then_branch {
1334 self.check_statement(stmt)?;
1335 }
1336 self.symbols.exit_scope();
1337
1338 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 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 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 let iter_type = self.check_expression(iter)?;
1378
1379 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 self.symbols.enter_scope();
1392 self.loop_depth += 1;
1393
1394 self.symbols.define(var.clone(), elem_type, false)?;
1396
1397 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 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 let expr_type = self.check_expression(expr)?;
1424
1425 for arm in arms {
1428 self.check_pattern(&arm.pattern, &expr_type)?;
1430
1431 self.symbols.enter_scope();
1433
1434 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 if let CheckerType::Enum(enum_name) = &expr_type {
1446 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 self.unsafe_depth += 1;
1484
1485 self.symbols.enter_scope();
1487 for stmt in body {
1488 self.check_statement(stmt)?;
1489 }
1490 self.symbols.exit_scope();
1491
1492 self.unsafe_depth -= 1;
1494
1495 Ok(())
1496 }
1497 }
1498 }
1499
1500 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 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 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 Ok(CheckerType::from(ty))
1540 }
1541 }
1542 _ => Ok(CheckerType::from(ty)),
1544 }
1545 }
1546
1547 #[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 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 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()), })
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 _ => ty.clone(),
1594 }
1595 }
1596
1597 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 if let Some(var_info) = self.symbols.lookup(name) {
1606 return Ok(var_info.ty.clone());
1607 }
1608
1609 match self.functions.get(name) {
1611 Some(func_type) => Ok(func_type.clone()),
1612 None => {
1613 let available_vars = self.get_available_variables();
1615 let available_funcs = self.get_available_functions();
1616
1617 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 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 Err(CompileError::Generic(format!(
1645 "Undefined variable or function: '{}'",
1646 name
1647 )))
1648 }
1649 }
1650 }
1651 Expr::Call { func, args, .. } => {
1652 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 if let Some(generic_func) = self.generic_functions.get(func_name).cloned() {
1664 let type_args = self.infer_type_args(&generic_func, args)?;
1666
1667 let instantiation = FunctionInstantiation {
1669 name: func_name.clone(),
1670 type_args: type_args.clone(),
1671 };
1672
1673 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 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 let func_type = match self.functions.get(func_name) {
1687 Some(ft) => ft.clone(),
1688 None => {
1689 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 match func_type {
1699 CheckerType::Function(param_types, return_type) => {
1700 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 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 match (&left_type, &right_type) {
1740 (CheckerType::Int, CheckerType::Int) => Ok(CheckerType::Int),
1741 (CheckerType::String, CheckerType::String) => Ok(CheckerType::String),
1742 _ => {
1743 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 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 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 Ok(CheckerType::Bool)
1795 }
1796 BinOp::And | BinOp::Or => {
1797 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 let elem_type = self.check_expression(&elements[0])?;
1825
1826 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 let elem_type = self.check_expression(value)?;
1846
1847 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 let array_type = self.check_expression(array)?;
1868
1869 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 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 if let Some(generic_struct) = self.generic_structs.get(name).cloned() {
1891 let mut type_substitutions: HashMap<String, CheckerType> = HashMap::new();
1893
1894 for (field_name, _) in fields {
1896 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 for (field_name, field_expr) in fields {
1911 let field_type = generic_struct
1913 .fields
1914 .iter()
1915 .find(|(fname, _)| fname == field_name)
1916 .map(|(_, ftype)| ftype)
1917 .unwrap(); let provided_type = self.check_expression(field_expr)?;
1921
1922 if let crate::ast::Type::TypeParam(param_name) = field_type {
1924 if generic_struct.type_params.contains(param_name) {
1925 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 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 }
1954
1955 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 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 let concrete_checker_type = self.substitute_type_params(
1986 field_type,
1987 &generic_struct.type_params,
1988 &inferred_args,
1989 )?;
1990
1991 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 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 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 Ok(instantiated_type);
2056 }
2057
2058 let struct_fields = self
2060 .structs
2061 .get(name)
2062 .ok_or_else(|| CompileError::Generic(format!("Unknown struct type: {}", name)))?
2063 .clone();
2064
2065 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 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 let object_type = self.check_expression(object)?;
2106
2107 match &object_type {
2108 CheckerType::Struct(name) => {
2110 let fields = self.structs.get(name).ok_or_else(|| {
2112 CompileError::Generic(format!("Unknown struct type: {}", name))
2113 })?;
2114
2115 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 CheckerType::Generic { name, args } => {
2131 let generic_struct = self.generic_structs.get(name).ok_or_else(|| {
2133 CompileError::Generic(format!("Unknown generic struct type: {}", name))
2134 })?;
2135
2136 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 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 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 if let Some(generic_enum) = self.generic_enums.get(enum_name).cloned() {
2182 let mut inferred_types = Vec::new();
2184
2185 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 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 (param_type, arg_expr) in param_types.iter().zip(arg_exprs) {
2206 let arg_type = self.check_expression(arg_expr)?;
2207
2208 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 if let Some(idx) = generic_enum
2222 .type_params
2223 .iter()
2224 .position(|p| p == param_name)
2225 {
2226 while inferred_types.len() <= idx {
2228 inferred_types.push(CheckerType::Unit);
2229 }
2231 inferred_types[idx] = arg_type;
2232 }
2233 }
2234 }
2235 }
2236 _ => {
2237 }
2240 }
2241
2242 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 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 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 match (&variant_info.fields, data.as_ref()) {
2275 (EnumVariantFields::Unit, None) => {
2276 }
2278 (EnumVariantFields::Unit, Some(_)) => {
2279 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 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 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 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 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 let start_type = self.check_expression(start)?;
2363 let end_type = self.check_expression(end)?;
2364
2365 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 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 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 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 let inner_type = self.check_expression(expr)?;
2421
2422 Ok(inner_type)
2425 }
2426 Expr::Deref { expr, .. } => {
2427 let expr_type = self.check_expression(expr)?;
2429
2430 Ok(expr_type)
2433 }
2434 Expr::Question { expr, .. } => {
2435 let expr_type = self.check_expression(expr)?;
2437
2438 match &expr_type {
2440 CheckerType::Generic { name, args } if name == "Result" && args.len() == 2 => {
2441 let ok_type = &args[0];
2443 let err_type = &args[1];
2444
2445 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 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 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 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 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 let expr_type = self.check_expression(expr)?;
2519 match &expr_type {
2520 CheckerType::Generic { name, args } if name == "Future" && args.len() == 1 => {
2521 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 fn check_pattern(&self, pattern: &Pattern, expected_type: &CheckerType) -> Result<()> {
2540 match pattern {
2541 Pattern::Wildcard => {
2542 Ok(())
2544 }
2545 Pattern::Ident(_) => {
2546 Ok(())
2548 }
2549 Pattern::EnumPattern {
2550 enum_name,
2551 variant: _,
2552 data: _,
2553 } => {
2554 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 fn bind_pattern_variables(
2570 &mut self,
2571 pattern: &Pattern,
2572 value_type: &CheckerType,
2573 ) -> Result<()> {
2574 match pattern {
2575 Pattern::Wildcard => {
2576 Ok(())
2578 }
2579 Pattern::Ident(name) => {
2580 self.symbols.define(
2582 name.clone(),
2583 value_type.clone(),
2584 false, )?;
2586 Ok(())
2587 }
2588 Pattern::EnumPattern {
2589 enum_name,
2590 variant,
2591 data,
2592 ..
2593 } => {
2594 if let Some(pattern_data) = data {
2596 match value_type {
2600 CheckerType::Enum(expected_enum) if expected_enum == enum_name => {
2601 if self.generic_enums.contains_key(enum_name) {
2603 return Err(CompileError::Generic(format!(
2605 "Generic enum {} used without type parameters",
2606 enum_name
2607 )));
2608 }
2609
2610 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 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 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 if let Some(generic_enum) = self.generic_enums.get(enum_name).cloned() {
2681 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 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 let type_params = generic_enum.type_params.clone();
2709 for (pattern, param_type) in
2710 patterns.iter().zip(param_types)
2711 {
2712 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 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 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 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 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 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 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 let expr_type = self.infer_expr_type(expr)?;
2805
2806 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 match expr {
2822 Expr::ArrayLiteral { elements, .. } => {
2823 if !elements.is_empty() {
2824 self.infer_from_expr_and_type(&elements[0], elem_type, type_map)?;
2826 }
2827 }
2828 Expr::ArrayRepeat { value, .. } => {
2829 self.infer_from_expr_and_type(value, elem_type, type_map)?;
2831 }
2832 Expr::Ident(name) => {
2833 if let Some(var_info) = self.symbols.lookup(name) {
2835 if let CheckerType::Array(var_elem_type, _) = &var_info.ty {
2836 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 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 Ok(())
2857 }
2858 }
2859 }
2860
2861 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()), Expr::Bool(_) => Ok("bool".to_string()),
2867 Expr::Ident(name) => {
2868 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 if elements.is_empty() {
2878 return Err(CompileError::Generic(
2879 "Cannot infer type from empty array".to_string(),
2880 ));
2881 }
2882
2883 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 let elem_type_str = self.infer_expr_type(value)?;
2891
2892 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 Err(CompileError::Generic(
2907 "Cannot infer type from complex expression".to_string(),
2908 ))
2909 }
2910 }
2911 }
2912
2913 #[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 fn instantiate_generic_function(
2956 &mut self,
2957 generic_func: &GenericFunction,
2958 type_args: &[String],
2959 ) -> Result<CheckerType> {
2960 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 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 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 #[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 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 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 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 for (arg, expected_type) in args.iter().zip(¶m_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 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 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 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 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 #[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 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 } else {
3794 panic!("Expected UnreachablePattern error");
3795 }
3796 }
3797}