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:
Michael Schimmel
2026-02-25 11:14:19 +01:00
parent 6034216524
commit d109cb2018
+29 -40
View File
@@ -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 =