authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-18 15:45:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-18 15:45:11-07:00
logbea447a6378fbc65eb79f31c5f1770c75850074c
tree95f989734bde6ec6232700933f308f3bf8ffc8e2
parent75c8c4442d1dd6fe43fbef1bfeaded360a98fe51

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.

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

src/Sema.zig+25-30
...@@ -1179,6 +1179,18 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T...@@ -1179,6 +1179,18 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T
1179 return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ lhs_ty, rhs_ty });1179 return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ lhs_ty, rhs_ty });
1180}1180}
11811181
1182fn failWithErrorSetCodeMissing(
1183 sema: *Sema,
1184 block: *Block,
1185 src: LazySrcLoc,
1186 dest_err_set_ty: Type,
1187 src_err_set_ty: Type,
1188) CompileError {
1189 return sema.fail(block, src, "expected type '{}', found type '{}'", .{
1190 dest_err_set_ty, src_err_set_ty,
1191 });
1192}
1193
1182/// We don't return a pointer to the new error note because the pointer1194/// We don't return a pointer to the new error note because the pointer
1183/// becomes invalid when you add another one.1195/// becomes invalid when you add another one.
1184fn errNote(1196fn errNote(
...@@ -12858,47 +12870,30 @@ fn wrapErrorUnion(...@@ -12858,47 +12870,30 @@ fn wrapErrorUnion(
12858 }12870 }
12859 switch (dest_err_set_ty.tag()) {12871 switch (dest_err_set_ty.tag()) {
12860 .anyerror => {},12872 .anyerror => {},
12861 .error_set_single => {12873 .error_set_single => ok: {
12862 const expected_name = val.castTag(.@"error").?.data.name;12874 const expected_name = val.castTag(.@"error").?.data.name;
12863 const n = dest_err_set_ty.castTag(.error_set_single).?.data;12875 const n = dest_err_set_ty.castTag(.error_set_single).?.data;
12864 if (!mem.eql(u8, expected_name, n)) {12876 if (mem.eql(u8, expected_name, n)) break :ok;
12865 return sema.fail(12877 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
12866 block,
12867 inst_src,
12868 "expected type '{}', found type '{}'",
12869 .{ dest_err_set_ty, inst_ty },
12870 );
12871 }
12872 },12878 },
12873 .error_set => {12879 .error_set => ok: {
12874 const expected_name = val.castTag(.@"error").?.data.name;12880 const expected_name = val.castTag(.@"error").?.data.name;
12875 const error_set = dest_err_set_ty.castTag(.error_set).?.data;12881 const error_set = dest_err_set_ty.castTag(.error_set).?.data;
12876 const names = error_set.names_ptr[0..error_set.names_len];12882 const names = error_set.names_ptr[0..error_set.names_len];
12877 // TODO this is O(N). I'm putting off solving this until we solve inferred12883 // TODO this is O(N). I'm putting off solving this until we solve inferred
12878 // error sets at the same time.12884 // error sets at the same time.
12879 const found = for (names) |name| {12885 for (names) |name| {
12880 if (mem.eql(u8, expected_name, name)) break true;12886 if (mem.eql(u8, expected_name, name)) break :ok;
12881 } else false;
12882 if (!found) {
12883 return sema.fail(
12884 block,
12885 inst_src,
12886 "expected type '{}', found type '{}'",
12887 .{ dest_err_set_ty, inst_ty },
12888 );
12889 }12887 }
12888 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
12890 },12889 },
12891 .error_set_inferred => {12890 .error_set_inferred => ok: {
12891 const err_set_payload = dest_err_set_ty.castTag(.error_set_inferred).?.data;
12892 if (err_set_payload.is_anyerror) break :ok;
12892 const expected_name = val.castTag(.@"error").?.data.name;12893 const expected_name = val.castTag(.@"error").?.data.name;
12893 const map = &dest_err_set_ty.castTag(.error_set_inferred).?.data.map;12894 if (err_set_payload.map.contains(expected_name)) break :ok;
12894 if (!map.contains(expected_name)) {12895 // TODO error set resolution here before emitting a compile error
12895 return sema.fail(12896 return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
12896 block,
12897 inst_src,
12898 "expected type '{}', found type '{}'",
12899 .{ dest_err_set_ty, inst_ty },
12900 );
12901 }
12902 },12897 },
12903 else => unreachable,12898 else => unreachable,
12904 }12899 }
src/type.zig+5
...@@ -3869,6 +3869,11 @@ pub const Type = extern union {...@@ -3869,6 +3869,11 @@ pub const Type = extern union {
3869 .error_set_inferred => {3869 .error_set_inferred => {
3870 const func = err_set_ty.castTag(.error_set_inferred).?.data.func;3870 const func = err_set_ty.castTag(.error_set_inferred).?.data.func;
3871 try self.functions.put(gpa, func, {});3871 try self.functions.put(gpa, func, {});
3872 var it = func.owner_decl.ty.fnReturnType().errorUnionSet()
3873 .castTag(.error_set_inferred).?.data.map.iterator();
3874 while (it.next()) |entry| {
3875 try self.map.put(gpa, entry.key_ptr.*, {});
3876 }
3872 },3877 },
3873 .anyerror => {3878 .anyerror => {
3874 self.is_anyerror = true;3879 self.is_anyerror = true;