authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-16 01:45:41+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-21 01:41:50+01:00
logcd733ceb852369427301fbb526b82ad4407d0607
tree9673ab520b07e73650be9038b7db62c628795e42
parentea913846c2d45a6e4862d5eaf94773ea880bfeab

stage2: replace ErrorSet and ErrorSetMerged arrays with hash maps


3 files changed, 55 insertions(+), 87 deletions(-)

src/Module.zig+2-6
...@@ -796,15 +796,11 @@ pub const ErrorSet = struct {...@@ -796,15 +796,11 @@ pub const ErrorSet = struct {
796 owner_decl: *Decl,796 owner_decl: *Decl,
797 /// Offset from Decl node index, points to the error set AST node.797 /// Offset from Decl node index, points to the error set AST node.
798 node_offset: i32,798 node_offset: i32,
799 names_len: u32,
800 /// The string bytes are stored in the owner Decl arena.799 /// The string bytes are stored in the owner Decl arena.
801 /// They are in the same order they appear in the AST.800 /// They are in the same order they appear in the AST.
802 /// The length is given by `names_len`.801 names: NameMap,
803 names_ptr: [*]const []const u8,
804802
805 pub fn names(self: ErrorSet) []const []const u8 {803 pub const NameMap = std.StringArrayHashMapUnmanaged(void);
806 return self.names_ptr[0..self.names_len];
807 }
808804
809 pub fn srcLoc(self: ErrorSet) SrcLoc {805 pub fn srcLoc(self: ErrorSet) SrcLoc {
810 return .{806 return .{
src/Sema.zig+44-73
...@@ -2025,15 +2025,22 @@ fn zirErrorSetDecl(...@@ -2025,15 +2025,22 @@ fn zirErrorSetDecl(
2025 }, type_name);2025 }, type_name);
2026 new_decl.owns_tv = true;2026 new_decl.owns_tv = true;
2027 errdefer sema.mod.abortAnonDecl(new_decl);2027 errdefer sema.mod.abortAnonDecl(new_decl);
2028 const names = try new_decl_arena_allocator.alloc([]const u8, fields.len);2028
2029 for (fields) |str_index, i| {2029 var names = Module.ErrorSet.NameMap{};
2030 names[i] = try new_decl_arena_allocator.dupe(u8, sema.code.nullTerminatedString(str_index));2030 try names.ensureUnusedCapacity(new_decl_arena_allocator, fields.len);
2031 for (fields) |str_index| {
2032 const name = try new_decl_arena_allocator.dupe(u8, sema.code.nullTerminatedString(str_index));
2033
2034 // TODO: This check should be performed in AstGen instead.
2035 const result = names.getOrPutAssumeCapacity(name);
2036 if (result.found_existing) {
2037 return sema.fail(block, src, "duplicate error set field {s}", .{name});
2038 }
2031 }2039 }
2032 error_set.* = .{2040 error_set.* = .{
2033 .owner_decl = new_decl,2041 .owner_decl = new_decl,
2034 .node_offset = inst_data.src_node,2042 .node_offset = inst_data.src_node,
2035 .names_ptr = names.ptr,2043 .names = names,
2036 .names_len = @intCast(u32, names.len),
2037 };2044 };
2038 try new_decl.finalizeNewArena(&new_decl_arena);2045 try new_decl.finalizeNewArena(&new_decl_arena);
2039 return sema.analyzeDeclVal(block, src, new_decl);2046 return sema.analyzeDeclVal(block, src, new_decl);
...@@ -4556,63 +4563,43 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -4556,63 +4563,43 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
4556 return Air.Inst.Ref.anyerror_type;4563 return Air.Inst.Ref.anyerror_type;
4557 }4564 }
4558 // Resolve both error sets now.4565 // Resolve both error sets now.
4559 var set: std.StringHashMapUnmanaged(void) = .{};4566 const lhs_names = switch (lhs_ty.tag()) {
4560 defer set.deinit(sema.gpa);4567 .error_set_single => blk: {
45614568 // Work around coercion problems
4562 switch (lhs_ty.tag()) {4569 const tmp: *const [1][]const u8 = &lhs_ty.castTag(.error_set_single).?.data;
4563 .error_set_single => {4570 break :blk tmp;
4564 const name = lhs_ty.castTag(.error_set_single).?.data;
4565 try set.put(sema.gpa, name, {});
4566 },
4567 .error_set_merged => {
4568 const names = lhs_ty.castTag(.error_set_merged).?.data;
4569 for (names) |name| {
4570 try set.put(sema.gpa, name, {});
4571 }
4572 },
4573 .error_set => {
4574 const lhs_set = lhs_ty.castTag(.error_set).?.data;
4575 try set.ensureUnusedCapacity(sema.gpa, lhs_set.names_len);
4576 for (lhs_set.names_ptr[0..lhs_set.names_len]) |name| {
4577 set.putAssumeCapacityNoClobber(name, {});
4578 }
4579 },4571 },
4572 .error_set_merged => lhs_ty.castTag(.error_set_merged).?.data.keys(),
4573 .error_set => lhs_ty.castTag(.error_set).?.data.names.keys(),
4580 else => unreachable,4574 else => unreachable,
4581 }4575 };
4582 switch (rhs_ty.tag()) {4576
4583 .error_set_single => {4577 const rhs_names = switch (rhs_ty.tag()) {
4584 const name = rhs_ty.castTag(.error_set_single).?.data;4578 .error_set_single => blk: {
4585 try set.put(sema.gpa, name, {});4579 const tmp: *const [1][]const u8 = &rhs_ty.castTag(.error_set_single).?.data;
4586 },4580 break :blk tmp;
4587 .error_set_merged => {
4588 const names = rhs_ty.castTag(.error_set_merged).?.data;
4589 for (names) |name| {
4590 try set.put(sema.gpa, name, {});
4591 }
4592 },
4593 .error_set => {
4594 const rhs_set = rhs_ty.castTag(.error_set).?.data;
4595 try set.ensureUnusedCapacity(sema.gpa, rhs_set.names_len);
4596 for (rhs_set.names_ptr[0..rhs_set.names_len]) |name| {
4597 set.putAssumeCapacity(name, {});
4598 }
4599 },4581 },
4582 .error_set_merged => rhs_ty.castTag(.error_set_merged).?.data.keys(),
4583 .error_set => rhs_ty.castTag(.error_set).?.data.names.keys(),
4600 else => unreachable,4584 else => unreachable,
4601 }4585 };
46024586
4603 // TODO do we really want to create a Decl for this?4587 // TODO do we really want to create a Decl for this?
4604 // The reason we do it right now is for memory management.4588 // The reason we do it right now is for memory management.
4605 var anon_decl = try block.startAnonDecl();4589 var anon_decl = try block.startAnonDecl();
4606 defer anon_decl.deinit();4590 defer anon_decl.deinit();
46074591
4608 const new_names = try anon_decl.arena().alloc([]const u8, set.count());4592 var names = Module.ErrorSet.NameMap{};
4609 var it = set.keyIterator();4593 // TODO: Guess is an upper bound, but maybe this needs to be reduced by computing the exact size first.
4610 var i: usize = 0;4594 try names.ensureUnusedCapacity(anon_decl.arena(), @intCast(u32, lhs_names.len + rhs_names.len));
4611 while (it.next()) |key| : (i += 1) {4595 for (lhs_names) |name| {
4612 new_names[i] = key.*;4596 names.putAssumeCapacityNoClobber(name, {});
4597 }
4598 for (rhs_names) |name| {
4599 names.putAssumeCapacity(name, {});
4613 }4600 }
46144601
4615 const err_set_ty = try Type.Tag.error_set_merged.create(anon_decl.arena(), new_names);4602 const err_set_ty = try Type.Tag.error_set_merged.create(anon_decl.arena(), names);
4616 const err_set_decl = try anon_decl.finish(4603 const err_set_decl = try anon_decl.finish(
4617 Type.type,4604 Type.type,
4618 try Value.Tag.ty.create(anon_decl.arena(), err_set_ty),4605 try Value.Tag.ty.create(anon_decl.arena(), err_set_ty),
...@@ -11425,14 +11412,8 @@ fn fieldVal(...@@ -11425,14 +11412,8 @@ fn fieldVal(
11425 switch (child_type.zigTypeTag()) {11412 switch (child_type.zigTypeTag()) {
11426 .ErrorSet => {11413 .ErrorSet => {
11427 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {11414 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
11428 const error_set = payload.data;11415 if (payload.data.names.getEntry(field_name)) |entry| {
11429 // TODO this is O(N). I'm putting off solving this until we solve inferred11416 break :blk entry.key_ptr.*;
11430 // error sets at the same time.
11431 const names = error_set.names_ptr[0..error_set.names_len];
11432 for (names) |name| {
11433 if (mem.eql(u8, field_name, name)) {
11434 break :blk name;
11435 }
11436 }11417 }
11437 return sema.fail(block, src, "no error named '{s}' in '{}'", .{11418 return sema.fail(block, src, "no error named '{s}' in '{}'", .{
11438 field_name, child_type,11419 field_name, child_type,
...@@ -11630,14 +11611,8 @@ fn fieldPtr(...@@ -11630,14 +11611,8 @@ fn fieldPtr(
11630 .ErrorSet => {11611 .ErrorSet => {
11631 // TODO resolve inferred error sets11612 // TODO resolve inferred error sets
11632 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {11613 const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
11633 const error_set = payload.data;11614 if (payload.data.names.getEntry(field_name)) |entry| {
11634 // TODO this is O(N). I'm putting off solving this until we solve inferred11615 break :blk entry.key_ptr.*;
11635 // error sets at the same time.
11636 const names = error_set.names_ptr[0..error_set.names_len];
11637 for (names) |name| {
11638 if (mem.eql(u8, field_name, name)) {
11639 break :blk name;
11640 }
11641 }11616 }
11642 return sema.fail(block, src, "no error named '{s}' in '{}'", .{11617 return sema.fail(block, src, "no error named '{s}' in '{}'", .{
11643 field_name, child_type,11618 field_name, child_type,
...@@ -13916,16 +13891,12 @@ fn wrapErrorUnion(...@@ -13916,16 +13891,12 @@ fn wrapErrorUnion(
13916 if (mem.eql(u8, expected_name, n)) break :ok;13891 if (mem.eql(u8, expected_name, n)) break :ok;
13917 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);13892 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13918 },13893 },
13919 .error_set => ok: {13894 .error_set => {
13920 const expected_name = val.castTag(.@"error").?.data.name;13895 const expected_name = val.castTag(.@"error").?.data.name;
13921 const error_set = dest_err_set_ty.castTag(.error_set).?.data;13896 const error_set = dest_err_set_ty.castTag(.error_set).?.data;
13922 const names = error_set.names_ptr[0..error_set.names_len];13897 if (!error_set.names.contains(expected_name)) {
13923 // TODO this is O(N). I'm putting off solving this until we solve inferred13898 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13924 // error sets at the same time.
13925 for (names) |name| {
13926 if (mem.eql(u8, expected_name, name)) break :ok;
13927 }13899 }
13928 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13929 },13900 },
13930 .error_set_inferred => ok: {13901 .error_set_inferred => ok: {
13931 const err_set_payload = dest_err_set_ty.castTag(.error_set_inferred).?.data;13902 const err_set_payload = dest_err_set_ty.castTag(.error_set_inferred).?.data;
src/type.zig+9-8
...@@ -904,10 +904,11 @@ pub const Type = extern union {...@@ -904,10 +904,11 @@ pub const Type = extern union {
904 });904 });
905 },905 },
906 .error_set_merged => {906 .error_set_merged => {
907 const names = self.castTag(.error_set_merged).?.data;907 const names = self.castTag(.error_set_merged).?.data.keys();
908 const duped_names = try allocator.alloc([]const u8, names.len);908 var duped_names = Module.ErrorSet.NameMap{};
909 for (duped_names) |*name, i| {909 try duped_names.ensureTotalCapacity(allocator, names.len);
910 name.* = try allocator.dupe(u8, names[i]);910 for (names) |name| {
911 duped_names.putAssumeCapacityNoClobber(name, .{});
911 }912 }
912 return Tag.error_set_merged.create(allocator, duped_names);913 return Tag.error_set_merged.create(allocator, duped_names);
913 },914 },
...@@ -1206,7 +1207,7 @@ pub const Type = extern union {...@@ -1206,7 +1207,7 @@ pub const Type = extern union {
1206 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});1207 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
1207 },1208 },
1208 .error_set_merged => {1209 .error_set_merged => {
1209 const names = ty.castTag(.error_set_merged).?.data;1210 const names = ty.castTag(.error_set_merged).?.data.keys();
1210 try writer.writeAll("error{");1211 try writer.writeAll("error{");
1211 for (names) |name, i| {1212 for (names) |name, i| {
1212 if (i != 0) try writer.writeByte(',');1213 if (i != 0) try writer.writeByte(',');
...@@ -4148,7 +4149,7 @@ pub const Type = extern union {...@@ -4148,7 +4149,7 @@ pub const Type = extern union {
4148 pub const base_tag = Tag.error_set_merged;4149 pub const base_tag = Tag.error_set_merged;
41494150
4150 base: Payload = Payload{ .tag = base_tag },4151 base: Payload = Payload{ .tag = base_tag },
4151 data: []const []const u8,4152 data: Module.ErrorSet.NameMap,
4152 };4153 };
41534154
4154 pub const ErrorSetInferred = struct {4155 pub const ErrorSetInferred = struct {
...@@ -4168,7 +4169,7 @@ pub const Type = extern union {...@@ -4168,7 +4169,7 @@ pub const Type = extern union {
4168 pub fn addErrorSet(self: *Data, gpa: Allocator, err_set_ty: Type) !void {4169 pub fn addErrorSet(self: *Data, gpa: Allocator, err_set_ty: Type) !void {
4169 switch (err_set_ty.tag()) {4170 switch (err_set_ty.tag()) {
4170 .error_set => {4171 .error_set => {
4171 const names = err_set_ty.castTag(.error_set).?.data.names();4172 const names = err_set_ty.castTag(.error_set).?.data.names.keys();
4172 for (names) |name| {4173 for (names) |name| {
4173 try self.map.put(gpa, name, {});4174 try self.map.put(gpa, name, {});
4174 }4175 }
...@@ -4187,7 +4188,7 @@ pub const Type = extern union {...@@ -4187,7 +4188,7 @@ pub const Type = extern union {
4187 }4188 }
4188 },4189 },
4189 .error_set_merged => {4190 .error_set_merged => {
4190 const names = err_set_ty.castTag(.error_set_merged).?.data;4191 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
4191 for (names) |name| {4192 for (names) |name| {
4192 try self.map.put(gpa, name, {});4193 try self.map.put(gpa, name, {});
4193 }4194 }