Skip to content

Commit

Permalink
fix: Anonymous object with fields in different order were not equal
Browse files Browse the repository at this point in the history
We now sort fields by their name so that indexes don't change regardless of their order in the code
  • Loading branch information
giann committed Sep 20, 2024
1 parent c287fc7 commit 6621857
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4103,6 +4103,8 @@ fn anonymousObjectInit(self: *Self, _: bool) Error!Ast.Node.Index {
}
}

try object_type.resolved_type.?.Object.sortFieldIndexes(self.gc.allocator);

try self.consume(.RightBrace, "Expected `}` after object initialization.");

return try self.ast.appendNode(
Expand Down Expand Up @@ -6648,6 +6650,8 @@ fn objectDeclaration(self: *Self) Error!Ast.Node.Index {
}
}

try object_type.resolved_type.?.Object.sortFieldIndexes(self.gc.allocator);

try self.consume(.RightBrace, "Expected `}` after object body.");

const scope_end = try self.endScope();
Expand Down
48 changes: 48 additions & 0 deletions src/obj.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,54 @@ pub const ObjObject = struct {
};
}

fn compareStrings(_: void, lhs: []const u8, rhs: []const u8) bool {
return std.mem.order(u8, lhs, rhs).compare(std.math.CompareOperator.lt);
}

// Anonymous object can have the same fields but in a different order
// This function will sort them by name and fix their index accordingly
pub fn sortFieldIndexes(self: *ObjectDef, allocator: Allocator) !void {
// Don't do anything on regular objects
if (!self.anonymous) {
return;
}

const fields = try allocator.alloc(
[]const u8,
self.fields.keys().len,
);
defer allocator.free(fields);
std.mem.copyForwards(
[]const u8,
fields,
self.fields.keys(),
);

std.mem.sort(
[]const u8,
fields,
{},
compareStrings,
);

for (fields, 0..) |field_name, index| {
const original_field = self.fields.get(field_name).?;
try self.fields.put(
field_name,
.{
.name = original_field.name,
.type_def = original_field.type_def,
.constant = original_field.constant,
.method = original_field.method,
.static = original_field.static,
.location = original_field.location,
.has_default = original_field.has_default,
.index = index,
},
);
}
}

pub fn deinit(self: *ObjectDef) void {
self.fields.deinit();
self.placeholders.deinit();
Expand Down

0 comments on commit 6621857

Please sign in to comment.