Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/analyser/InternPool.zig
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub const Key = union(enum) {
pub const ErrorSet = struct {
owner_decl: Decl.OptionalIndex,
names: StringSlice,
source_node: u32,
};

pub const Function = struct {
Expand Down Expand Up @@ -346,6 +347,7 @@ pub const Key = union(enum) {
.error_set_type => |error_set_type| {
std.hash.autoHash(hasher, error_set_type.owner_decl);
error_set_type.names.hashWithHasher(hasher, ip);
std.hash.autoHash(hasher, error_set_type.source_node);
},
.function_type => |function_type| {
std.hash.autoHash(hasher, function_type.args_is_comptime);
Expand Down Expand Up @@ -435,6 +437,7 @@ pub const Key = union(enum) {
const b_info = b.error_set_type;

if (a_info.owner_decl != b_info.owner_decl) return false;
if (a_info.source_node != b_info.source_node) return false;

if (a_info.names.len != b_info.names.len) return false;

Expand Down Expand Up @@ -3545,6 +3548,7 @@ pub fn errorSetMerge(ip: *InternPool, gpa: Allocator, a_ty: Index, b_ty: Index)
.error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, set.keys()),
.source_node = 0,
},
});
}
Expand Down Expand Up @@ -4543,16 +4547,19 @@ test "error set type" {
const empty_error_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = StringSlice.empty,
.source_node = 0,
} });

const foo_bar_baz_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{ foo_name, bar_name, baz_name }),
.source_node = 0,
} });

const foo_bar_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{ foo_name, bar_name }),
.source_node = 0,
} });

try expect(empty_error_set != foo_bar_baz_set);
Expand All @@ -4572,6 +4579,7 @@ test "error union type" {
const empty_error_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = StringSlice.empty,
.source_node = 0,
} });
const bool_type = try ip.get(gpa, .{ .simple_type = .bool });

Expand Down Expand Up @@ -4932,18 +4940,22 @@ test "coerceInMemoryAllowed error set" {
const foo_bar_baz_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{ baz_name, bar_name, foo_name }),
.source_node = 0,
} });
const foo_bar_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{ foo_name, bar_name }),
.source_node = 0,
} });
const foo_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{foo_name}),
.source_node = 0,
} });
const empty_set = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = StringSlice.empty,
.source_node = 0,
} });

try expect(try ip.coerceInMemoryAllowed(gpa, arena, .anyerror_type, foo_bar_baz_set, true, builtin.target) == .ok);
Expand Down Expand Up @@ -5224,21 +5236,25 @@ test "resolvePeerTypes error sets" {
const @"error{foo}" = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{foo_name}),
.source_node = 0,
} });

const @"error{bar}" = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{bar_name}),
.source_node = 0,
} });

const @"error{foo,bar}" = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{ foo_name, bar_name }),
.source_node = 0,
} });

const @"error{bar,foo}" = try ip.get(gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try ip.getStringSlice(gpa, &.{ bar_name, foo_name }),
.source_node = 0,
} });

try ip.testResolvePeerTypesInOrder(@"error{foo}", @"error{bar}", @"error{foo,bar}");
Expand Down
2 changes: 2 additions & 0 deletions src/analyser/degibberish.zig
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ test "degibberish - error union types" {
const @"error{foo,bar,baz}" = try ip.get(gpa, .{ .error_set_type = .{
.names = try ip.getStringSlice(gpa, &.{ foo_string, bar_string, baz_string }),
.owner_decl = .none,
.source_node = 0,
} });

const @"error{foo,bar,baz}!u32" = try ip.get(gpa, .{ .error_union_type = .{
Expand All @@ -226,6 +227,7 @@ test "degibberish - error set types" {
const @"error{foo,bar,baz}" = try ip.get(gpa, .{ .error_set_type = .{
.names = try ip.getStringSlice(gpa, &.{ foo_string, bar_string, baz_string }),
.owner_decl = .none,
.source_node = 0,
} });

try std.testing.expectFmt("error set of (foo,bar,baz)", "{f}", .{fmtDegibberish(&ip, @"error{foo,bar,baz}")});
Expand Down
56 changes: 55 additions & 1 deletion src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2125,7 +2125,11 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) error
try strings.append(analyser.gpa, index);
}
const names = try analyser.ip.getStringSlice(analyser.gpa, strings.items);
const ip_index = try analyser.ip.get(analyser.gpa, .{ .error_set_type = .{ .owner_decl = .none, .names = names } });
const ip_index = try analyser.ip.get(analyser.gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = names,
.source_node = @intFromEnum(node),
} });
return Type.fromIP(analyser, .type_type, ip_index);
},

Expand Down Expand Up @@ -2700,6 +2704,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) error
const error_set_type = try analyser.ip.get(analyser.gpa, .{ .error_set_type = .{
.owner_decl = .none,
.names = try analyser.ip.getStringSlice(analyser.gpa, &.{name_index}),
.source_node = 0,
} });
const error_value = try analyser.ip.get(analyser.gpa, .{ .error_value = .{
.ty = error_set_type,
Expand Down Expand Up @@ -4125,6 +4130,9 @@ pub const Type = struct {
return decl;
}
}
if (self.isErrorSetType(analyser)) {
return try self.lookupErrorSetField(analyser, symbol);
}
return try lookupSymbolContainer(self, symbol, .other);
} else {
if (try lookupSymbolContainer(self, symbol, .other)) |decl| {
Expand All @@ -4141,6 +4149,52 @@ pub const Type = struct {
}
}

fn lookupErrorSetField(self: Type, analyser: *Analyser, field_name: []const u8) error{OutOfMemory}!?DeclWithHandle {
const ip_index = self.data.ip_index.index orelse return null;
const error_set = analyser.ip.indexToKey(ip_index).error_set_type;

var field_index: ?usize = null;
const names = analyser.ip.extra.items[error_set.names.start..][0..error_set.names.len];
for (names, 0..) |name_index, i| {
const name_locked = analyser.ip.string_pool.stringToSliceLock(@enumFromInt(name_index));
defer name_locked.release(&analyser.ip.string_pool);
if (std.mem.eql(u8, name_locked.slice, field_name)) {
field_index = i;
break;
}
}

const found_index = field_index orelse return null;
if (error_set.source_node == 0) return null;

const node_index = error_set.source_node;

for (analyser.store.handles.values()) |handle| {
const tree = handle.tree;
if (node_index >= tree.nodes.len) continue;

const node: Ast.Node.Index = @enumFromInt(node_index);
if (tree.nodeTag(node) != .error_set_decl) continue;

const lbrace, const rbrace = tree.nodeData(node).token_and_token;

var error_i: usize = 0;
for (lbrace + 1..rbrace) |tok_i| {
if (tree.tokenTag(@intCast(tok_i)) != .identifier) continue;
if (error_i == found_index) {
const identifier_token: Ast.TokenIndex = @intCast(tok_i);
return .{
.decl = .{ .error_token = identifier_token },
.handle = handle,
};
}
error_i += 1;
}
}

return null;
}

pub fn stringifyTypeOf(ty: Type, analyser: *Analyser, options: FormatOptions) error{OutOfMemory}![]const u8 {
const typeof = try ty.typeOf(analyser);
var aw: std.io.Writer.Allocating = .init(analyser.arena);
Expand Down
2 changes: 1 addition & 1 deletion src/features/references.zig
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ fn symbolReferences(
=> |payload| payload.node,
.function_parameter => |payload| payload.func,
.label => unreachable, // handled separately by labelReferences
.error_token => return .empty,
.error_token => null,
};

var builder: Builder = .{
Expand Down
Loading