authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-01-14 10:14:29-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-02 23:53:05-07:00
log8b100792ebaa4fa17dd75fadc7a8bdb47328dfad
tree4bb2ea1399992f4cca2d935b78b12d4becdfffb1
parent4b57fb5f23aa6513ceaebe396d1faf215cf0a475

stage2: error set merging with tests

I had to come up with creative tests because we don't have error set type equality yet.

2 files changed, 109 insertions(+), 2 deletions(-)

src/zir_sema.zig+75-1
......@@ -1196,7 +1196,81 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE
11961196fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
11971197 const tracy = trace(@src());
11981198 defer tracy.end();
1199 return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{});
1199
1200 const rhs_ty = try resolveType(mod, scope, inst.positionals.rhs);
1201 const lhs_ty = try resolveType(mod, scope, inst.positionals.lhs);
1202 if (rhs_ty.zigTypeTag() != .ErrorSet)
1203 return mod.fail(scope, inst.positionals.rhs.src, "expected error set type, found {}", .{rhs_ty});
1204 if (lhs_ty.zigTypeTag() != .ErrorSet)
1205 return mod.fail(scope, inst.positionals.lhs.src, "expected error set type, found {}", .{lhs_ty});
1206
1207 // anything merged with anyerror is anyerror
1208 if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror)
1209 return mod.constInst(scope, inst.base.src, .{
1210 .ty = Type.initTag(.type),
1211 .val = Value.initTag(.anyerror_type),
1212 });
1213 // The declarations arena will store the hashmap.
1214 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1215 errdefer new_decl_arena.deinit();
1216
1217 const payload = try new_decl_arena.allocator.create(Value.Payload.ErrorSet);
1218 payload.* = .{
1219 .base = .{ .tag = .error_set },
1220 .data = .{
1221 .fields = .{},
1222 .decl = undefined, // populated below
1223 },
1224 };
1225 try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, switch (rhs_ty.tag()) {
1226 .error_set_single => 1,
1227 .error_set => rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1228 else => unreachable,
1229 } + switch (lhs_ty.tag()) {
1230 .error_set_single => 1,
1231 .error_set => lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1232 else => unreachable,
1233 }));
1234
1235 switch (lhs_ty.tag()) {
1236 .error_set_single => {
1237 const name = lhs_ty.castTag(.error_set_single).?.data;
1238 const num = mod.global_error_set.get(name).?;
1239 payload.data.fields.putAssumeCapacity(name, num);
1240 },
1241 .error_set => {
1242 var multiple = lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1243 var it = multiple.iterator();
1244 while (it.next()) |entry| {
1245 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1246 }
1247 },
1248 else => unreachable,
1249 }
1250
1251 switch (rhs_ty.tag()) {
1252 .error_set_single => {
1253 const name = rhs_ty.castTag(.error_set_single).?.data;
1254 const num = mod.global_error_set.get(name).?;
1255 payload.data.fields.putAssumeCapacity(name, num);
1256 },
1257 .error_set => {
1258 var multiple = rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1259 var it = multiple.iterator();
1260 while (it.next()) |name| {
1261 const entry = try mod.getErrorValue(name.key);
1262 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1263 }
1264 },
1265 else => unreachable,
1266 }
1267 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1268 .ty = Type.initTag(.type),
1269 .val = Value.initPayload(&payload.base),
1270 });
1271 payload.data.decl = new_decl;
1272
1273 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
12001274}
12011275
12021276fn zirEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
test/stage2/test.zig+34-1
......@@ -985,7 +985,7 @@ pub fn addCases(ctx: *TestContext) !void {
985985 "Hello, World!\n",
986986 );
987987 try case.files.append(.{
988 .src =
988 .src =
989989 \\pub fn print() void {
990990 \\ asm volatile ("syscall"
991991 \\ :
......@@ -1525,4 +1525,37 @@ pub fn addCases(ctx: *TestContext) !void {
15251525 \\}
15261526 , "");
15271527 }
1528 {
1529 var case = ctx.exe("merge error sets", linux_x64);
1530
1531 case.addCompareOutput(
1532 \\export fn _start() noreturn {
1533 \\ const E = error{ A, B, D } || error { A, B, C };
1534 \\ const a = E.A;
1535 \\ const b = E.B;
1536 \\ const c = E.C;
1537 \\ const d = E.D;
1538 \\ const E2 = error { X, Y } || @TypeOf(error.Z);
1539 \\ const x = E2.X;
1540 \\ const y = E2.Y;
1541 \\ const z = E2.Z;
1542 \\ assert(anyerror || error { Z } == anyerror);
1543 \\ exit();
1544 \\}
1545 \\fn assert(b: bool) void {
1546 \\ if (!b) unreachable;
1547 \\}
1548 \\fn exit() noreturn {
1549 \\ asm volatile ("syscall"
1550 \\ :
1551 \\ : [number] "{rax}" (231),
1552 \\ [arg1] "{rdi}" (0)
1553 \\ : "rcx", "r11", "memory"
1554 \\ );
1555 \\ unreachable;
1556 \\}
1557 ,
1558 "",
1559 );
1560 }
15281561}