Refactor type checking for globals
Introduces a `global_types` field to `TypeContext` and updates the `TypeChecker` to pass it down. This allows type checking to correctly infer and set types for global variables, removing the previous hardcoded `StaticType::Any` for global addresses.
This commit is contained in:
@@ -11,6 +11,8 @@ struct TypeContext<'a> {
|
||||
slots: Vec<StaticType>,
|
||||
/// Types of captured variables (passed from outer scope)
|
||||
upvalue_types: Vec<StaticType>,
|
||||
/// Access to global types for unified resolution
|
||||
global_types: &'a std::cell::RefCell<HashMap<u32, StaticType>>,
|
||||
/// The expected parameters of the current function (for 'again' validation)
|
||||
current_params_ty: Option<StaticType>,
|
||||
}
|
||||
@@ -19,12 +21,14 @@ impl<'a> TypeContext<'a> {
|
||||
fn new(
|
||||
slot_count: u32,
|
||||
upvalue_types: Vec<StaticType>,
|
||||
global_types: &'a std::cell::RefCell<HashMap<u32, StaticType>>,
|
||||
parent: Option<&'a TypeContext<'a>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
_parent: parent,
|
||||
slots: vec![StaticType::Any; slot_count as usize],
|
||||
upvalue_types,
|
||||
global_types,
|
||||
current_params_ty: None,
|
||||
}
|
||||
}
|
||||
@@ -36,7 +40,12 @@ impl<'a> TypeContext<'a> {
|
||||
.get(idx as usize)
|
||||
.cloned()
|
||||
.unwrap_or(StaticType::Any),
|
||||
Address::Global(_) => StaticType::Any, // Globals are dynamic for now
|
||||
Address::Global(idx) => self
|
||||
.global_types
|
||||
.borrow()
|
||||
.get(&idx)
|
||||
.cloned()
|
||||
.unwrap_or(StaticType::Any),
|
||||
Address::Upvalue(idx) => self
|
||||
.upvalue_types
|
||||
.get(idx as usize)
|
||||
@@ -45,11 +54,19 @@ impl<'a> TypeContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_local_type(&mut self, idx: u32, ty: StaticType) {
|
||||
fn set_type(&mut self, addr: Address, ty: StaticType) {
|
||||
match addr {
|
||||
Address::Local(idx) => {
|
||||
if let Some(slot) = self.slots.get_mut(idx as usize) {
|
||||
*slot = ty;
|
||||
}
|
||||
}
|
||||
Address::Global(idx) => {
|
||||
self.global_types.borrow_mut().insert(idx, ty);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TypeChecker {
|
||||
@@ -76,8 +93,9 @@ impl TypeChecker {
|
||||
}
|
||||
|
||||
// 2. Create the specialized context
|
||||
let root_ctx = TypeContext::new(0, vec![], None);
|
||||
let mut lambda_ctx = TypeContext::new(64, upvalue_types, Some(&root_ctx));
|
||||
let root_ctx = TypeContext::new(0, vec![], &self.global_types, None);
|
||||
let mut lambda_ctx =
|
||||
TypeContext::new(64, upvalue_types, &self.global_types, Some(&root_ctx));
|
||||
|
||||
// 3. INJECT specialized argument types into slots
|
||||
let arg_tuple_ty = if arg_types.is_empty() {
|
||||
@@ -147,15 +165,7 @@ impl TypeChecker {
|
||||
captured_by,
|
||||
..
|
||||
} => {
|
||||
match addr {
|
||||
Address::Local(slot) => ctx.set_local_type(slot, specialized_ty.clone()),
|
||||
Address::Global(global_index) => {
|
||||
self.global_types
|
||||
.borrow_mut()
|
||||
.insert(global_index, specialized_ty.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ctx.set_type(addr, specialized_ty.clone());
|
||||
(
|
||||
BoundKind::Define {
|
||||
name,
|
||||
@@ -261,20 +271,11 @@ impl TypeChecker {
|
||||
} => {
|
||||
let val_typed = self.check_node(*value, ctx)?;
|
||||
let ty = val_typed.ty.clone();
|
||||
|
||||
match addr {
|
||||
Address::Local(slot) => ctx.set_local_type(slot, ty.clone()),
|
||||
Address::Global(global_index) => {
|
||||
self.global_types
|
||||
.borrow_mut()
|
||||
.insert(global_index, ty.clone());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ctx.set_type(addr, ty.clone());
|
||||
|
||||
(
|
||||
BoundKind::Define {
|
||||
name,
|
||||
name: name.clone(),
|
||||
addr,
|
||||
kind: decl_kind,
|
||||
value: Box::new(val_typed),
|
||||
@@ -285,15 +286,7 @@ impl TypeChecker {
|
||||
}
|
||||
|
||||
BoundKind::Get { addr, name } => {
|
||||
let ty = if let Address::Global(idx) = addr {
|
||||
self.global_types
|
||||
.borrow()
|
||||
.get(&idx)
|
||||
.cloned()
|
||||
.unwrap_or(StaticType::Any)
|
||||
} else {
|
||||
ctx.get_type(addr)
|
||||
};
|
||||
let ty = ctx.get_type(addr);
|
||||
(
|
||||
BoundKind::Get {
|
||||
addr,
|
||||
@@ -306,12 +299,7 @@ impl TypeChecker {
|
||||
BoundKind::Set { addr, value } => {
|
||||
let val_typed = self.check_node(*value, ctx)?;
|
||||
let ty = val_typed.ty.clone();
|
||||
|
||||
if let Address::Local(idx) = addr {
|
||||
ctx.set_local_type(idx, ty.clone());
|
||||
} else if let Address::Global(idx) = addr {
|
||||
self.global_types.borrow_mut().insert(idx, ty.clone());
|
||||
}
|
||||
ctx.set_type(addr, ty.clone());
|
||||
|
||||
(
|
||||
BoundKind::Set {
|
||||
@@ -394,7 +382,8 @@ impl TypeChecker {
|
||||
}
|
||||
|
||||
// 2. Create nested context for lambda body
|
||||
let mut lambda_ctx = TypeContext::new(64, upvalue_types, Some(ctx));
|
||||
let mut lambda_ctx =
|
||||
TypeContext::new(64, upvalue_types, ctx.global_types, Some(ctx));
|
||||
|
||||
// 3. Check parameters and body
|
||||
let params_typed =
|
||||
|
||||
Reference in New Issue
Block a user