mirror of
https://github.com/ziglang/zig.git
synced 2024-11-28 08:02:32 +00:00
Sema: improve error message when calling optional function
Co-authored-by: wrongnull <wrongnull@gmail.com>
This commit is contained in:
parent
957f269a42
commit
eef92753c7
70
src/Sema.zig
70
src/Sema.zig
@ -6308,22 +6308,8 @@ fn zirCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const callee_ty = sema.typeOf(func);
|
const callee_ty = sema.typeOf(func);
|
||||||
const func_ty = func_ty: {
|
|
||||||
switch (callee_ty.zigTypeTag()) {
|
|
||||||
.Fn => break :func_ty callee_ty,
|
|
||||||
.Pointer => {
|
|
||||||
const ptr_info = callee_ty.ptrInfo().data;
|
|
||||||
if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
|
|
||||||
break :func_ty ptr_info.pointee_type;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
return sema.fail(block, callee_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
|
|
||||||
};
|
|
||||||
|
|
||||||
const total_args = args_len + @boolToInt(bound_arg_src != null);
|
const total_args = args_len + @boolToInt(bound_arg_src != null);
|
||||||
try sema.checkCallArgumentCount(block, func, callee_src, func_ty, total_args, bound_arg_src != null);
|
const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);
|
||||||
|
|
||||||
const args_body = sema.code.extra[extra.end..];
|
const args_body = sema.code.extra[extra.end..];
|
||||||
|
|
||||||
@ -6423,18 +6409,49 @@ fn checkCallArgumentCount(
|
|||||||
block: *Block,
|
block: *Block,
|
||||||
func: Air.Inst.Ref,
|
func: Air.Inst.Ref,
|
||||||
func_src: LazySrcLoc,
|
func_src: LazySrcLoc,
|
||||||
func_ty: Type,
|
callee_ty: Type,
|
||||||
total_args: usize,
|
total_args: usize,
|
||||||
member_fn: bool,
|
member_fn: bool,
|
||||||
) !void {
|
) !Type {
|
||||||
|
const func_ty = func_ty: {
|
||||||
|
switch (callee_ty.zigTypeTag()) {
|
||||||
|
.Fn => break :func_ty callee_ty,
|
||||||
|
.Pointer => {
|
||||||
|
const ptr_info = callee_ty.ptrInfo().data;
|
||||||
|
if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
|
||||||
|
break :func_ty ptr_info.pointee_type;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.Optional => {
|
||||||
|
var buf: Type.Payload.ElemType = undefined;
|
||||||
|
const opt_child = callee_ty.optionalChild(&buf);
|
||||||
|
if (opt_child.zigTypeTag() == .Fn or (opt_child.isSinglePointer() and
|
||||||
|
opt_child.childType().zigTypeTag() == .Fn))
|
||||||
|
{
|
||||||
|
const msg = msg: {
|
||||||
|
const msg = try sema.errMsg(block, func_src, "cannot call optional type '{}'", .{
|
||||||
|
callee_ty.fmt(sema.mod),
|
||||||
|
});
|
||||||
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{});
|
||||||
|
break :msg msg;
|
||||||
|
};
|
||||||
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
|
||||||
|
};
|
||||||
|
|
||||||
const func_ty_info = func_ty.fnInfo();
|
const func_ty_info = func_ty.fnInfo();
|
||||||
const fn_params_len = func_ty_info.param_types.len;
|
const fn_params_len = func_ty_info.param_types.len;
|
||||||
const args_len = total_args - @boolToInt(member_fn);
|
const args_len = total_args - @boolToInt(member_fn);
|
||||||
if (func_ty_info.is_var_args) {
|
if (func_ty_info.is_var_args) {
|
||||||
assert(func_ty_info.cc == .C);
|
assert(func_ty_info.cc == .C);
|
||||||
if (total_args >= fn_params_len) return;
|
if (total_args >= fn_params_len) return func_ty;
|
||||||
} else if (fn_params_len == total_args) {
|
} else if (fn_params_len == total_args) {
|
||||||
return;
|
return func_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
const maybe_decl = try sema.funcDeclSrc(func);
|
const maybe_decl = try sema.funcDeclSrc(func);
|
||||||
@ -21666,20 +21683,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
|||||||
}
|
}
|
||||||
|
|
||||||
const callee_ty = sema.typeOf(func);
|
const callee_ty = sema.typeOf(func);
|
||||||
const func_ty = func_ty: {
|
const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
|
||||||
switch (callee_ty.zigTypeTag()) {
|
|
||||||
.Fn => break :func_ty callee_ty,
|
|
||||||
.Pointer => {
|
|
||||||
const ptr_info = callee_ty.ptrInfo().data;
|
|
||||||
if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
|
|
||||||
break :func_ty ptr_info.pointee_type;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
|
|
||||||
};
|
|
||||||
try sema.checkCallArgumentCount(block, func, func_src, func_ty, resolved_args.len, false);
|
|
||||||
|
|
||||||
const ensure_result_used = extra.flags.ensure_result_used;
|
const ensure_result_used = extra.flags.ensure_result_used;
|
||||||
return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
|
return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
|
||||||
|
17
test/cases/compile_errors/call_optional_function.zig
Normal file
17
test/cases/compile_errors/call_optional_function.zig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
pub export fn entry1() void {
|
||||||
|
const optional_fn: ?fn () void = null;
|
||||||
|
_ = optional_fn();
|
||||||
|
}
|
||||||
|
pub export fn entry2() void {
|
||||||
|
const optional_fn_ptr: ?*const fn () void = null;
|
||||||
|
_ = optional_fn_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :3:9: error: cannot call optional type '?fn() void'
|
||||||
|
// :3:9: note: consider using '.?', 'orelse' or 'if'
|
||||||
|
// :7:9: error: cannot call optional type '?*const fn() void'
|
||||||
|
// :7:9: note: consider using '.?', 'orelse' or 'if'
|
Loading…
Reference in New Issue
Block a user