zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit bea447a6378fbc65eb79f31c5f1770c75850074c (tree)
parent 75c8c4442d1dd6fe43fbef1bfeaded360a98fe51
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Mon, 18 Oct 2021 15:45:11 -0700

stage2: fix coercion of error set to error union

When returning an error set or an error union from a function which has
an inferred error set, it populates the error names in addition to the
set of functions. This can have false negatives, meaning that after
checking the map of an unresolved error set, one must do full error set
resolution before emitting a compile error.

Diffstat:
Msrc/Sema.zig | 55+++++++++++++++++++++++++------------------------------
Msrc/type.zig | 5+++++
2 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/src/Sema.zig b/src/Sema.zig @@ -1179,6 +1179,18 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ lhs_ty, rhs_ty }); } +fn failWithErrorSetCodeMissing( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + dest_err_set_ty: Type, + src_err_set_ty: Type, +) CompileError { + return sema.fail(block, src, "expected type '{}', found type '{}'", .{ + dest_err_set_ty, src_err_set_ty, + }); +} + /// We don't return a pointer to the new error note because the pointer /// becomes invalid when you add another one. fn errNote( @@ -12858,47 +12870,30 @@ fn wrapErrorUnion( } switch (dest_err_set_ty.tag()) { .anyerror => {}, - .error_set_single => { + .error_set_single => ok: { const expected_name = val.castTag(.@"error").?.data.name; const n = dest_err_set_ty.castTag(.error_set_single).?.data; - if (!mem.eql(u8, expected_name, n)) { - return sema.fail( - block, - inst_src, - "expected type '{}', found type '{}'", - .{ dest_err_set_ty, inst_ty }, - ); - } + if (mem.eql(u8, expected_name, n)) break :ok; + return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); }, - .error_set => { + .error_set => ok: { const expected_name = val.castTag(.@"error").?.data.name; const error_set = dest_err_set_ty.castTag(.error_set).?.data; const names = error_set.names_ptr[0..error_set.names_len]; // TODO this is O(N). I'm putting off solving this until we solve inferred // error sets at the same time. - const found = for (names) |name| { - if (mem.eql(u8, expected_name, name)) break true; - } else false; - if (!found) { - return sema.fail( - block, - inst_src, - "expected type '{}', found type '{}'", - .{ dest_err_set_ty, inst_ty }, - ); + for (names) |name| { + if (mem.eql(u8, expected_name, name)) break :ok; } + return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); }, - .error_set_inferred => { + .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 expected_name = val.castTag(.@"error").?.data.name; - const map = &dest_err_set_ty.castTag(.error_set_inferred).?.data.map; - if (!map.contains(expected_name)) { - return sema.fail( - block, - inst_src, - "expected type '{}', found type '{}'", - .{ dest_err_set_ty, inst_ty }, - ); - } + if (err_set_payload.map.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); }, else => unreachable, } diff --git a/src/type.zig b/src/type.zig @@ -3869,6 +3869,11 @@ pub const Type = extern union { .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.*, {}); + } }, .anyerror => { self.is_anyerror = true;