| author | |
| committer | |
| log | b2343e63bd06d1312ca80745236bb42358062115 |
| tree | 4b2ce783339913199d5199a0c4d19a7dc51af090 |
| parent | cd733ceb852369427301fbb526b82ad4407d0607 |
4 files changed, 61 insertions(+), 77 deletions(-)
src/Module.zig+46-14| ... | ... | @@ -1207,6 +1207,24 @@ pub const Fn = struct { |
| 1207 | 1207 | is_cold: bool = false, |
| 1208 | 1208 | is_noinline: bool = false, |
| 1209 | 1209 | |
| 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 | 1228 | pub const Analysis = enum { |
| 1211 | 1229 | queued, |
| 1212 | 1230 | /// This function intentionally only has ZIR generated because it is marked |
| ... | ... | @@ -1222,23 +1240,37 @@ pub const Fn = struct { |
| 1222 | 1240 | }; |
| 1223 | 1241 | |
| 1224 | 1242 | 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); | |
| 1229 | 1245 | } |
| 1230 | 1246 | |
| 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, | |
| 1240 | 1273 | } |
| 1241 | return null; | |
| 1242 | 1274 | } |
| 1243 | 1275 | }; |
| 1244 | 1276 |
src/Sema.zig+10-15| ... | ... | @@ -5107,12 +5107,7 @@ fn funcCommon( |
| 5107 | 5107 | const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison) |
| 5108 | 5108 | bare_return_type |
| 5109 | 5109 | 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); | |
| 5116 | 5111 | break :blk try Type.Tag.error_union.create(sema.arena, .{ |
| 5117 | 5112 | .error_set = error_set_ty, |
| 5118 | 5113 | .payload = bare_return_type, |
| ... | ... | @@ -9209,14 +9204,14 @@ fn analyzeRet( |
| 9209 | 9204 | // add the error tag to the inferred error set of the in-scope function, so |
| 9210 | 9205 | // that the coercion below works correctly. |
| 9211 | 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 | 9208 | const op_ty = sema.typeOf(uncasted_operand); |
| 9214 | 9209 | switch (op_ty.zigTypeTag()) { |
| 9215 | 9210 | .ErrorSet => { |
| 9216 | try payload.data.addErrorSet(sema.gpa, op_ty); | |
| 9211 | try sema.func.?.addErrorSet(sema.gpa, op_ty); | |
| 9217 | 9212 | }, |
| 9218 | 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 | 9216 | else => {}, |
| 9222 | 9217 | } |
| ... | ... | @@ -12501,10 +12496,10 @@ fn coerceInMemoryAllowedErrorSets( |
| 12501 | 12496 | // of inferred error sets. |
| 12502 | 12497 | if (src_ty.castTag(.error_set_inferred)) |src_payload| { |
| 12503 | 12498 | 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; | |
| 12506 | 12501 | |
| 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 | 12503 | return .ok; |
| 12509 | 12504 | } |
| 12510 | 12505 | } |
| ... | ... | @@ -13899,10 +13894,10 @@ fn wrapErrorUnion( |
| 13899 | 13894 | } |
| 13900 | 13895 | }, |
| 13901 | 13896 | .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; | |
| 13904 | 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 | 13901 | // TODO error set resolution here before emitting a compile error |
| 13907 | 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 | 722 | try bw.writeAll(" payload; uint16_t error; } "); |
| 723 | 723 | const name_index = buffer.items.len; |
| 724 | 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 | 726 | try bw.writeAll("zig_E_"); |
| 727 | 727 | try dg.renderDeclName(func.owner_decl, bw); |
| 728 | 728 | try bw.writeAll(";\n"); |
src/type.zig+4-47| ... | ... | @@ -627,7 +627,7 @@ pub const Type = extern union { |
| 627 | 627 | } |
| 628 | 628 | |
| 629 | 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 | } |
| 632 | 632 | |
| 633 | 633 | if (a.tag() == .error_set_single and b.tag() == .error_set_single) { |
| ... | ... | @@ -1203,7 +1203,7 @@ pub const Type = extern union { |
| 1203 | 1203 | return writer.writeAll(std.mem.sliceTo(error_set.owner_decl.name, 0)); |
| 1204 | 1204 | }, |
| 1205 | 1205 | .error_set_inferred => { |
| 1206 | const func = ty.castTag(.error_set_inferred).?.data.func; | |
| 1206 | const func = ty.castTag(.error_set_inferred).?.data; | |
| 1207 | 1207 | return writer.print("(inferred error set of {s})", .{func.owner_decl.name}); |
| 1208 | 1208 | }, |
| 1209 | 1209 | .error_set_merged => { |
| ... | ... | @@ -2869,7 +2869,7 @@ pub const Type = extern union { |
| 2869 | 2869 | pub fn isAnyError(ty: Type) bool { |
| 2870 | 2870 | return switch (ty.tag()) { |
| 2871 | 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 | 2873 | else => false, |
| 2874 | 2874 | }; |
| 2875 | 2875 | } |
| ... | ... | @@ -4156,50 +4156,7 @@ pub const Type = extern union { |
| 4156 | 4156 | pub const base_tag = Tag.error_set_inferred; |
| 4157 | 4157 | |
| 4158 | 4158 | 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, | |
| 4203 | 4160 | }; |
| 4204 | 4161 | |
| 4205 | 4162 | pub const Pointer = struct { |