diff --git a/src/Sema.zig b/src/Sema.zig index bb14943e22..95b8d8acdf 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20411,7 +20411,7 @@ fn coerceExtra( const InMemoryCoercionResult = union(enum) { ok, no_match: Pair, - int_mismatch: Int, + int_not_coercible: Int, error_union_payload: PairAndChild, array_len: IntPair, array_sentinel: Sentinel, @@ -20527,7 +20527,7 @@ const InMemoryCoercionResult = union(enum) { try sema.addDeclaredHereNote(msg, types.actual); break; }, - .int_mismatch => |int| { + .int_not_coercible => |int| { try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{ @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits, }); @@ -20768,17 +20768,25 @@ fn coerceInMemoryAllowed( if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { const dest_info = dest_ty.intInfo(target); const src_info = src_ty.intInfo(target); - if (dest_info.signedness != src_info.signedness or - dest_info.bits != src_info.bits) + + if (dest_info.signedness == src_info.signedness and + dest_info.bits == src_info.bits) { - return InMemoryCoercionResult{ .int_mismatch = .{ + return .ok; + } + + if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or + // small enough unsigned ints can get casted to large enough signed ints + (dest_info.signedness == .signed and (src_info.signedness == .unsigned or dest_info.bits <= src_info.bits)) or + (dest_info.signedness == .unsigned and src_info.signedness == .signed)) + { + return InMemoryCoercionResult{ .int_not_coercible = .{ .actual_signedness = src_info.signedness, .wanted_signedness = dest_info.signedness, .actual_bits = src_info.bits, .wanted_bits = dest_info.bits, } }; } - return .ok; } // Differently-named floats with the same number of bits. diff --git a/test/cases/compile_errors/cast_between_optional_T_where_T_is_not_a_pointer.zig b/test/cases/compile_errors/cast_between_optional_T_where_T_is_not_a_pointer.zig index a09059eb3e..dcccd0fb8a 100644 --- a/test/cases/compile_errors/cast_between_optional_T_where_T_is_not_a_pointer.zig +++ b/test/cases/compile_errors/cast_between_optional_T_where_T_is_not_a_pointer.zig @@ -1,11 +1,18 @@ pub const fnty1 = ?*const fn (i8) void; pub const fnty2 = ?*const fn (u64) void; -export fn entry() void { +export fn entry1() void { var a: fnty1 = undefined; var b: fnty2 = undefined; a = b; } +pub const fnty3 = ?*const fn (u63) void; +export fn entry2() void { + var a: fnty3 = undefined; + var b: fnty2 = undefined; + a = b; +} + // error // backend=stage2 // target=native @@ -14,3 +21,6 @@ export fn entry() void { // :6:9: note: pointer type child 'fn(u64) void' cannot cast into pointer type child 'fn(i8) void' // :6:9: note: parameter 0 'u64' cannot cast into 'i8' // :6:9: note: unsigned 64-bit int cannot represent all possible signed 8-bit values +// :13:9: error: expected type '?*const fn(u63) void', found '?*const fn(u64) void' +// :13:9: note: pointer type child 'fn(u64) void' cannot cast into pointer type child 'fn(u63) void' +// :13:9: note: parameter 0 'u64' cannot cast into 'u63'