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(...@@ -6308,22 +6308,8 @@ fn zirCall(
6308 }6308 }
63096309
6310 const callee_ty = sema.typeOf(func);6310 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
6325 const total_args = args_len + @boolToInt(bound_arg_src != null);6311 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
6328 const args_body = sema.code.extra[extra.end..];6314 const args_body = sema.code.extra[extra.end..];
63296315
...@@ -6423,18 +6409,49 @@ fn checkCallArgumentCount(...@@ -6423,18 +6409,49 @@ fn checkCallArgumentCount(
6423 block: *Block,6409 block: *Block,
6424 func: Air.Inst.Ref,6410 func: Air.Inst.Ref,
6425 func_src: LazySrcLoc,6411 func_src: LazySrcLoc,
6426 func_ty: Type,6412 callee_ty: Type,
6427 total_args: usize,6413 total_args: usize,
6428 member_fn: bool,6414 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
6430 const func_ty_info = func_ty.fnInfo();6447 const func_ty_info = func_ty.fnInfo();
6431 const fn_params_len = func_ty_info.param_types.len;6448 const fn_params_len = func_ty_info.param_types.len;
6432 const args_len = total_args - @boolToInt(member_fn);6449 const args_len = total_args - @boolToInt(member_fn);
6433 if (func_ty_info.is_var_args) {6450 if (func_ty_info.is_var_args) {
6434 assert(func_ty_info.cc == .C);6451 assert(func_ty_info.cc == .C);
6435 if (total_args >= fn_params_len) return;6452 if (total_args >= fn_params_len) return func_ty;
6436 } else if (fn_params_len == total_args) {6453 } else if (fn_params_len == total_args) {
6437 return;6454 return func_ty;
6438 }6455 }
64396456
6440 const maybe_decl = try sema.funcDeclSrc(func);6457 const maybe_decl = try sema.funcDeclSrc(func);
...@@ -21666,20 +21683,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -21666,20 +21683,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
21666 }21683 }
2166721684
21668 const callee_ty = sema.typeOf(func);21685 const callee_ty = sema.typeOf(func);
21669 const func_ty = func_ty: {21686 const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
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);
2168321687
21684 const ensure_result_used = extra.flags.ensure_result_used;21688 const ensure_result_used = extra.flags.ensure_result_used;
21685 return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);21689 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'