...
This commit is contained in:
@@ -775,7 +775,7 @@ pub const CodeGen = struct {
|
||||
},
|
||||
.vector_type, .array_type => self.allocaStoreAsI64(self.typeToLLVM(ty), val, "any_vec"),
|
||||
.slice_type => self.allocaStoreAsI64(self.getStringStructType(), val, "any_slice"),
|
||||
.pointer_type, .many_pointer_type => self.ptrToInt(val, "any_ptr"),
|
||||
.pointer_type, .many_pointer_type, .function_type => self.ptrToInt(val, "any_ptr"),
|
||||
.meta_type => |mt| self.allocaStoreAsI64(self.getStringStructType(), self.buildStringSlice(val, self.constInt64(mt.name.len)), "any_type"),
|
||||
else => self.sExt(val, i64_ty, "any_val"),
|
||||
};
|
||||
@@ -3299,8 +3299,27 @@ pub const CodeGen = struct {
|
||||
fn genFieldAssignment(self: *CodeGen, asgn: ast.Assignment) !c.LLVMValueRef {
|
||||
const fa = asgn.target.data.field_access;
|
||||
|
||||
// Object must be an identifier for now
|
||||
if (fa.object.data != .identifier) return self.emitError("field assignment target must be a variable");
|
||||
// Non-identifier object (e.g. a.first.next = val — chained pointer field assignment)
|
||||
if (fa.object.data != .identifier) {
|
||||
const obj_ty = self.inferType(fa.object);
|
||||
if (obj_ty.isPointer()) {
|
||||
// Chained pointer auto-deref: expr.field = val where expr is *Struct
|
||||
const pointee_ty = self.resolveTypeFromName(obj_ty.pointer_type.pointee_name) orelse
|
||||
return self.emitError("unknown pointee type for chained field assignment");
|
||||
if (pointee_ty.isStruct()) {
|
||||
const sname = pointee_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 ptr_val = try self.genExpr(fa.object);
|
||||
const gep = self.structGEP(info.llvm_type, ptr_val, @intCast(fi), "chain_pfield_ptr");
|
||||
const rhs = try self.genExprAsType(asgn.value, field_ty);
|
||||
self.storeOrCompound(asgn.op, gep, rhs, field_ty, "chain_pcur");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return self.emitError("field assignment target must be a variable");
|
||||
}
|
||||
const obj_name = fa.object.data.identifier.name;
|
||||
const entry = self.getNamedOrGlobal(obj_name) orelse return self.emitErrorFmt("undefined variable '{s}'", .{obj_name});
|
||||
|
||||
@@ -3970,6 +3989,14 @@ pub const CodeGen = struct {
|
||||
return;
|
||||
}
|
||||
|
||||
// Forward declaration: register name early so self-referential *T works
|
||||
try self.type_registry.put(sd.name, .{ .struct_info = .{
|
||||
.field_names = &.{},
|
||||
.field_types = &.{},
|
||||
.field_defaults = &.{},
|
||||
.llvm_type = null,
|
||||
} });
|
||||
|
||||
// Pre-pass: hoist inline type declarations from field types
|
||||
for (sd.field_types, 0..) |ft, i| {
|
||||
try self.hoistInlineTypeDecl(sd.name, sd.field_names[i], ft);
|
||||
@@ -4008,6 +4035,15 @@ pub const CodeGen = struct {
|
||||
}
|
||||
|
||||
fn registerTaggedEnum(self: *CodeGen, ud: ast.EnumDecl) !void {
|
||||
// Forward declaration: register name early so self-referential *T works
|
||||
try self.type_registry.put(ud.name, .{ .tagged_enum = .{
|
||||
.variant_names = &.{},
|
||||
.variant_types = &.{},
|
||||
.llvm_type = null,
|
||||
.max_payload_size = 0,
|
||||
.payload_field_index = 0,
|
||||
} });
|
||||
|
||||
// Pre-pass: hoist inline type declarations from variant types
|
||||
for (ud.variant_types, 0..) |vt_opt, i| {
|
||||
if (vt_opt) |vt| {
|
||||
@@ -4189,6 +4225,15 @@ pub const CodeGen = struct {
|
||||
}
|
||||
|
||||
fn registerUnionType(self: *CodeGen, ud: ast.UnionDecl) !void {
|
||||
// Forward declaration: register name early so self-referential *T works
|
||||
try self.type_registry.put(ud.name, .{ .union_info = .{
|
||||
.field_names = &.{},
|
||||
.field_types = &.{},
|
||||
.llvm_type = null,
|
||||
.total_size = 0,
|
||||
.promoted_fields = std.StringHashMap(PromotedField).init(self.allocator),
|
||||
} });
|
||||
|
||||
// Hoist inline type declarations from field types
|
||||
for (ud.field_types, 0..) |ft, i| {
|
||||
try self.hoistInlineTypeDecl(ud.name, ud.field_names[i], ft);
|
||||
@@ -5524,6 +5569,24 @@ pub const CodeGen = struct {
|
||||
// Non-identifier object: evaluate expression and check type
|
||||
const obj_val = try self.genExpr(fa.object);
|
||||
const obj_ty = self.inferType(fa.object);
|
||||
// Pointer auto-deref: expr.field where expr is *T → load through pointer
|
||||
if (obj_ty.isPointer()) {
|
||||
const pointee_ty = self.resolveTypeFromName(obj_ty.pointer_type.pointee_name) orelse
|
||||
return self.emitError("unknown pointee type for auto-deref");
|
||||
if (pointee_ty.isStruct()) {
|
||||
const sname = pointee_ty.struct_type;
|
||||
const info = try self.getStructInfo(sname);
|
||||
const idx = self.findNameIndex(info.field_names, fa.field) orelse
|
||||
return self.emitErrorFmt("no field '{s}' in struct '{s}'", .{ fa.field, sname });
|
||||
const gep = self.structGEP(info.llvm_type, obj_val, @intCast(idx), "pfield");
|
||||
return self.loadTyped(info.field_types[idx], gep, "pfieldval");
|
||||
}
|
||||
if (pointee_ty.isSlice()) {
|
||||
const slice_val = c.LLVMBuildLoad2(self.builder, self.getStringStructType(), obj_val, "pslice_load");
|
||||
return self.extractFatPtrField(slice_val, fa.field, "*slice");
|
||||
}
|
||||
return self.emitErrorFmt("no field '{s}' on pointer", .{fa.field});
|
||||
}
|
||||
if (obj_ty.isVector()) {
|
||||
return self.genVectorExtract(obj_val, fa.field);
|
||||
}
|
||||
|
||||
@@ -1122,9 +1122,9 @@ pub const VM = struct {
|
||||
alloc_field_names[0] = "ctx";
|
||||
alloc_field_names[1] = "alloc";
|
||||
alloc_field_names[2] = "free";
|
||||
alloc_fields[0] = .{ .int_val = 0 }; // null ctx pointer
|
||||
alloc_fields[1] = .{ .int_val = 0 }; // null alloc
|
||||
alloc_fields[2] = .{ .int_val = 0 }; // null free
|
||||
alloc_fields[0] = .{ .null_val = {} }; // null ctx pointer
|
||||
alloc_fields[1] = .{ .null_val = {} }; // null alloc
|
||||
alloc_fields[2] = .{ .null_val = {} }; // null free
|
||||
|
||||
const ctx_fields = try self.allocator.alloc(Value, 2);
|
||||
const ctx_field_names = try self.allocator.alloc([]const u8, 2);
|
||||
@@ -1771,8 +1771,10 @@ pub const VM = struct {
|
||||
if (a == .int_val and b == .int_val) return a.int_val == b.int_val;
|
||||
if (a == .bool_val and b == .bool_val) return a.bool_val == b.bool_val;
|
||||
if (a == .string_val and b == .string_val) return std.mem.eql(u8, a.string_val, b.string_val);
|
||||
// Pointer comparison
|
||||
// Pointer comparison (null_val == int_val(0) for null pointer compatibility)
|
||||
if (a == .null_val and b == .null_val) return true;
|
||||
if (a == .null_val and b == .int_val) return b.int_val == 0;
|
||||
if (a == .int_val and b == .null_val) return a.int_val == 0;
|
||||
if (a == .null_val or b == .null_val) return false;
|
||||
if (a == .pointer_val and b == .pointer_val) return a.pointer_val.target == b.pointer_val.target;
|
||||
// Float comparison
|
||||
|
||||
@@ -197,7 +197,7 @@ pub const DocumentStore = struct {
|
||||
.ty = sym.ty,
|
||||
.def_span = sym.def_span,
|
||||
.scope_depth = 0,
|
||||
.origin = file_path,
|
||||
.origin = sym.origin orelse file_path,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -263,7 +263,7 @@ pub const DocumentStore = struct {
|
||||
.ty = sym.ty,
|
||||
.def_span = sym.def_span,
|
||||
.scope_depth = 0,
|
||||
.origin = imp.path,
|
||||
.origin = sym.origin orelse imp.path,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,6 +555,8 @@ pub const Analyzer = struct {
|
||||
for (indices.items) |idx| {
|
||||
if (idx >= scope_start) {
|
||||
const sym = self.symbols.items[idx];
|
||||
// Skip imported symbols — local declarations are allowed to shadow them
|
||||
if (sym.origin != null) continue;
|
||||
if (sym.scope_depth == self.scope_depth) {
|
||||
try self.diagnostics.append(self.allocator, .{
|
||||
.level = .warn,
|
||||
|
||||
@@ -531,6 +531,9 @@ pub const Type = union(enum) {
|
||||
return Type.s(capped);
|
||||
}
|
||||
|
||||
// Pointer types: both are pointers → return first (all are opaque ptr at LLVM level)
|
||||
if ((a.isPointer() or a.isManyPointer()) and (b.isPointer() or b.isManyPointer())) return a;
|
||||
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user