mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Sema: prefer original error message in coerce
This commit is contained in:
parent
b9f01bc394
commit
34fe2b4f4b
66
src/Sema.zig
66
src/Sema.zig
@ -19853,6 +19853,26 @@ fn coerce(
|
|||||||
inst: Air.Inst.Ref,
|
inst: Air.Inst.Ref,
|
||||||
inst_src: LazySrcLoc,
|
inst_src: LazySrcLoc,
|
||||||
) CompileError!Air.Inst.Ref {
|
) CompileError!Air.Inst.Ref {
|
||||||
|
return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true) catch |err| switch (err) {
|
||||||
|
error.NotCoercible => unreachable,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const CoersionError = CompileError || error{
|
||||||
|
/// When coerce is called recursively, this error should be returned instead of using `fail`
|
||||||
|
/// to ensure correct types in compile errors.
|
||||||
|
NotCoercible,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn coerceExtra(
|
||||||
|
sema: *Sema,
|
||||||
|
block: *Block,
|
||||||
|
dest_ty_unresolved: Type,
|
||||||
|
inst: Air.Inst.Ref,
|
||||||
|
inst_src: LazySrcLoc,
|
||||||
|
report_err: bool,
|
||||||
|
) CoersionError!Air.Inst.Ref {
|
||||||
switch (dest_ty_unresolved.tag()) {
|
switch (dest_ty_unresolved.tag()) {
|
||||||
.var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
|
.var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
|
||||||
.generic_poison => return inst,
|
.generic_poison => return inst,
|
||||||
@ -19869,7 +19889,7 @@ fn coerce(
|
|||||||
const arena = sema.arena;
|
const arena = sema.arena;
|
||||||
const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
|
const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
|
||||||
|
|
||||||
const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
|
var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
|
||||||
if (in_memory_result == .ok) {
|
if (in_memory_result == .ok) {
|
||||||
if (maybe_inst_val) |val| {
|
if (maybe_inst_val) |val| {
|
||||||
// Keep the comptime Value representation; take the new type.
|
// Keep the comptime Value representation; take the new type.
|
||||||
@ -19882,7 +19902,7 @@ fn coerce(
|
|||||||
const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
|
const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
|
||||||
|
|
||||||
switch (dest_ty.zigTypeTag()) {
|
switch (dest_ty.zigTypeTag()) {
|
||||||
.Optional => {
|
.Optional => optional: {
|
||||||
// undefined sets the optional bit also to undefined.
|
// undefined sets the optional bit also to undefined.
|
||||||
if (is_undef) {
|
if (is_undef) {
|
||||||
return sema.addConstUndef(dest_ty);
|
return sema.addConstUndef(dest_ty);
|
||||||
@ -19903,10 +19923,19 @@ fn coerce(
|
|||||||
|
|
||||||
// T to ?T
|
// T to ?T
|
||||||
const child_type = try dest_ty.optionalChildAlloc(sema.arena);
|
const child_type = try dest_ty.optionalChildAlloc(sema.arena);
|
||||||
const intermediate = try sema.coerce(block, child_type, inst, inst_src);
|
const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false) catch |err| switch (err) {
|
||||||
return sema.wrapOptional(block, dest_ty, intermediate, inst_src);
|
error.NotCoercible => {
|
||||||
|
if (in_memory_result == .no_match) {
|
||||||
|
// Try to give more useful notes
|
||||||
|
in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src);
|
||||||
|
}
|
||||||
|
break :optional;
|
||||||
|
},
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
|
||||||
},
|
},
|
||||||
.Pointer => {
|
.Pointer => pointer: {
|
||||||
const dest_info = dest_ty.ptrInfo().data;
|
const dest_info = dest_ty.ptrInfo().data;
|
||||||
|
|
||||||
// Function body to function pointer.
|
// Function body to function pointer.
|
||||||
@ -20011,16 +20040,26 @@ fn coerce(
|
|||||||
return sema.addConstant(dest_ty, Value.@"null");
|
return sema.addConstant(dest_ty, Value.@"null");
|
||||||
},
|
},
|
||||||
.ComptimeInt => {
|
.ComptimeInt => {
|
||||||
const addr = try sema.coerce(block, Type.usize, inst, inst_src);
|
const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false) catch |err| switch (err) {
|
||||||
return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
|
error.NotCoercible => break :pointer,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
|
||||||
},
|
},
|
||||||
.Int => {
|
.Int => {
|
||||||
const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
|
const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
|
||||||
.signed => Type.isize,
|
.signed => Type.isize,
|
||||||
.unsigned => Type.usize,
|
.unsigned => Type.usize,
|
||||||
};
|
};
|
||||||
const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src);
|
const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false) catch |err| switch (err) {
|
||||||
return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
|
error.NotCoercible => {
|
||||||
|
// Try to give more useful notes
|
||||||
|
in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src);
|
||||||
|
break :pointer;
|
||||||
|
},
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
|
||||||
},
|
},
|
||||||
.Pointer => p: {
|
.Pointer => p: {
|
||||||
const inst_info = inst_ty.ptrInfo().data;
|
const inst_info = inst_ty.ptrInfo().data;
|
||||||
@ -20155,6 +20194,7 @@ fn coerce(
|
|||||||
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
|
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
|
||||||
// comptime known integer to other number
|
// comptime known integer to other number
|
||||||
if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
|
if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
|
||||||
|
if (!report_err) return error.NotCoercible;
|
||||||
return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
|
return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
|
||||||
}
|
}
|
||||||
return try sema.addConstant(dest_ty, val);
|
return try sema.addConstant(dest_ty, val);
|
||||||
@ -20356,6 +20396,8 @@ fn coerce(
|
|||||||
return sema.addConstUndef(dest_ty);
|
return sema.addConstUndef(dest_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!report_err) return error.NotCoercible;
|
||||||
|
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
|
const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
@ -20534,8 +20576,10 @@ const InMemoryCoercionResult = union(enum) {
|
|||||||
cur = pair.child;
|
cur = pair.child;
|
||||||
},
|
},
|
||||||
.optional_shape => |pair| {
|
.optional_shape => |pair| {
|
||||||
try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type '{}'", .{
|
var buf_actual: Type.Payload.ElemType = undefined;
|
||||||
pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
|
var buf_wanted: Type.Payload.ElemType = undefined;
|
||||||
|
try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
|
||||||
|
pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
pub fn main() void {
|
pub export fn entry() void {
|
||||||
var a: ?*anyopaque = undefined;
|
var a: ?*anyopaque = undefined;
|
||||||
a = @as(?usize, null);
|
a = @as(?usize, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// output_mode=Exe
|
// backend=stage2
|
||||||
// backend=stage2,llvm
|
// target=native
|
||||||
// target=x86_64-linux,x86_64-macos
|
|
||||||
//
|
//
|
||||||
// :3:21: error: expected type '*anyopaque', found '?usize'
|
// :3:21: error: expected type '?*anyopaque', found '?usize'
|
||||||
|
// :3:21: note: optional type child 'usize' cannot cast into optional type child '*anyopaque'
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
pub const fnty1 = ?*const fn (i8) void;
|
||||||
|
pub const fnty2 = ?*const fn (u64) void;
|
||||||
|
export fn entry() void {
|
||||||
|
var a: fnty1 = undefined;
|
||||||
|
var b: fnty2 = undefined;
|
||||||
|
a = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :6:9: error: expected type '?*const fn(i8) void', found '?*const fn(u64) 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
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
export fn entry1() void {
|
||||||
|
_ = @as([*c]u8, @as(u65, std.math.maxInt(u65)));
|
||||||
|
}
|
||||||
|
export fn entry2() void {
|
||||||
|
_ = @as([*c]u8, std.math.maxInt(u65));
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :3:21: error: expected type '[*c]u8', found 'u65'
|
||||||
|
// :3:21: note: unsigned 64-bit int cannot represent all possible unsigned 65-bit values
|
||||||
|
// :6:36: error: expected type '[*c]u8', found 'comptime_int'
|
||||||
@ -1,15 +0,0 @@
|
|||||||
pub const fnty1 = ?fn (i8) void;
|
|
||||||
pub const fnty2 = ?fn (u64) void;
|
|
||||||
export fn entry() void {
|
|
||||||
var a: fnty1 = undefined;
|
|
||||||
var b: fnty2 = undefined;
|
|
||||||
a = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
// error
|
|
||||||
// backend=stage1
|
|
||||||
// target=native
|
|
||||||
// is_test=1
|
|
||||||
//
|
|
||||||
// tmp.zig:6:9: error: expected type '?fn(i8) void', found '?fn(u64) void'
|
|
||||||
// tmp.zig:6:9: note: optional type child 'fn(u64) void' cannot cast into optional type child 'fn(i8) void'
|
|
||||||
@ -10,6 +10,6 @@ export fn main() void {
|
|||||||
// backend=stage2
|
// backend=stage2
|
||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// :5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'
|
// :5:22: error: expected type '?fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'
|
||||||
// :5:22: note: parameter 0 '[*:0]u8' cannot cast into '[*c]u8'
|
// :5:22: note: parameter 0 '[*:0]u8' cannot cast into '[*c]u8'
|
||||||
// :5:22: note: '[*c]u8' could have null values which are illegal in type '[*:0]u8'
|
// :5:22: note: '[*c]u8' could have null values which are illegal in type '[*:0]u8'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user