Skip to content

Commit 651981b

Browse files
committed
fix: Add variable type inference for struct initializers
- Add variable_types HashMap to TypedAstBuilder to track declared variable types - Update create_var_decl to infer type from initializer expression and register it - Update create_variable to look up registered type for proper variable references - Update create_field_access to infer field type from object's struct type This enables proper type propagation for struct field access through variables: const p = Point{ .x = 10, .y = 20 }; return p.x; // Now correctly returns 10
1 parent 857cbc1 commit 651981b

1 file changed

Lines changed: 31 additions & 3 deletions

File tree

crates/zyn_peg/src/runtime.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,8 @@ pub struct TypedAstBuilder {
848848
variants: HashMap<NodeHandle, TypedVariant>,
849849
/// Stored struct field initializers (name, value) by handle
850850
struct_field_inits: HashMap<NodeHandle, (String, NodeHandle)>,
851+
/// Variable name to type mapping (for proper variable references)
852+
variable_types: HashMap<String, Type>,
851853
/// Program declaration handles (in order)
852854
program_decls: Vec<NodeHandle>,
853855
}
@@ -870,6 +872,7 @@ impl TypedAstBuilder {
870872
fields: HashMap::new(),
871873
variants: HashMap::new(),
872874
struct_field_inits: HashMap::new(),
875+
variable_types: HashMap::new(),
873876
program_decls: Vec::new(),
874877
}
875878
}
@@ -1148,7 +1151,20 @@ impl AstHostFunctions for TypedAstBuilder {
11481151
let object_expr = self.get_expr(object)
11491152
.unwrap_or_else(|| self.inner.variable("object", Type::Primitive(PrimitiveType::I32), span));
11501153

1151-
let expr = self.inner.field_access(object_expr, field, Type::Primitive(PrimitiveType::I32), span);
1154+
// Infer field type from object's struct type
1155+
let field_type = match &object_expr.ty {
1156+
Type::Struct { fields, .. } => {
1157+
// Find the field by name and get its type
1158+
let field_name = InternedString::new_global(field);
1159+
fields.iter()
1160+
.find(|f| f.name == field_name)
1161+
.map(|f| f.ty.clone())
1162+
.unwrap_or(Type::Primitive(PrimitiveType::I32))
1163+
}
1164+
_ => Type::Primitive(PrimitiveType::I32),
1165+
};
1166+
1167+
let expr = self.inner.field_access(object_expr, field, field_type, span);
11521168
self.store_expr(expr)
11531169
}
11541170

@@ -1164,9 +1180,17 @@ impl AstHostFunctions for TypedAstBuilder {
11641180
let init_expr = init.and_then(|h| self.get_expr(h));
11651181
let mutability = if is_const { Mutability::Immutable } else { Mutability::Mutable };
11661182

1183+
// Infer type from initializer expression if available
1184+
let var_type = init_expr.as_ref()
1185+
.map(|expr| expr.ty.clone())
1186+
.unwrap_or(Type::Primitive(PrimitiveType::I32));
1187+
1188+
// Register the variable type for later lookup
1189+
self.variable_types.insert(name.to_string(), var_type.clone());
1190+
11671191
let stmt = self.inner.let_statement(
11681192
name,
1169-
Type::Primitive(PrimitiveType::I32),
1193+
var_type,
11701194
mutability,
11711195
init_expr,
11721196
span,
@@ -1494,7 +1518,11 @@ impl AstHostFunctions for TypedAstBuilder {
14941518

14951519
fn create_variable(&mut self, name: &str) -> NodeHandle {
14961520
let span = self.default_span();
1497-
let expr = self.inner.variable(name, Type::Primitive(PrimitiveType::I32), span);
1521+
// Look up the variable's declared type, default to I32 if not found
1522+
let var_type = self.variable_types.get(name)
1523+
.cloned()
1524+
.unwrap_or(Type::Primitive(PrimitiveType::I32));
1525+
let expr = self.inner.variable(name, var_type, span);
14981526
self.store_expr(expr)
14991527
}
15001528

0 commit comments

Comments
 (0)