From 630e76c3194c3cc3276a740b75e5036171623ea0 Mon Sep 17 00:00:00 2001 From: agra Date: Tue, 24 Feb 2026 17:42:13 +0200 Subject: [PATCH] chained dereference --- src/codegen.zig | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/codegen.zig b/src/codegen.zig index 5f948fe..e877d53 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -3912,7 +3912,7 @@ pub const CodeGen = struct { fn genFieldAssignment(self: *CodeGen, asgn: ast.Assignment) !c.LLVMValueRef { const fa = asgn.target.data.field_access; - // Non-identifier object (e.g. a.first.next = val — chained pointer field assignment) + // Non-identifier object (e.g. a.b.c = val — chained field assignment) if (fa.object.data != .identifier) { const obj_ty = self.inferType(fa.object); if (obj_ty.isPointer()) { @@ -3931,6 +3931,18 @@ pub const CodeGen = struct { return null; } } + if (obj_ty.isStruct()) { + // Chained struct field: expr.field = val where expr is a struct (e.g. self.inner.len = 0) + const sname = obj_ty.struct_type; + const info = try self.getStructInfo(sname); + const fi = try self.findFieldIndex(info.field_names, fa.field, sname); + const field_ty = info.field_types[fi]; + const intermediate_ptr = try self.genAddressOf(fa.object); + const gep = self.structGEP(info.llvm_type, intermediate_ptr, @intCast(fi), "chain_sfield_ptr"); + const rhs = try self.genExprAsType(asgn.value, field_ty); + self.storeOrCompound(asgn.op, gep, rhs, field_ty, "chain_scur"); + return null; + } return self.emitError("field assignment target must be a variable"); } const obj_name = fa.object.data.identifier.name; @@ -4604,6 +4616,25 @@ pub const CodeGen = struct { } } } + } else { + // Chained field access: a.b.c — recursively get address of intermediate + const intermediate_ptr = try self.genAddressOf(fa.object); + const obj_ty = self.inferType(fa.object); + if (obj_ty.isStruct()) { + const sname = obj_ty.struct_type; + const info = try self.getStructInfo(sname); + const idx = try self.findFieldIndex(info.field_names, fa.field, sname); + return self.structGEP(info.llvm_type, intermediate_ptr, @intCast(idx), "addr_chain_field"); + } + if (obj_ty.isPointer()) { + const pointee_name = obj_ty.pointer_type.pointee_name; + if (self.lookupStructInfo(pointee_name)) |info| { + const loaded_ptr = c.LLVMBuildLoad2(self.builder, + self.ptrType(), intermediate_ptr, "chain_ptr_load"); + const idx = try self.findFieldIndex(info.field_names, fa.field, pointee_name); + return self.structGEP(info.llvm_type, loaded_ptr, @intCast(idx), "addr_chain_pfield"); + } + } } } return self.emitError("address-of requires a variable, index, or field expression");