authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-05-22 13:23:21+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-05-22 19:11:38+03:00
logeef92753c7cf677191adc40a7cdf7561ceb43bdb
treeabd8efecb1544b393d713cf62f9bfa5a04db1df0
parent957f269a4259207400f7bac9bd8a200c1c5a53d7

Sema: improve error message when calling optional function

Co-authored-by: wrongnull <wrongnull@gmail.com>

2 files changed, 54 insertions(+), 33 deletions(-)

src/Sema.zig+37-33
......@@ -6308,22 +6308,8 @@ fn zirCall(
63086308 }
63096309
63106310 const callee_ty = sema.typeOf(func);
6311 const func_ty = func_ty: {
6312 switch (callee_ty.zigTypeTag()) {
6313 .Fn => break :func_ty callee_ty,
6314 .Pointer => {
6315 const ptr_info = callee_ty.ptrInfo().data;
6316 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
6317 break :func_ty ptr_info.pointee_type;
6318 }
6319 },
6320 else => {},
6321 }
6322 return sema.fail(block, callee_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
6323 };
6324
63256311 const total_args = args_len + @boolToInt(bound_arg_src != null);
6326 try sema.checkCallArgumentCount(block, func, callee_src, func_ty, total_args, bound_arg_src != null);
6312 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);
63276313
63286314 const args_body = sema.code.extra[extra.end..];
63296315
......@@ -6423,18 +6409,49 @@ fn checkCallArgumentCount(
64236409 block: *Block,
64246410 func: Air.Inst.Ref,
64256411 func_src: LazySrcLoc,
6426 func_ty: Type,
6412 callee_ty: Type,
64276413 total_args: usize,
64286414 member_fn: bool,
6429) !void {
6415) !Type {
6416 const func_ty = func_ty: {
6417 switch (callee_ty.zigTypeTag()) {
6418 .Fn => break :func_ty callee_ty,
6419 .Pointer => {
6420 const ptr_info = callee_ty.ptrInfo().data;
6421 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
6422 break :func_ty ptr_info.pointee_type;
6423 }
6424 },
6425 .Optional => {
6426 var buf: Type.Payload.ElemType = undefined;
6427 const opt_child = callee_ty.optionalChild(&buf);
6428 if (opt_child.zigTypeTag() == .Fn or (opt_child.isSinglePointer() and
6429 opt_child.childType().zigTypeTag() == .Fn))
6430 {
6431 const msg = msg: {
6432 const msg = try sema.errMsg(block, func_src, "cannot call optional type '{}'", .{
6433 callee_ty.fmt(sema.mod),
6434 });
6435 errdefer msg.destroy(sema.gpa);
6436 try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{});
6437 break :msg msg;
6438 };
6439 return sema.failWithOwnedErrorMsg(msg);
6440 }
6441 },
6442 else => {},
6443 }
6444 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
6445 };
6446
64306447 const func_ty_info = func_ty.fnInfo();
64316448 const fn_params_len = func_ty_info.param_types.len;
64326449 const args_len = total_args - @boolToInt(member_fn);
64336450 if (func_ty_info.is_var_args) {
64346451 assert(func_ty_info.cc == .C);
6435 if (total_args >= fn_params_len) return;
6452 if (total_args >= fn_params_len) return func_ty;
64366453 } else if (fn_params_len == total_args) {
6437 return;
6454 return func_ty;
64386455 }
64396456
64406457 const maybe_decl = try sema.funcDeclSrc(func);
......@@ -21666,20 +21683,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2166621683 }
2166721684
2166821685 const callee_ty = sema.typeOf(func);
21669 const func_ty = func_ty: {
21670 switch (callee_ty.zigTypeTag()) {
21671 .Fn => break :func_ty callee_ty,
21672 .Pointer => {
21673 const ptr_info = callee_ty.ptrInfo().data;
21674 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
21675 break :func_ty ptr_info.pointee_type;
21676 }
21677 },
21678 else => {},
21679 }
21680 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
21681 };
21682 try sema.checkCallArgumentCount(block, func, func_src, func_ty, resolved_args.len, false);
21686 const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
2168321687
2168421688 const ensure_result_used = extra.flags.ensure_result_used;
2168521689 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
test/cases/compile_errors/call_optional_function.zig created+17
......@@ -0,0 +1,17 @@
1pub export fn entry1() void {
2 const optional_fn: ?fn () void = null;
3 _ = optional_fn();
4}
5pub export fn entry2() void {
6 const optional_fn_ptr: ?*const fn () void = null;
7 _ = optional_fn_ptr();
8}
9
10// error
11// backend=stage2
12// target=native
13//
14// :3:9: error: cannot call optional type '?fn() void'
15// :3:9: note: consider using '.?', 'orelse' or 'if'
16// :7:9: error: cannot call optional type '?*const fn() void'
17// :7:9: note: consider using '.?', 'orelse' or 'if'