authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-20 01:12:58+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-21 12:24:48+03:00
loge8102d8738eafb969e03b0609c60be73326610eb
tree7d41c1b78c1263b12a519b85f6ea45d88bd51638
parent4a98385b0aa3808ab05a1ebfbc90fd0bcd97c0d9

Sema: add note about function call being comptime because of comptime only return type


4 files changed, 117 insertions(+), 7 deletions(-)

src/Sema.zig+71-7
......@@ -5643,6 +5643,37 @@ const GenericCallAdapter = struct {
56435643 }
56445644};
56455645
5646fn addComptimeReturnTypeNote(
5647 sema: *Sema,
5648 block: *Block,
5649 func: Air.Inst.Ref,
5650 func_src: LazySrcLoc,
5651 return_ty: Type,
5652 parent: *Module.ErrorMsg,
5653 requires_comptime: bool,
5654) !void {
5655 if (!requires_comptime) return;
5656
5657 const src_loc = if (try sema.funcDeclSrc(block, func_src, func)) |capture| blk: {
5658 var src_loc = capture;
5659 src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
5660 break :blk src_loc;
5661 } else blk: {
5662 const src_decl = sema.mod.declPtr(block.src_decl);
5663 break :blk func_src.toSrcLoc(src_decl);
5664 };
5665 if (return_ty.tag() == .generic_poison) {
5666 return sema.mod.errNoteNonLazy(src_loc, parent, "generic function is instantiated with a comptime only return type", .{});
5667 }
5668 try sema.mod.errNoteNonLazy(
5669 src_loc,
5670 parent,
5671 "function is being called at comptime because it returns a comptime only type '{}'",
5672 .{return_ty.fmt(sema.mod)},
5673 );
5674 try sema.explainWhyTypeIsComptime(block, func_src, parent, src_loc, return_ty);
5675}
5676
56465677fn analyzeCall(
56475678 sema: *Sema,
56485679 block: *Block,
......@@ -5733,9 +5764,11 @@ fn analyzeCall(
57335764
57345765 var is_generic_call = func_ty_info.is_generic;
57355766 var is_comptime_call = block.is_comptime or modifier == .compile_time;
5767 var comptime_only_ret_ty = false;
57365768 if (!is_comptime_call) {
57375769 if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {
57385770 is_comptime_call = ct;
5771 comptime_only_ret_ty = ct;
57395772 } else |err| switch (err) {
57405773 error.GenericPoison => is_generic_call = true,
57415774 else => |e| return e,
......@@ -5764,6 +5797,7 @@ fn analyzeCall(
57645797 error.ComptimeReturn => {
57655798 is_inline_call = true;
57665799 is_comptime_call = true;
5800 comptime_only_ret_ty = true;
57675801 },
57685802 else => |e| return e,
57695803 }
......@@ -5774,8 +5808,12 @@ fn analyzeCall(
57745808 }
57755809
57765810 const result: Air.Inst.Ref = if (is_inline_call) res: {
5777 // TODO explain why function is being called at comptime
5778 const func_val = try sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known");
5811 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known") catch |err| {
5812 if (err == error.AnalysisFail and sema.err != null) {
5813 try sema.addComptimeReturnTypeNote(block, func, func_src, func_ty_info.return_type, sema.err.?, comptime_only_ret_ty);
5814 }
5815 return err;
5816 };
57795817 const module_fn = switch (func_val.tag()) {
57805818 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
57815819 .function => func_val.castTag(.function).?.data,
......@@ -5887,6 +5925,11 @@ fn analyzeCall(
58875925 is_comptime_call,
58885926 &should_memoize,
58895927 memoized_call_key,
5928 // last 4 arguments are only used when reporting errors
5929 undefined,
5930 undefined,
5931 undefined,
5932 undefined,
58905933 ) catch |err| switch (err) {
58915934 error.NeededSourceLocation => {
58925935 sema.inst_map.clearRetainingCapacity();
......@@ -5904,6 +5947,10 @@ fn analyzeCall(
59045947 is_comptime_call,
59055948 &should_memoize,
59065949 memoized_call_key,
5950 func,
5951 func_src,
5952 func_ty_info.return_type,
5953 comptime_only_ret_ty,
59075954 );
59085955 return error.AnalysisFail;
59095956 },
......@@ -6119,6 +6166,10 @@ fn analyzeInlineCallArg(
61196166 is_comptime_call: bool,
61206167 should_memoize: *bool,
61216168 memoized_call_key: Module.MemoizedCall.Key,
6169 func: Air.Inst.Ref,
6170 func_src: LazySrcLoc,
6171 ret_ty: Type,
6172 comptime_only_ret_ty: bool,
61226173) !void {
61236174 const zir_tags = sema.code.instructions.items(.tag);
61246175 switch (zir_tags[inst]) {
......@@ -6134,14 +6185,23 @@ fn analyzeInlineCallArg(
61346185 new_fn_info.param_types[arg_i.*] = param_ty;
61356186 const uncasted_arg = uncasted_args[arg_i.*];
61366187 if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) {
6137 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known");
6188 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| {
6189 if (err == error.AnalysisFail and sema.err != null) {
6190 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6191 }
6192 return err;
6193 };
61386194 }
61396195 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
61406196 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
61416197
61426198 if (is_comptime_call) {
6143 // TODO explain why function is being called at comptime
6144 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known");
6199 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
6200 if (err == error.AnalysisFail and sema.err != null) {
6201 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6202 }
6203 return err;
6204 };
61456205 switch (arg_val.tag()) {
61466206 .generic_poison, .generic_poison_type => {
61476207 // This function is currently evaluated as part of an as-of-yet unresolvable
......@@ -6171,8 +6231,12 @@ fn analyzeInlineCallArg(
61716231 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
61726232
61736233 if (is_comptime_call) {
6174 // TODO explain why function is being called at comptime
6175 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known");
6234 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
6235 if (err == error.AnalysisFail and sema.err != null) {
6236 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6237 }
6238 return err;
6239 };
61766240 switch (arg_val.tag()) {
61776241 .generic_poison, .generic_poison_type => {
61786242 // This function is currently evaluated as part of an as-of-yet unresolvable
test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig created+23
......@@ -0,0 +1,23 @@
1const S = struct {
2 fnPtr: fn () void,
3 a: u8,
4};
5fn bar() void {}
6
7fn foo(a: u8) S {
8 return .{ .fnPtr = bar, .a = a };
9}
10pub export fn entry() void {
11 var a: u8 = 1;
12 _ = foo(a);
13}
14
15// error
16// backend=stage2
17// target=native
18//
19// :12:13: error: unable to resolve comptime value
20// :12:13: note: argument to function being called at comptime must be comptime known
21// :7:15: note: function is being called at comptime because it returns a comptime only type 'tmp.S'
22// :2:12: note: struct requires comptime because of this field
23// :2:12: note: use '*const fn() void' for a function pointer type
test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig created+22
......@@ -0,0 +1,22 @@
1fn S(comptime PtrTy: type) type {
2 return struct {
3 fnPtr: PtrTy,
4 a: u8,
5 };
6}
7fn bar() void {}
8
9fn foo(a: u8, comptime PtrTy: type) S(PtrTy) {
10 return .{ .fnPtr = bar, .a = a };
11}
12pub export fn entry() void {
13 var a: u8 = 1;
14 _ = foo(a, fn () void);
15}
16// error
17// backend=stage2
18// target=native
19//
20// :14:13: error: unable to resolve comptime value
21// :14:13: note: argument to function being called at comptime must be comptime known
22// :9:38: note: generic function is instantiated with a comptime only return type
test/compile_errors.zig+1
......@@ -204,6 +204,7 @@ pub fn addCases(ctx: *TestContext) !void {
204204 , &[_][]const u8{
205205 ":3:12: error: unable to resolve comptime value",
206206 ":3:12: note: argument to function being called at comptime must be comptime known",
207 ":2:55: note: generic function is instantiated with a comptime only return type",
207208 });
208209 }
209210