authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-10 16:51:10+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-10 23:47:56+03:00
log34fe2b4f4be29efa8f4ba4b9f32b22373fdddc22
tree8227137b718913e1997324cac2642e66375836bc
parentb9f01bc39452042be1609b63f3066cfcac82f273

Sema: prefer original error message in `coerce`


6 files changed, 92 insertions(+), 32 deletions(-)

src/Sema.zig+55-11
...@@ -19853,6 +19853,26 @@ fn coerce(...@@ -19853,6 +19853,26 @@ fn coerce(
19853 inst: Air.Inst.Ref,19853 inst: Air.Inst.Ref,
19854 inst_src: LazySrcLoc,19854 inst_src: LazySrcLoc,
19855) CompileError!Air.Inst.Ref {19855) CompileError!Air.Inst.Ref {
19856 return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true) catch |err| switch (err) {
19857 error.NotCoercible => unreachable,
19858 else => |e| return e,
19859 };
19860}
19861
19862const CoersionError = CompileError || error{
19863 /// When coerce is called recursively, this error should be returned instead of using `fail`
19864 /// to ensure correct types in compile errors.
19865 NotCoercible,
19866};
19867
19868fn coerceExtra(
19869 sema: *Sema,
19870 block: *Block,
19871 dest_ty_unresolved: Type,
19872 inst: Air.Inst.Ref,
19873 inst_src: LazySrcLoc,
19874 report_err: bool,
19875) CoersionError!Air.Inst.Ref {
19856 switch (dest_ty_unresolved.tag()) {19876 switch (dest_ty_unresolved.tag()) {
19857 .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),19877 .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
19858 .generic_poison => return inst,19878 .generic_poison => return inst,
...@@ -19869,7 +19889,7 @@ fn coerce(...@@ -19869,7 +19889,7 @@ fn coerce(
19869 const arena = sema.arena;19889 const arena = sema.arena;
19870 const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);19890 const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
1987119891
19872 const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);19892 var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
19873 if (in_memory_result == .ok) {19893 if (in_memory_result == .ok) {
19874 if (maybe_inst_val) |val| {19894 if (maybe_inst_val) |val| {
19875 // Keep the comptime Value representation; take the new type.19895 // Keep the comptime Value representation; take the new type.
...@@ -19882,7 +19902,7 @@ fn coerce(...@@ -19882,7 +19902,7 @@ fn coerce(
19882 const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;19902 const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
1988319903
19884 switch (dest_ty.zigTypeTag()) {19904 switch (dest_ty.zigTypeTag()) {
19885 .Optional => {19905 .Optional => optional: {
19886 // undefined sets the optional bit also to undefined.19906 // undefined sets the optional bit also to undefined.
19887 if (is_undef) {19907 if (is_undef) {
19888 return sema.addConstUndef(dest_ty);19908 return sema.addConstUndef(dest_ty);
...@@ -19903,10 +19923,19 @@ fn coerce(...@@ -19903,10 +19923,19 @@ fn coerce(
1990319923
19904 // T to ?T19924 // T to ?T
19905 const child_type = try dest_ty.optionalChildAlloc(sema.arena);19925 const child_type = try dest_ty.optionalChildAlloc(sema.arena);
19906 const intermediate = try sema.coerce(block, child_type, inst, inst_src);19926 const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false) catch |err| switch (err) {
19907 return sema.wrapOptional(block, dest_ty, intermediate, inst_src);19927 error.NotCoercible => {
19928 if (in_memory_result == .no_match) {
19929 // Try to give more useful notes
19930 in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src);
19931 }
19932 break :optional;
19933 },
19934 else => |e| return e,
19935 };
19936 return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
19908 },19937 },
19909 .Pointer => {19938 .Pointer => pointer: {
19910 const dest_info = dest_ty.ptrInfo().data;19939 const dest_info = dest_ty.ptrInfo().data;
1991119940
19912 // Function body to function pointer.19941 // Function body to function pointer.
...@@ -20011,16 +20040,26 @@ fn coerce(...@@ -20011,16 +20040,26 @@ fn coerce(
20011 return sema.addConstant(dest_ty, Value.@"null");20040 return sema.addConstant(dest_ty, Value.@"null");
20012 },20041 },
20013 .ComptimeInt => {20042 .ComptimeInt => {
20014 const addr = try sema.coerce(block, Type.usize, inst, inst_src);20043 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false) catch |err| switch (err) {
20015 return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);20044 error.NotCoercible => break :pointer,
20045 else => |e| return e,
20046 };
20047 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
20016 },20048 },
20017 .Int => {20049 .Int => {
20018 const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {20050 const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
20019 .signed => Type.isize,20051 .signed => Type.isize,
20020 .unsigned => Type.usize,20052 .unsigned => Type.usize,
20021 };20053 };
20022 const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src);20054 const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false) catch |err| switch (err) {
20023 return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);20055 error.NotCoercible => {
20056 // Try to give more useful notes
20057 in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src);
20058 break :pointer;
20059 },
20060 else => |e| return e,
20061 };
20062 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
20024 },20063 },
20025 .Pointer => p: {20064 .Pointer => p: {
20026 const inst_info = inst_ty.ptrInfo().data;20065 const inst_info = inst_ty.ptrInfo().data;
...@@ -20155,6 +20194,7 @@ fn coerce(...@@ -20155,6 +20194,7 @@ fn coerce(
20155 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {20194 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
20156 // comptime known integer to other number20195 // comptime known integer to other number
20157 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {20196 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
20197 if (!report_err) return error.NotCoercible;
20158 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });20198 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
20159 }20199 }
20160 return try sema.addConstant(dest_ty, val);20200 return try sema.addConstant(dest_ty, val);
...@@ -20356,6 +20396,8 @@ fn coerce(...@@ -20356,6 +20396,8 @@ fn coerce(
20356 return sema.addConstUndef(dest_ty);20396 return sema.addConstUndef(dest_ty);
20357 }20397 }
2035820398
20399 if (!report_err) return error.NotCoercible;
20400
20359 const msg = msg: {20401 const msg = msg: {
20360 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });20402 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
20361 errdefer msg.destroy(sema.gpa);20403 errdefer msg.destroy(sema.gpa);
...@@ -20534,8 +20576,10 @@ const InMemoryCoercionResult = union(enum) {...@@ -20534,8 +20576,10 @@ const InMemoryCoercionResult = union(enum) {
20534 cur = pair.child;20576 cur = pair.child;
20535 },20577 },
20536 .optional_shape => |pair| {20578 .optional_shape => |pair| {
20537 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type '{}'", .{20579 var buf_actual: Type.Payload.ElemType = undefined;
20538 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),20580 var buf_wanted: Type.Payload.ElemType = undefined;
20581 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
20582 pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod),
20539 });20583 });
20540 break;20584 break;
20541 },20585 },
test/cases/compile_errors/any_typed_null_to_any_typed_optional.zig+5-5
...@@ -1,11 +1,11 @@...@@ -1,11 +1,11 @@
1pub fn main() void {1pub export fn entry() void {
2 var a: ?*anyopaque = undefined;2 var a: ?*anyopaque = undefined;
3 a = @as(?usize, null);3 a = @as(?usize, null);
4}4}
55
6// error6// error
7// output_mode=Exe7// backend=stage2
8// backend=stage2,llvm8// target=native
9// target=x86_64-linux,x86_64-macos
10//9//
11// :3:21: error: expected type '*anyopaque', found '?usize'10// :3:21: error: expected type '?*anyopaque', found '?usize'
11// :3:21: note: optional type child 'usize' cannot cast into optional type child '*anyopaque'
test/cases/compile_errors/cast_between_optional_T_where_T_is_not_a_pointer.zig created+16
...@@ -0,0 +1,16 @@
1pub const fnty1 = ?*const fn (i8) void;
2pub const fnty2 = ?*const fn (u64) void;
3export fn entry() void {
4 var a: fnty1 = undefined;
5 var b: fnty2 = undefined;
6 a = b;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :6:9: error: expected type '?*const fn(i8) void', found '?*const fn(u64) void'
14// :6:9: note: pointer type child 'fn(u64) void' cannot cast into pointer type child 'fn(i8) void'
15// :6:9: note: parameter 0 'u64' cannot cast into 'i8'
16// :6:9: note: unsigned 64-bit int cannot represent all possible signed 8-bit values
test/cases/compile_errors/implicit_cast_to_c_ptr_from_int.zig created+15
...@@ -0,0 +1,15 @@
1const std = @import("std");
2export fn entry1() void {
3 _ = @as([*c]u8, @as(u65, std.math.maxInt(u65)));
4}
5export fn entry2() void {
6 _ = @as([*c]u8, std.math.maxInt(u65));
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :3:21: error: expected type '[*c]u8', found 'u65'
14// :3:21: note: unsigned 64-bit int cannot represent all possible unsigned 65-bit values
15// :6:36: error: expected type '[*c]u8', found 'comptime_int'
test/cases/compile_errors/stage1/test/cast_between_optional_T_where_T_is_not_a_pointer.zig deleted-15
...@@ -1,15 +0,0 @@
1pub const fnty1 = ?fn (i8) void;
2pub const fnty2 = ?fn (u64) void;
3export fn entry() void {
4 var a: fnty1 = undefined;
5 var b: fnty2 = undefined;
6 a = b;
7}
8
9// error
10// backend=stage1
11// target=native
12// is_test=1
13//
14// tmp.zig:6:9: error: expected type '?fn(i8) void', found '?fn(u64) void'
15// tmp.zig:6:9: note: optional type child 'fn(u64) void' cannot cast into optional type child 'fn(i8) void'
test/cases/compile_errors/type_mismatch_in_C_prototype_with_varargs.zig+1-1
...@@ -10,6 +10,6 @@ export fn main() void {...@@ -10,6 +10,6 @@ export fn main() void {
10// backend=stage210// backend=stage2
11// target=native11// target=native
12//12//
13// :5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'13// :5:22: error: expected type '?fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'
14// :5:22: note: parameter 0 '[*:0]u8' cannot cast into '[*c]u8'14// :5:22: note: parameter 0 '[*:0]u8' cannot cast into '[*c]u8'
15// :5:22: note: '[*c]u8' could have null values which are illegal in type '[*:0]u8'15// :5:22: note: '[*c]u8' could have null values which are illegal in type '[*:0]u8'