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 {...@@ -5643,6 +5643,37 @@ const GenericCallAdapter = struct {
5643 }5643 }
5644};5644};
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
5646fn analyzeCall(5677fn analyzeCall(
5647 sema: *Sema,5678 sema: *Sema,
5648 block: *Block,5679 block: *Block,
...@@ -5733,9 +5764,11 @@ fn analyzeCall(...@@ -5733,9 +5764,11 @@ fn analyzeCall(
57335764
5734 var is_generic_call = func_ty_info.is_generic;5765 var is_generic_call = func_ty_info.is_generic;
5735 var is_comptime_call = block.is_comptime or modifier == .compile_time;5766 var is_comptime_call = block.is_comptime or modifier == .compile_time;
5767 var comptime_only_ret_ty = false;
5736 if (!is_comptime_call) {5768 if (!is_comptime_call) {
5737 if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {5769 if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {
5738 is_comptime_call = ct;5770 is_comptime_call = ct;
5771 comptime_only_ret_ty = ct;
5739 } else |err| switch (err) {5772 } else |err| switch (err) {
5740 error.GenericPoison => is_generic_call = true,5773 error.GenericPoison => is_generic_call = true,
5741 else => |e| return e,5774 else => |e| return e,
...@@ -5764,6 +5797,7 @@ fn analyzeCall(...@@ -5764,6 +5797,7 @@ fn analyzeCall(
5764 error.ComptimeReturn => {5797 error.ComptimeReturn => {
5765 is_inline_call = true;5798 is_inline_call = true;
5766 is_comptime_call = true;5799 is_comptime_call = true;
5800 comptime_only_ret_ty = true;
5767 },5801 },
5768 else => |e| return e,5802 else => |e| return e,
5769 }5803 }
...@@ -5774,8 +5808,12 @@ fn analyzeCall(...@@ -5774,8 +5808,12 @@ fn analyzeCall(
5774 }5808 }
57755809
5776 const result: Air.Inst.Ref = if (is_inline_call) res: {5810 const result: Air.Inst.Ref = if (is_inline_call) res: {
5777 // TODO explain why function is being called at comptime5811 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known") catch |err| {
5778 const func_val = try sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known");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 };
5779 const module_fn = switch (func_val.tag()) {5817 const module_fn = switch (func_val.tag()) {
5780 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,5818 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
5781 .function => func_val.castTag(.function).?.data,5819 .function => func_val.castTag(.function).?.data,
...@@ -5887,6 +5925,11 @@ fn analyzeCall(...@@ -5887,6 +5925,11 @@ fn analyzeCall(
5887 is_comptime_call,5925 is_comptime_call,
5888 &should_memoize,5926 &should_memoize,
5889 memoized_call_key,5927 memoized_call_key,
5928 // last 4 arguments are only used when reporting errors
5929 undefined,
5930 undefined,
5931 undefined,
5932 undefined,
5890 ) catch |err| switch (err) {5933 ) catch |err| switch (err) {
5891 error.NeededSourceLocation => {5934 error.NeededSourceLocation => {
5892 sema.inst_map.clearRetainingCapacity();5935 sema.inst_map.clearRetainingCapacity();
...@@ -5904,6 +5947,10 @@ fn analyzeCall(...@@ -5904,6 +5947,10 @@ fn analyzeCall(
5904 is_comptime_call,5947 is_comptime_call,
5905 &should_memoize,5948 &should_memoize,
5906 memoized_call_key,5949 memoized_call_key,
5950 func,
5951 func_src,
5952 func_ty_info.return_type,
5953 comptime_only_ret_ty,
5907 );5954 );
5908 return error.AnalysisFail;5955 return error.AnalysisFail;
5909 },5956 },
...@@ -6119,6 +6166,10 @@ fn analyzeInlineCallArg(...@@ -6119,6 +6166,10 @@ fn analyzeInlineCallArg(
6119 is_comptime_call: bool,6166 is_comptime_call: bool,
6120 should_memoize: *bool,6167 should_memoize: *bool,
6121 memoized_call_key: Module.MemoizedCall.Key,6168 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,
6122) !void {6173) !void {
6123 const zir_tags = sema.code.instructions.items(.tag);6174 const zir_tags = sema.code.instructions.items(.tag);
6124 switch (zir_tags[inst]) {6175 switch (zir_tags[inst]) {
...@@ -6134,14 +6185,23 @@ fn analyzeInlineCallArg(...@@ -6134,14 +6185,23 @@ fn analyzeInlineCallArg(
6134 new_fn_info.param_types[arg_i.*] = param_ty;6185 new_fn_info.param_types[arg_i.*] = param_ty;
6135 const uncasted_arg = uncasted_args[arg_i.*];6186 const uncasted_arg = uncasted_args[arg_i.*];
6136 if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) {6187 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 };
6138 }6194 }
6139 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);6195 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
6140 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);6196 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
61416197
6142 if (is_comptime_call) {6198 if (is_comptime_call) {
6143 // TODO explain why function is being called at comptime6199 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
6144 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known");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 };
6145 switch (arg_val.tag()) {6205 switch (arg_val.tag()) {
6146 .generic_poison, .generic_poison_type => {6206 .generic_poison, .generic_poison_type => {
6147 // This function is currently evaluated as part of an as-of-yet unresolvable6207 // This function is currently evaluated as part of an as-of-yet unresolvable
...@@ -6171,8 +6231,12 @@ fn analyzeInlineCallArg(...@@ -6171,8 +6231,12 @@ fn analyzeInlineCallArg(
6171 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);6231 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
61726232
6173 if (is_comptime_call) {6233 if (is_comptime_call) {
6174 // TODO explain why function is being called at comptime6234 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
6175 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known");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 };
6176 switch (arg_val.tag()) {6240 switch (arg_val.tag()) {
6177 .generic_poison, .generic_poison_type => {6241 .generic_poison, .generic_poison_type => {
6178 // This function is currently evaluated as part of an as-of-yet unresolvable6242 // 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 {...@@ -204,6 +204,7 @@ pub fn addCases(ctx: *TestContext) !void {
204 , &[_][]const u8{204 , &[_][]const u8{
205 ":3:12: error: unable to resolve comptime value",205 ":3:12: error: unable to resolve comptime value",
206 ":3:12: note: argument to function being called at comptime must be comptime known",206 ":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",
207 });208 });
208 }209 }
209210