Skip to content

Commit 17fe033

Browse files
author
Moika
committed
Fix generic type system implementation and update semantic analyzer
1 parent aa0eb9a commit 17fe033

4 files changed

Lines changed: 67 additions & 9 deletions

File tree

src/semantic/analyzer.rs

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::inference::{type_ann_to_type, InferenceContext};
22
use crate::parser::{
3-
BinaryOp, Block, ExportKind, Expr, ExprKind, ImportSpecifier, Literal, Param, Program, Stmt,
4-
StmtKind, TypeAnn, UnaryOp,
3+
BinaryOp, Block, ExportKind, Expr, ExprKind, GenericParams, ImportSpecifier, Literal, Param,
4+
Program, Stmt, StmtKind, TraitBound, TypeAnn, UnaryOp,
55
};
66
use crate::source::Span;
77
use crate::types::Type;
@@ -24,6 +24,8 @@ struct AnalysisContext {
2424
_in_const_function: bool,
2525
/// Whether we're currently in an async function
2626
in_async_function: bool,
27+
/// Generic parameters in the current scope (maps name to bounds)
28+
generic_params: HashMap<String, Vec<TraitBound>>,
2729
}
2830

2931
impl AnalysisContext {
@@ -33,6 +35,7 @@ impl AnalysisContext {
3335
in_loop: false,
3436
_in_const_function: false,
3537
in_async_function: false,
38+
generic_params: HashMap::new(),
3639
}
3740
}
3841
}
@@ -193,6 +196,7 @@ impl SemanticAnalyzer {
193196
return_type: Type::Unknown, // void
194197
is_const: false,
195198
is_async: false,
199+
generic_params: vec![],
196200
};
197201
self.symbol_table
198202
.define_function(
@@ -214,6 +218,7 @@ impl SemanticAnalyzer {
214218
return_type: Type::I32,
215219
is_const: true,
216220
is_async: false,
221+
generic_params: vec![],
217222
};
218223
self.symbol_table
219224
.define_function(
@@ -257,10 +262,11 @@ impl SemanticAnalyzer {
257262
ret_type,
258263
body,
259264
is_async,
260-
generic_params: _,
265+
generic_params,
261266
} => {
262267
self.analyze_function_with_attributes(
263268
name,
269+
generic_params.as_ref(),
264270
params,
265271
ret_type.as_ref(),
266272
body,
@@ -394,6 +400,7 @@ impl SemanticAnalyzer {
394400
fn analyze_function(
395401
&mut self,
396402
name: &str,
403+
generic_params: Option<&GenericParams>,
397404
params: &[Param],
398405
ret_type: Option<&TypeAnn>,
399406
body: &Block,
@@ -422,6 +429,7 @@ impl SemanticAnalyzer {
422429
return_type: return_type.clone(),
423430
is_const: false, // Legacy method - const handled in new method
424431
is_async,
432+
generic_params: vec![], // TODO: Implement generic parameter conversion
425433
};
426434

427435
// Define the function
@@ -445,14 +453,25 @@ impl SemanticAnalyzer {
445453
self.symbol_table.enter_scope();
446454
self.inference_ctx.push_scope();
447455

448-
// Push function context
456+
// Push function context with generic parameters
449457
// For async functions, we need to check returns against the unwrapped type
450-
let func_context = AnalysisContext {
458+
let mut func_context = AnalysisContext {
451459
current_function_return: Some(base_return_type),
452460
in_loop: false,
453461
_in_const_function: false, // TODO: Support @const
454462
in_async_function: is_async,
463+
generic_params: HashMap::new(),
455464
};
465+
466+
// Extract generic parameters if present
467+
if let Some(generics) = generic_params {
468+
for param in &generics.params {
469+
func_context
470+
.generic_params
471+
.insert(param.name.clone(), param.bounds.clone());
472+
}
473+
}
474+
456475
self.push_context(func_context);
457476

458477
// Define parameters
@@ -493,6 +512,7 @@ impl SemanticAnalyzer {
493512
fn analyze_function_with_attributes(
494513
&mut self,
495514
name: &str,
515+
generic_params: Option<&GenericParams>,
496516
params: &[Param],
497517
ret_type: Option<&TypeAnn>,
498518
body: &Block,
@@ -527,6 +547,7 @@ impl SemanticAnalyzer {
527547
return_type: return_type.clone(),
528548
is_const,
529549
is_async,
550+
generic_params: vec![], // TODO: Implement generic parameter conversion
530551
};
531552

532553
// Define the function
@@ -550,13 +571,24 @@ impl SemanticAnalyzer {
550571
self.symbol_table.enter_scope();
551572
self.inference_ctx.push_scope();
552573

553-
// Push function context with const flag
554-
let func_context = AnalysisContext {
574+
// Push function context with const flag and generic parameters
575+
let mut func_context = AnalysisContext {
555576
current_function_return: Some(base_return_type),
556577
in_loop: false,
557578
_in_const_function: is_const,
558579
in_async_function: is_async,
580+
generic_params: HashMap::new(),
559581
};
582+
583+
// Extract generic parameters if present
584+
if let Some(generics) = generic_params {
585+
for param in &generics.params {
586+
func_context
587+
.generic_params
588+
.insert(param.name.clone(), param.bounds.clone());
589+
}
590+
}
591+
560592
self.push_context(func_context);
561593

562594
// Define parameters
@@ -787,7 +819,15 @@ impl SemanticAnalyzer {
787819
is_async,
788820
} => {
789821
// Analyze the function first
790-
self.analyze_function(name, params, ret_type.as_ref(), body, *is_async, span)?;
822+
self.analyze_function(
823+
name,
824+
None,
825+
params,
826+
ret_type.as_ref(),
827+
body,
828+
*is_async,
829+
span,
830+
)?;
791831

792832
// Then mark it as exported
793833
if let Err(err) = self.symbol_table.process_export(kind, span) {
@@ -915,6 +955,13 @@ impl SemanticAnalyzer {
915955

916956
/// Analyze an identifier
917957
fn analyze_identifier(&mut self, name: &str, span: crate::source::Span) -> Result<Type> {
958+
// First check if it's a type parameter in the current generic context
959+
let ctx = self.current_context();
960+
if ctx.generic_params.contains_key(name) {
961+
// This is a type parameter reference
962+
return Ok(Type::TypeParam(name.to_string()));
963+
}
964+
918965
// Use module-aware lookup
919966
if let Some(symbol) = self.symbol_table.lookup_with_modules(name) {
920967
let symbol_id = symbol.id;

src/semantic/pattern_exhaustiveness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ mod tests {
264264
use crate::source::Span;
265265

266266
fn dummy_span() -> Span {
267-
Span::default()
267+
Span::dummy()
268268
}
269269

270270
fn dummy_expr() -> Expr {

src/semantic/symbol.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ pub struct FunctionSignature {
5555
pub is_const: bool,
5656
/// Whether this function is async (for actors)
5757
pub is_async: bool,
58+
/// Generic parameters with their bounds
59+
pub generic_params: Vec<(String, Vec<String>)>,
5860
}
5961

6062
impl Symbol {
@@ -219,6 +221,7 @@ mod tests {
219221
return_type: Type::I32,
220222
is_const: false,
221223
is_async: false,
224+
generic_params: vec![],
222225
};
223226

224227
let func_symbol = Symbol::function(
@@ -247,13 +250,15 @@ mod tests {
247250
return_type: Type::I32,
248251
is_const: false,
249252
is_async: false,
253+
generic_params: vec![],
250254
};
251255

252256
let sig2 = FunctionSignature {
253257
params: vec![("x".to_string(), Type::I32), ("y".to_string(), Type::I32)],
254258
return_type: Type::I32,
255259
is_const: false,
256260
is_async: false,
261+
generic_params: vec![],
257262
};
258263

259264
assert!(sig1.is_compatible_for_overload(&sig2));
@@ -265,6 +270,7 @@ mod tests {
265270
return_type: Type::I32,
266271
is_const: false,
267272
is_async: false,
273+
generic_params: vec![],
268274
};
269275

270276
assert!(sig1.is_compatible_for_overload(&sig3));
@@ -275,6 +281,7 @@ mod tests {
275281
return_type: Type::F32, // Different return type doesn't matter
276282
is_const: true, // Different const doesn't matter
277283
is_async: false,
284+
generic_params: vec![],
278285
};
279286

280287
assert!(!sig1.is_compatible_for_overload(&sig4));

src/semantic/symbol_table.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ mod tests {
832832
return_type: Type::I32,
833833
is_const: false,
834834
is_async: false,
835+
generic_params: vec![],
835836
};
836837
table
837838
.define_function("add".to_string(), sig1, make_span())
@@ -843,6 +844,7 @@ mod tests {
843844
return_type: Type::I32,
844845
is_const: false,
845846
is_async: false,
847+
generic_params: vec![],
846848
};
847849
table
848850
.define_function("add".to_string(), sig2, make_span())
@@ -887,6 +889,7 @@ mod tests {
887889
return_type: Type::I32,
888890
is_const: false,
889891
is_async: false,
892+
generic_params: vec![],
890893
};
891894
table
892895
.define_function("foo".to_string(), sig1.clone(), make_span())
@@ -898,6 +901,7 @@ mod tests {
898901
return_type: Type::F32,
899902
is_const: true,
900903
is_async: false,
904+
generic_params: vec![],
901905
};
902906
let result = table.define_function("foo".to_string(), sig2, make_span());
903907
assert!(result.is_err());

0 commit comments

Comments
 (0)