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>, slots: Vec<StaticType>,
/// Types of captured variables (passed from outer scope) /// Types of captured variables (passed from outer scope)
upvalue_types: Vec<StaticType>, 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) /// The expected parameters of the current function (for 'again' validation)
current_params_ty: Option<StaticType>, current_params_ty: Option<StaticType>,
} }
@@ -19,12 +21,14 @@ impl<'a> TypeContext<'a> {
fn new( fn new(
slot_count: u32, slot_count: u32,
upvalue_types: Vec<StaticType>, upvalue_types: Vec<StaticType>,
global_types: &'a std::cell::RefCell<HashMap<u32, StaticType>>,
parent: Option<&'a TypeContext<'a>>, parent: Option<&'a TypeContext<'a>>,
) -> Self { ) -> Self {
Self { Self {
_parent: parent, _parent: parent,
slots: vec![StaticType::Any; slot_count as usize], slots: vec![StaticType::Any; slot_count as usize],
upvalue_types, upvalue_types,
global_types,
current_params_ty: None, current_params_ty: None,
} }
} }
@@ -36,7 +40,12 @@ impl<'a> TypeContext<'a> {
.get(idx as usize) .get(idx as usize)
.cloned() .cloned()
.unwrap_or(StaticType::Any), .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 Address::Upvalue(idx) => self
.upvalue_types .upvalue_types
.get(idx as usize) .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) { if let Some(slot) = self.slots.get_mut(idx as usize) {
*slot = ty; *slot = ty;
} }
} }
Address::Global(idx) => {
self.global_types.borrow_mut().insert(idx, ty);
}
_ => {}
}
}
} }
pub struct TypeChecker { pub struct TypeChecker {
@@ -76,8 +93,9 @@ impl TypeChecker {
} }
// 2. Create the specialized context // 2. Create the specialized context
let root_ctx = TypeContext::new(0, vec![], None); let root_ctx = TypeContext::new(0, vec![], &self.global_types, None);
let mut lambda_ctx = TypeContext::new(64, upvalue_types, Some(&root_ctx)); let mut lambda_ctx =
TypeContext::new(64, upvalue_types, &self.global_types, Some(&root_ctx));
// 3. INJECT specialized argument types into slots // 3. INJECT specialized argument types into slots
let arg_tuple_ty = if arg_types.is_empty() { let arg_tuple_ty = if arg_types.is_empty() {
@@ -147,15 +165,7 @@ impl TypeChecker {
captured_by, captured_by,
.. ..
} => { } => {
match addr { ctx.set_type(addr, specialized_ty.clone());
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());
}
_ => {}
}
( (
BoundKind::Define { BoundKind::Define {
name, name,
@@ -261,20 +271,11 @@ impl TypeChecker {
} => { } => {
let val_typed = self.check_node(*value, ctx)?; let val_typed = self.check_node(*value, ctx)?;
let ty = val_typed.ty.clone(); let ty = val_typed.ty.clone();
ctx.set_type(addr, 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());
}
_ => {}
}
( (
BoundKind::Define { BoundKind::Define {
name, name: name.clone(),
addr, addr,
kind: decl_kind, kind: decl_kind,
value: Box::new(val_typed), value: Box::new(val_typed),
@@ -285,15 +286,7 @@ impl TypeChecker {
} }
BoundKind::Get { addr, name } => { BoundKind::Get { addr, name } => {
let ty = if let Address::Global(idx) = addr { let ty = ctx.get_type(addr);
self.global_types
.borrow()
.get(&idx)
.cloned()
.unwrap_or(StaticType::Any)
} else {
ctx.get_type(addr)
};
( (
BoundKind::Get { BoundKind::Get {
addr, addr,
@@ -306,12 +299,7 @@ impl TypeChecker {
BoundKind::Set { addr, value } => { BoundKind::Set { addr, value } => {
let val_typed = self.check_node(*value, ctx)?; let val_typed = self.check_node(*value, ctx)?;
let ty = val_typed.ty.clone(); let ty = val_typed.ty.clone();
ctx.set_type(addr, 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());
}
( (
BoundKind::Set { BoundKind::Set {
@@ -394,7 +382,8 @@ impl TypeChecker {
} }
// 2. Create nested context for lambda body // 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 // 3. Check parameters and body
let params_typed = let params_typed =