mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
stage2: move inferred error set state into func
This commit is contained in:
parent
cd733ceb85
commit
b2343e63bd
@ -1207,6 +1207,24 @@ pub const Fn = struct {
|
||||
is_cold: bool = false,
|
||||
is_noinline: bool = false,
|
||||
|
||||
/// These fields are used to keep track of any dependencies related to functions
|
||||
/// that return inferred error sets. It's values are not used when the function
|
||||
/// does not return an inferred error set.
|
||||
inferred_error_set: struct {
|
||||
/// All currently known errors that this function returns. This includes direct additions
|
||||
/// via `return error.Foo;`, and possibly also errors that are returned from any dependent functions.
|
||||
/// When the inferred error set is fully resolved, this map contains all the errors that the function might return.
|
||||
errors: std.StringHashMapUnmanaged(void) = .{},
|
||||
|
||||
/// Other functions with inferred error sets which the inferred error set of this
|
||||
/// function should include.
|
||||
functions: std.AutoHashMapUnmanaged(*Fn, void) = .{},
|
||||
|
||||
/// Whether the function returned anyerror. This is true if either of the dependent functions
|
||||
/// returns anyerror.
|
||||
is_anyerror: bool = false,
|
||||
} = .{},
|
||||
|
||||
pub const Analysis = enum {
|
||||
queued,
|
||||
/// This function intentionally only has ZIR generated because it is marked
|
||||
@ -1222,23 +1240,37 @@ pub const Fn = struct {
|
||||
};
|
||||
|
||||
pub fn deinit(func: *Fn, gpa: Allocator) void {
|
||||
if (func.getInferredErrorSet()) |error_set_data| {
|
||||
error_set_data.map.deinit(gpa);
|
||||
error_set_data.functions.deinit(gpa);
|
||||
}
|
||||
func.inferred_error_set.errors.deinit(gpa);
|
||||
func.inferred_error_set.functions.deinit(gpa);
|
||||
}
|
||||
|
||||
pub fn getInferredErrorSet(func: *Fn) ?*Type.Payload.ErrorSetInferred.Data {
|
||||
const ret_ty = func.owner_decl.ty.fnReturnType();
|
||||
if (ret_ty.tag() == .generic_poison) {
|
||||
return null;
|
||||
pub fn addErrorSet(func: *Fn, gpa: Allocator, err_set_ty: Type) !void {
|
||||
switch (err_set_ty.tag()) {
|
||||
.error_set => {
|
||||
const names = err_set_ty.castTag(.error_set).?.data.names.keys();
|
||||
for (names) |name| {
|
||||
try func.inferred_error_set.errors.put(gpa, name, {});
|
||||
}
|
||||
},
|
||||
.error_set_single => {
|
||||
const name = err_set_ty.castTag(.error_set_single).?.data;
|
||||
try func.inferred_error_set.errors.put(gpa, name, {});
|
||||
},
|
||||
.error_set_inferred => {
|
||||
const dependent_func = err_set_ty.castTag(.error_set_inferred).?.data;
|
||||
try func.inferred_error_set.functions.put(gpa, dependent_func, {});
|
||||
},
|
||||
.error_set_merged => {
|
||||
const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
|
||||
for (names) |name| {
|
||||
try func.inferred_error_set.errors.put(gpa, name, {});
|
||||
}
|
||||
},
|
||||
.anyerror => {
|
||||
func.inferred_error_set.is_anyerror = true;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
if (ret_ty.zigTypeTag() == .ErrorUnion) {
|
||||
if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
|
||||
return &payload.data;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
25
src/Sema.zig
25
src/Sema.zig
@ -5107,12 +5107,7 @@ fn funcCommon(
|
||||
const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
|
||||
bare_return_type
|
||||
else blk: {
|
||||
const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{
|
||||
.func = new_func,
|
||||
.map = .{},
|
||||
.functions = .{},
|
||||
.is_anyerror = false,
|
||||
});
|
||||
const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, new_func);
|
||||
break :blk try Type.Tag.error_union.create(sema.arena, .{
|
||||
.error_set = error_set_ty,
|
||||
.payload = bare_return_type,
|
||||
@ -9209,14 +9204,14 @@ fn analyzeRet(
|
||||
// add the error tag to the inferred error set of the in-scope function, so
|
||||
// that the coercion below works correctly.
|
||||
if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) {
|
||||
if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
|
||||
if (sema.fn_ret_ty.errorUnionSet().tag() == .error_set_inferred) {
|
||||
const op_ty = sema.typeOf(uncasted_operand);
|
||||
switch (op_ty.zigTypeTag()) {
|
||||
.ErrorSet => {
|
||||
try payload.data.addErrorSet(sema.gpa, op_ty);
|
||||
try sema.func.?.addErrorSet(sema.gpa, op_ty);
|
||||
},
|
||||
.ErrorUnion => {
|
||||
try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet());
|
||||
try sema.func.?.addErrorSet(sema.gpa, op_ty.errorUnionSet());
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -12501,10 +12496,10 @@ fn coerceInMemoryAllowedErrorSets(
|
||||
// of inferred error sets.
|
||||
if (src_ty.castTag(.error_set_inferred)) |src_payload| {
|
||||
if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
|
||||
const src_func = src_payload.data.func;
|
||||
const dst_func = dst_payload.data.func;
|
||||
const src_func = src_payload.data;
|
||||
const dst_func = dst_payload.data;
|
||||
|
||||
if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) {
|
||||
if (src_func == dst_func or dst_func.inferred_error_set.functions.contains(src_func)) {
|
||||
return .ok;
|
||||
}
|
||||
}
|
||||
@ -13899,10 +13894,10 @@ fn wrapErrorUnion(
|
||||
}
|
||||
},
|
||||
.error_set_inferred => ok: {
|
||||
const err_set_payload = dest_err_set_ty.castTag(.error_set_inferred).?.data;
|
||||
if (err_set_payload.is_anyerror) break :ok;
|
||||
const func = dest_err_set_ty.castTag(.error_set_inferred).?.data;
|
||||
if (func.inferred_error_set.is_anyerror) break :ok;
|
||||
const expected_name = val.castTag(.@"error").?.data.name;
|
||||
if (err_set_payload.map.contains(expected_name)) break :ok;
|
||||
if (func.inferred_error_set.errors.contains(expected_name)) break :ok;
|
||||
// TODO error set resolution here before emitting a compile error
|
||||
return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
|
||||
},
|
||||
|
||||
@ -722,7 +722,7 @@ pub const DeclGen = struct {
|
||||
try bw.writeAll(" payload; uint16_t error; } ");
|
||||
const name_index = buffer.items.len;
|
||||
if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {
|
||||
const func = inf_err_set_payload.data.func;
|
||||
const func = inf_err_set_payload.data;
|
||||
try bw.writeAll("zig_E_");
|
||||
try dg.renderDeclName(func.owner_decl, bw);
|
||||
try bw.writeAll(";\n");
|
||||
|
||||
51
src/type.zig
51
src/type.zig
@ -627,7 +627,7 @@ pub const Type = extern union {
|
||||
}
|
||||
|
||||
if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) {
|
||||
return a.castTag(.error_set_inferred).?.data.func == b.castTag(.error_set_inferred).?.data.func;
|
||||
return a.castTag(.error_set_inferred).?.data == b.castTag(.error_set_inferred).?.data;
|
||||
}
|
||||
|
||||
if (a.tag() == .error_set_single and b.tag() == .error_set_single) {
|
||||
@ -1203,7 +1203,7 @@ pub const Type = extern union {
|
||||
return writer.writeAll(std.mem.sliceTo(error_set.owner_decl.name, 0));
|
||||
},
|
||||
.error_set_inferred => {
|
||||
const func = ty.castTag(.error_set_inferred).?.data.func;
|
||||
const func = ty.castTag(.error_set_inferred).?.data;
|
||||
return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
|
||||
},
|
||||
.error_set_merged => {
|
||||
@ -2869,7 +2869,7 @@ pub const Type = extern union {
|
||||
pub fn isAnyError(ty: Type) bool {
|
||||
return switch (ty.tag()) {
|
||||
.anyerror => true,
|
||||
.error_set_inferred => ty.castTag(.error_set_inferred).?.data.is_anyerror,
|
||||
.error_set_inferred => ty.castTag(.error_set_inferred).?.data.inferred_error_set.is_anyerror,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
@ -4156,50 +4156,7 @@ pub const Type = extern union {
|
||||
pub const base_tag = Tag.error_set_inferred;
|
||||
|
||||
base: Payload = Payload{ .tag = base_tag },
|
||||
data: Data,
|
||||
|
||||
pub const Data = struct {
|
||||
func: *Module.Fn,
|
||||
/// Direct additions to the inferred error set via `return error.Foo;`.
|
||||
map: std.StringHashMapUnmanaged(void),
|
||||
/// Other functions with inferred error sets which this error set includes.
|
||||
functions: std.AutoHashMapUnmanaged(*Module.Fn, void),
|
||||
is_anyerror: bool,
|
||||
|
||||
pub fn addErrorSet(self: *Data, gpa: Allocator, err_set_ty: Type) !void {
|
||||
switch (err_set_ty.tag()) {
|
||||
.error_set => {
|
||||
const names = err_set_ty.castTag(.error_set).?.data.names.keys();
|
||||
for (names) |name| {
|
||||
try self.map.put(gpa, name, {});
|
||||
}
|
||||
},
|
||||
.error_set_single => {
|
||||
const name = err_set_ty.castTag(.error_set_single).?.data;
|
||||
try self.map.put(gpa, name, {});
|
||||
},
|
||||
.error_set_inferred => {
|
||||
const func = err_set_ty.castTag(.error_set_inferred).?.data.func;
|
||||
try self.functions.put(gpa, func, {});
|
||||
var it = func.owner_decl.ty.fnReturnType().errorUnionSet()
|
||||
.castTag(.error_set_inferred).?.data.map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
try self.map.put(gpa, entry.key_ptr.*, {});
|
||||
}
|
||||
},
|
||||
.error_set_merged => {
|
||||
const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
|
||||
for (names) |name| {
|
||||
try self.map.put(gpa, name, {});
|
||||
}
|
||||
},
|
||||
.anyerror => {
|
||||
self.is_anyerror = true;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
};
|
||||
data: *Module.Fn,
|
||||
};
|
||||
|
||||
pub const Pointer = struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user