authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-16 02:23:15+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-12-21 01:41:50+01:00
logb2343e63bd06d1312ca80745236bb42358062115
tree4b2ce783339913199d5199a0c4d19a7dc51af090
parentcd733ceb852369427301fbb526b82ad4407d0607

stage2: move inferred error set state into func


4 files changed, 61 insertions(+), 77 deletions(-)

src/Module.zig+46-14
......@@ -1207,6 +1207,24 @@ pub const Fn = struct {
12071207 is_cold: bool = false,
12081208 is_noinline: bool = false,
12091209
1210 /// These fields are used to keep track of any dependencies related to functions
1211 /// that return inferred error sets. It's values are not used when the function
1212 /// does not return an inferred error set.
1213 inferred_error_set: struct {
1214 /// All currently known errors that this function returns. This includes direct additions
1215 /// via `return error.Foo;`, and possibly also errors that are returned from any dependent functions.
1216 /// When the inferred error set is fully resolved, this map contains all the errors that the function might return.
1217 errors: std.StringHashMapUnmanaged(void) = .{},
1218
1219 /// Other functions with inferred error sets which the inferred error set of this
1220 /// function should include.
1221 functions: std.AutoHashMapUnmanaged(*Fn, void) = .{},
1222
1223 /// Whether the function returned anyerror. This is true if either of the dependent functions
1224 /// returns anyerror.
1225 is_anyerror: bool = false,
1226 } = .{},
1227
12101228 pub const Analysis = enum {
12111229 queued,
12121230 /// This function intentionally only has ZIR generated because it is marked
......@@ -1222,23 +1240,37 @@ pub const Fn = struct {
12221240 };
12231241
12241242 pub fn deinit(func: *Fn, gpa: Allocator) void {
1225 if (func.getInferredErrorSet()) |error_set_data| {
1226 error_set_data.map.deinit(gpa);
1227 error_set_data.functions.deinit(gpa);
1228 }
1243 func.inferred_error_set.errors.deinit(gpa);
1244 func.inferred_error_set.functions.deinit(gpa);
12291245 }
12301246
1231 pub fn getInferredErrorSet(func: *Fn) ?*Type.Payload.ErrorSetInferred.Data {
1232 const ret_ty = func.owner_decl.ty.fnReturnType();
1233 if (ret_ty.tag() == .generic_poison) {
1234 return null;
1235 }
1236 if (ret_ty.zigTypeTag() == .ErrorUnion) {
1237 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
1238 return &payload.data;
1239 }
1247 pub fn addErrorSet(func: *Fn, gpa: Allocator, err_set_ty: Type) !void {
1248 switch (err_set_ty.tag()) {
1249 .error_set => {
1250 const names = err_set_ty.castTag(.error_set).?.data.names.keys();
1251 for (names) |name| {
1252 try func.inferred_error_set.errors.put(gpa, name, {});
1253 }
1254 },
1255 .error_set_single => {
1256 const name = err_set_ty.castTag(.error_set_single).?.data;
1257 try func.inferred_error_set.errors.put(gpa, name, {});
1258 },
1259 .error_set_inferred => {
1260 const dependent_func = err_set_ty.castTag(.error_set_inferred).?.data;
1261 try func.inferred_error_set.functions.put(gpa, dependent_func, {});
1262 },
1263 .error_set_merged => {
1264 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
1265 for (names) |name| {
1266 try func.inferred_error_set.errors.put(gpa, name, {});
1267 }
1268 },
1269 .anyerror => {
1270 func.inferred_error_set.is_anyerror = true;
1271 },
1272 else => unreachable,
12401273 }
1241 return null;
12421274 }
12431275};
12441276
src/Sema.zig+10-15
......@@ -5107,12 +5107,7 @@ fn funcCommon(
51075107 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
51085108 bare_return_type
51095109 else blk: {
5110 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{
5111 .func = new_func,
5112 .map = .{},
5113 .functions = .{},
5114 .is_anyerror = false,
5115 });
5110 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, new_func);
51165111 break :blk try Type.Tag.error_union.create(sema.arena, .{
51175112 .error_set = error_set_ty,
51185113 .payload = bare_return_type,
......@@ -9209,14 +9204,14 @@ fn analyzeRet(
92099204 // add the error tag to the inferred error set of the in-scope function, so
92109205 // that the coercion below works correctly.
92119206 if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) {
9212 if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
9207 if (sema.fn_ret_ty.errorUnionSet().tag() == .error_set_inferred) {
92139208 const op_ty = sema.typeOf(uncasted_operand);
92149209 switch (op_ty.zigTypeTag()) {
92159210 .ErrorSet => {
9216 try payload.data.addErrorSet(sema.gpa, op_ty);
9211 try sema.func.?.addErrorSet(sema.gpa, op_ty);
92179212 },
92189213 .ErrorUnion => {
9219 try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet());
9214 try sema.func.?.addErrorSet(sema.gpa, op_ty.errorUnionSet());
92209215 },
92219216 else => {},
92229217 }
......@@ -12501,10 +12496,10 @@ fn coerceInMemoryAllowedErrorSets(
1250112496 // of inferred error sets.
1250212497 if (src_ty.castTag(.error_set_inferred)) |src_payload| {
1250312498 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
12504 const src_func = src_payload.data.func;
12505 const dst_func = dst_payload.data.func;
12499 const src_func = src_payload.data;
12500 const dst_func = dst_payload.data;
1250612501
12507 if (src_func == dst_func or dst_payload.data.functions.contains(src_func)) {
12502 if (src_func == dst_func or dst_func.inferred_error_set.functions.contains(src_func)) {
1250812503 return .ok;
1250912504 }
1251012505 }
......@@ -13899,10 +13894,10 @@ fn wrapErrorUnion(
1389913894 }
1390013895 },
1390113896 .error_set_inferred => ok: {
13902 const err_set_payload = dest_err_set_ty.castTag(.error_set_inferred).?.data;
13903 if (err_set_payload.is_anyerror) break :ok;
13897 const func = dest_err_set_ty.castTag(.error_set_inferred).?.data;
13898 if (func.inferred_error_set.is_anyerror) break :ok;
1390413899 const expected_name = val.castTag(.@"error").?.data.name;
13905 if (err_set_payload.map.contains(expected_name)) break :ok;
13900 if (func.inferred_error_set.errors.contains(expected_name)) break :ok;
1390613901 // TODO error set resolution here before emitting a compile error
1390713902 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
1390813903 },
src/codegen/c.zig+1-1
......@@ -722,7 +722,7 @@ pub const DeclGen = struct {
722722 try bw.writeAll(" payload; uint16_t error; } ");
723723 const name_index = buffer.items.len;
724724 if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {
725 const func = inf_err_set_payload.data.func;
725 const func = inf_err_set_payload.data;
726726 try bw.writeAll("zig_E_");
727727 try dg.renderDeclName(func.owner_decl, bw);
728728 try bw.writeAll(";\n");
src/type.zig+4-47
......@@ -627,7 +627,7 @@ pub const Type = extern union {
627627 }
628628
629629 if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) {
630 return a.castTag(.error_set_inferred).?.data.func == b.castTag(.error_set_inferred).?.data.func;
630 return a.castTag(.error_set_inferred).?.data == b.castTag(.error_set_inferred).?.data;
631631 }
632632
633633 if (a.tag() == .error_set_single and b.tag() == .error_set_single) {
......@@ -1203,7 +1203,7 @@ pub const Type = extern union {
12031203 return writer.writeAll(std.mem.sliceTo(error_set.owner_decl.name, 0));
12041204 },
12051205 .error_set_inferred => {
1206 const func = ty.castTag(.error_set_inferred).?.data.func;
1206 const func = ty.castTag(.error_set_inferred).?.data;
12071207 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
12081208 },
12091209 .error_set_merged => {
......@@ -2869,7 +2869,7 @@ pub const Type = extern union {
28692869 pub fn isAnyError(ty: Type) bool {
28702870 return switch (ty.tag()) {
28712871 .anyerror => true,
2872 .error_set_inferred => ty.castTag(.error_set_inferred).?.data.is_anyerror,
2872 .error_set_inferred => ty.castTag(.error_set_inferred).?.data.inferred_error_set.is_anyerror,
28732873 else => false,
28742874 };
28752875 }
......@@ -4156,50 +4156,7 @@ pub const Type = extern union {
41564156 pub const base_tag = Tag.error_set_inferred;
41574157
41584158 base: Payload = Payload{ .tag = base_tag },
4159 data: Data,
4160
4161 pub const Data = struct {
4162 func: *Module.Fn,
4163 /// Direct additions to the inferred error set via `return error.Foo;`.
4164 map: std.StringHashMapUnmanaged(void),
4165 /// Other functions with inferred error sets which this error set includes.
4166 functions: std.AutoHashMapUnmanaged(*Module.Fn, void),
4167 is_anyerror: bool,
4168
4169 pub fn addErrorSet(self: *Data, gpa: Allocator, err_set_ty: Type) !void {
4170 switch (err_set_ty.tag()) {
4171 .error_set => {
4172 const names = err_set_ty.castTag(.error_set).?.data.names.keys();
4173 for (names) |name| {
4174 try self.map.put(gpa, name, {});
4175 }
4176 },
4177 .error_set_single => {
4178 const name = err_set_ty.castTag(.error_set_single).?.data;
4179 try self.map.put(gpa, name, {});
4180 },
4181 .error_set_inferred => {
4182 const func = err_set_ty.castTag(.error_set_inferred).?.data.func;
4183 try self.functions.put(gpa, func, {});
4184 var it = func.owner_decl.ty.fnReturnType().errorUnionSet()
4185 .castTag(.error_set_inferred).?.data.map.iterator();
4186 while (it.next()) |entry| {
4187 try self.map.put(gpa, entry.key_ptr.*, {});
4188 }
4189 },
4190 .error_set_merged => {
4191 const names = err_set_ty.castTag(.error_set_merged).?.data.keys();
4192 for (names) |name| {
4193 try self.map.put(gpa, name, {});
4194 }
4195 },
4196 .anyerror => {
4197 self.is_anyerror = true;
4198 },
4199 else => unreachable,
4200 }
4201 }
4202 };
4159 data: *Module.Fn,
42034160 };
42044161
42054162 pub const Pointer = struct {