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 {...@@ -1207,6 +1207,24 @@ pub const Fn = struct {
1207 is_cold: bool = false,1207 is_cold: bool = false,
1208 is_noinline: bool = false,1208 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
1210 pub const Analysis = enum {1228 pub const Analysis = enum {
1211 queued,1229 queued,
1212 /// This function intentionally only has ZIR generated because it is marked1230 /// This function intentionally only has ZIR generated because it is marked
...@@ -1222,23 +1240,37 @@ pub const Fn = struct {...@@ -1222,23 +1240,37 @@ pub const Fn = struct {
1222 };1240 };
12231241
1224 pub fn deinit(func: *Fn, gpa: Allocator) void {1242 pub fn deinit(func: *Fn, gpa: Allocator) void {
1225 if (func.getInferredErrorSet()) |error_set_data| {1243 func.inferred_error_set.errors.deinit(gpa);
1226 error_set_data.map.deinit(gpa);1244 func.inferred_error_set.functions.deinit(gpa);
1227 error_set_data.functions.deinit(gpa);
1228 }
1229 }1245 }
12301246
1231 pub fn getInferredErrorSet(func: *Fn) ?*Type.Payload.ErrorSetInferred.Data {1247 pub fn addErrorSet(func: *Fn, gpa: Allocator, err_set_ty: Type) !void {
1232 const ret_ty = func.owner_decl.ty.fnReturnType();1248 switch (err_set_ty.tag()) {
1233 if (ret_ty.tag() == .generic_poison) {1249 .error_set => {
1234 return null;1250 const names = err_set_ty.castTag(.error_set).?.data.names.keys();
1235 }1251 for (names) |name| {
1236 if (ret_ty.zigTypeTag() == .ErrorUnion) {1252 try func.inferred_error_set.errors.put(gpa, name, {});
1237 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {1253 }
1238 return &payload.data;1254 },
1239 }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,
1240 }1273 }
1241 return null;
1242 }1274 }
1243};1275};
12441276
src/Sema.zig+10-15
...@@ -5107,12 +5107,7 @@ fn funcCommon(...@@ -5107,12 +5107,7 @@ fn funcCommon(
5107 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)5107 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
5108 bare_return_type5108 bare_return_type
5109 else blk: {5109 else blk: {
5110 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{5110 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, new_func);
5111 .func = new_func,
5112 .map = .{},
5113 .functions = .{},
5114 .is_anyerror = false,
5115 });
5116 break :blk try Type.Tag.error_union.create(sema.arena, .{5111 break :blk try Type.Tag.error_union.create(sema.arena, .{
5117 .error_set = error_set_ty,5112 .error_set = error_set_ty,
5118 .payload = bare_return_type,5113 .payload = bare_return_type,
...@@ -9209,14 +9204,14 @@ fn analyzeRet(...@@ -9209,14 +9204,14 @@ fn analyzeRet(
9209 // add the error tag to the inferred error set of the in-scope function, so9204 // add the error tag to the inferred error set of the in-scope function, so
9210 // that the coercion below works correctly.9205 // that the coercion below works correctly.
9211 if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) {9206 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) {
9213 const op_ty = sema.typeOf(uncasted_operand);9208 const op_ty = sema.typeOf(uncasted_operand);
9214 switch (op_ty.zigTypeTag()) {9209 switch (op_ty.zigTypeTag()) {
9215 .ErrorSet => {9210 .ErrorSet => {
9216 try payload.data.addErrorSet(sema.gpa, op_ty);9211 try sema.func.?.addErrorSet(sema.gpa, op_ty);
9217 },9212 },
9218 .ErrorUnion => {9213 .ErrorUnion => {
9219 try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet());9214 try sema.func.?.addErrorSet(sema.gpa, op_ty.errorUnionSet());
9220 },9215 },
9221 else => {},9216 else => {},
9222 }9217 }
...@@ -12501,10 +12496,10 @@ fn coerceInMemoryAllowedErrorSets(...@@ -12501,10 +12496,10 @@ fn coerceInMemoryAllowedErrorSets(
12501 // of inferred error sets.12496 // of inferred error sets.
12502 if (src_ty.castTag(.error_set_inferred)) |src_payload| {12497 if (src_ty.castTag(.error_set_inferred)) |src_payload| {
12503 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {12498 if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
12504 const src_func = src_payload.data.func;12499 const src_func = src_payload.data;
12505 const dst_func = dst_payload.data.func;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)) {
12508 return .ok;12503 return .ok;
12509 }12504 }
12510 }12505 }
...@@ -13899,10 +13894,10 @@ fn wrapErrorUnion(...@@ -13899,10 +13894,10 @@ fn wrapErrorUnion(
13899 }13894 }
13900 },13895 },
13901 .error_set_inferred => ok: {13896 .error_set_inferred => ok: {
13902 const err_set_payload = dest_err_set_ty.castTag(.error_set_inferred).?.data;13897 const func = dest_err_set_ty.castTag(.error_set_inferred).?.data;
13903 if (err_set_payload.is_anyerror) break :ok;13898 if (func.inferred_error_set.is_anyerror) break :ok;
13904 const expected_name = val.castTag(.@"error").?.data.name;13899 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;
13906 // TODO error set resolution here before emitting a compile error13901 // TODO error set resolution here before emitting a compile error
13907 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);13902 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
13908 },13903 },
src/codegen/c.zig+1-1
...@@ -722,7 +722,7 @@ pub const DeclGen = struct {...@@ -722,7 +722,7 @@ pub const DeclGen = struct {
722 try bw.writeAll(" payload; uint16_t error; } ");722 try bw.writeAll(" payload; uint16_t error; } ");
723 const name_index = buffer.items.len;723 const name_index = buffer.items.len;
724 if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {724 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;
726 try bw.writeAll("zig_E_");726 try bw.writeAll("zig_E_");
727 try dg.renderDeclName(func.owner_decl, bw);727 try dg.renderDeclName(func.owner_decl, bw);
728 try bw.writeAll(";\n");728 try bw.writeAll(";\n");
src/type.zig+4-47
...@@ -627,7 +627,7 @@ pub const Type = extern union {...@@ -627,7 +627,7 @@ pub const Type = extern union {
627 }627 }
628628
629 if (a.tag() == .error_set_inferred and b.tag() == .error_set_inferred) {629 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;
631 }631 }
632632
633 if (a.tag() == .error_set_single and b.tag() == .error_set_single) {633 if (a.tag() == .error_set_single and b.tag() == .error_set_single) {
...@@ -1203,7 +1203,7 @@ pub const Type = extern union {...@@ -1203,7 +1203,7 @@ pub const Type = extern union {
1203 return writer.writeAll(std.mem.sliceTo(error_set.owner_decl.name, 0));1203 return writer.writeAll(std.mem.sliceTo(error_set.owner_decl.name, 0));
1204 },1204 },
1205 .error_set_inferred => {1205 .error_set_inferred => {
1206 const func = ty.castTag(.error_set_inferred).?.data.func;1206 const func = ty.castTag(.error_set_inferred).?.data;
1207 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});
1208 },1208 },
1209 .error_set_merged => {1209 .error_set_merged => {
...@@ -2869,7 +2869,7 @@ pub const Type = extern union {...@@ -2869,7 +2869,7 @@ pub const Type = extern union {
2869 pub fn isAnyError(ty: Type) bool {2869 pub fn isAnyError(ty: Type) bool {
2870 return switch (ty.tag()) {2870 return switch (ty.tag()) {
2871 .anyerror => true,2871 .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,
2873 else => false,2873 else => false,
2874 };2874 };
2875 }2875 }
...@@ -4156,50 +4156,7 @@ pub const Type = extern union {...@@ -4156,50 +4156,7 @@ pub const Type = extern union {
4156 pub const base_tag = Tag.error_set_inferred;4156 pub const base_tag = Tag.error_set_inferred;
41574157
4158 base: Payload = Payload{ .tag = base_tag },4158 base: Payload = Payload{ .tag = base_tag },
4159 data: Data,4159 data: *Module.Fn,
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 };
4203 };4160 };
42044161
4205 pub const Pointer = struct {4162 pub const Pointer = struct {