authorgravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2022-08-06 22:32:00+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-27 11:17:48+03:00
logae8d26a6a00a528bdf555689c2a93cb35a3287f2
treed72b651523e62b81d0b1733cf2f1a4eced7265db
parentda95da438ed5c934a9f42811651f5ffa524e48a8

Sema: add error for non-comptime param in comptime func

Adds error for taking a non comptime parameter in a function returning a comptime-only type but not when that type is dependent on a parameter. Co-authored-by: Veikka Tuominen <git@vexu.eu>

10 files changed, 95 insertions(+), 26 deletions(-)

lib/std/c.zig+1-1
...@@ -20,7 +20,7 @@ pub const Tokenizer = tokenizer.Tokenizer;...@@ -20,7 +20,7 @@ pub const Tokenizer = tokenizer.Tokenizer;
20/// If linking gnu libc (glibc), the `ok` value will be true if the target20/// If linking gnu libc (glibc), the `ok` value will be true if the target
21/// version is greater than or equal to `glibc_version`.21/// version is greater than or equal to `glibc_version`.
22/// If linking a libc other than these, returns `false`.22/// If linking a libc other than these, returns `false`.
23pub fn versionCheck(glibc_version: std.builtin.Version) type {23pub fn versionCheck(comptime glibc_version: std.builtin.Version) type {
24 return struct {24 return struct {
25 pub const ok = blk: {25 pub const ok = blk: {
26 if (!builtin.link_libc) break :blk false;26 if (!builtin.link_libc) break :blk false;
lib/std/elf.zig+2-2
...@@ -406,7 +406,7 @@ pub const Header = struct {...@@ -406,7 +406,7 @@ pub const Header = struct {
406 }406 }
407};407};
408408
409pub fn ProgramHeaderIterator(ParseSource: anytype) type {409pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
410 return struct {410 return struct {
411 elf_header: Header,411 elf_header: Header,
412 parse_source: ParseSource,412 parse_source: ParseSource,
...@@ -456,7 +456,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {...@@ -456,7 +456,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {
456 };456 };
457}457}
458458
459pub fn SectionHeaderIterator(ParseSource: anytype) type {459pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
460 return struct {460 return struct {
461 elf_header: Header,461 elf_header: Header,
462 parse_source: ParseSource,462 parse_source: ParseSource,
lib/std/io/bit_reader.zig+1-1
...@@ -7,7 +7,7 @@ const meta = std.meta;...@@ -7,7 +7,7 @@ const meta = std.meta;
7const math = std.math;7const math = std.math;
88
9/// Creates a stream which allows for reading bit fields from another stream9/// Creates a stream which allows for reading bit fields from another stream
10pub fn BitReader(endian: std.builtin.Endian, comptime ReaderType: type) type {10pub fn BitReader(comptime endian: std.builtin.Endian, comptime ReaderType: type) type {
11 return struct {11 return struct {
12 forward_reader: ReaderType,12 forward_reader: ReaderType,
13 bit_buffer: u7,13 bit_buffer: u7,
lib/std/io/bit_writer.zig+1-1
...@@ -7,7 +7,7 @@ const meta = std.meta;...@@ -7,7 +7,7 @@ const meta = std.meta;
7const math = std.math;7const math = std.math;
88
9/// Creates a stream which allows for writing bit fields to another stream9/// Creates a stream which allows for writing bit fields to another stream
10pub fn BitWriter(endian: std.builtin.Endian, comptime WriterType: type) type {10pub fn BitWriter(comptime endian: std.builtin.Endian, comptime WriterType: type) type {
11 return struct {11 return struct {
12 forward_writer: WriterType,12 forward_writer: WriterType,
13 bit_buffer: u8,13 bit_buffer: u8,
lib/std/meta.zig+1-1
...@@ -764,7 +764,7 @@ const TagPayloadType = TagPayload;...@@ -764,7 +764,7 @@ const TagPayloadType = TagPayload;
764764
765///Given a tagged union type, and an enum, return the type of the union765///Given a tagged union type, and an enum, return the type of the union
766/// field corresponding to the enum tag.766/// field corresponding to the enum tag.
767pub fn TagPayload(comptime U: type, tag: Tag(U)) type {767pub fn TagPayload(comptime U: type, comptime tag: Tag(U)) type {
768 comptime debug.assert(trait.is(.Union)(U));768 comptime debug.assert(trait.is(.Union)(U));
769769
770 const info = @typeInfo(U).Union;770 const info = @typeInfo(U).Union;
lib/std/multi_array_list.zig+1-1
...@@ -459,7 +459,7 @@ pub fn MultiArrayList(comptime S: type) type {...@@ -459,7 +459,7 @@ pub fn MultiArrayList(comptime S: type) type {
459 return self.bytes[0..capacityInBytes(self.capacity)];459 return self.bytes[0..capacityInBytes(self.capacity)];
460 }460 }
461461
462 fn FieldType(field: Field) type {462 fn FieldType(comptime field: Field) type {
463 return meta.fieldInfo(S, field).field_type;463 return meta.fieldInfo(S, field).field_type;
464 }464 }
465465
src/Sema.zig+47-14
...@@ -7816,19 +7816,17 @@ fn funcCommon(...@@ -7816,19 +7816,17 @@ fn funcCommon(
7816 };7816 };
7817 }7817 }
78187818
7819 var is_comptime_ret = false;7819 var ret_ty_requires_comptime = false;
7820 const ret_poison = if (!is_generic) rp: {7820 const ret_poison = if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| rp: {
7821 if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| {7821 ret_ty_requires_comptime = ret_comptime;
7822 is_comptime_ret = ret_comptime;7822 break :rp bare_return_type.tag() == .generic_poison;
7823 break :rp bare_return_type.tag() == .generic_poison;7823 } else |err| switch (err) {
7824 } else |err| switch (err) {7824 error.GenericPoison => rp: {
7825 error.GenericPoison => {7825 is_generic = true;
7826 is_generic = true;7826 break :rp true;
7827 break :rp true;7827 },
7828 },7828 else => |e| return e,
7829 else => |e| return e,7829 };
7830 }
7831 } else bare_return_type.tag() == .generic_poison;
78327830
7833 const return_type = if (!inferred_error_set or ret_poison)7831 const return_type = if (!inferred_error_set or ret_poison)
7834 bare_return_type7832 bare_return_type
...@@ -7873,6 +7871,41 @@ fn funcCommon(...@@ -7873,6 +7871,41 @@ fn funcCommon(
7873 return sema.failWithOwnedErrorMsg(msg);7871 return sema.failWithOwnedErrorMsg(msg);
7874 }7872 }
78757873
7874 // If the return type is comptime only but not dependent on parameters then all parameter types also need to be comptime
7875 if (!sema.is_generic_instantiation and has_body and ret_ty_requires_comptime) comptime_check: {
7876 for (block.params.items) |param| {
7877 if (!param.is_comptime) break;
7878 } else break :comptime_check;
7879
7880 const msg = try sema.errMsg(
7881 block,
7882 ret_ty_src,
7883 "function with comptime only return type '{}' requires all parameters to be comptime",
7884 .{return_type.fmt(sema.mod)},
7885 );
7886 try sema.explainWhyTypeIsComptime(block, ret_ty_src, msg, ret_ty_src.toSrcLoc(sema.owner_decl), return_type);
7887
7888 const tags = sema.code.instructions.items(.tag);
7889 const data = sema.code.instructions.items(.data);
7890 const param_body = sema.code.getParamBody(func_inst);
7891 for (block.params.items) |param, i| {
7892 if (!param.is_comptime) {
7893 const param_index = param_body[i];
7894 const param_src = switch (tags[param_index]) {
7895 .param => data[param_index].pl_tok.src(),
7896 .param_anytype => data[param_index].str_tok.src(),
7897 else => unreachable,
7898 };
7899 if (param.name.len != 0) {
7900 try sema.errNote(block, param_src, msg, "param '{s}' is required to be comptime", .{param.name});
7901 } else {
7902 try sema.errNote(block, param_src, msg, "param is required to be comptime", .{});
7903 }
7904 }
7905 }
7906 return sema.failWithOwnedErrorMsg(msg);
7907 }
7908
7876 const arch = sema.mod.getTarget().cpu.arch;7909 const arch = sema.mod.getTarget().cpu.arch;
7877 if (switch (cc_workaround) {7910 if (switch (cc_workaround) {
7878 .Unspecified, .C, .Naked, .Async, .Inline => null,7911 .Unspecified, .C, .Naked, .Async, .Inline => null,
...@@ -7917,7 +7950,7 @@ fn funcCommon(...@@ -7917,7 +7950,7 @@ fn funcCommon(
7917 }7950 }
7918 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;7951 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
7919 for (comptime_params) |ct| is_generic = is_generic or ct;7952 for (comptime_params) |ct| is_generic = is_generic or ct;
7920 is_generic = is_generic or is_comptime_ret;7953 is_generic = is_generic or ret_ty_requires_comptime;
79217954
7922 break :fn_ty try Type.Tag.function.create(sema.arena, .{7955 break :fn_ty try Type.Tag.function.create(sema.arena, .{
7923 .param_types = param_types,7956 .param_types = param_types,
test/behavior/union.zig+1-1
...@@ -745,7 +745,7 @@ fn setAttribute(attr: Attribute) void {...@@ -745,7 +745,7 @@ fn setAttribute(attr: Attribute) void {
745 _ = attr;745 _ = attr;
746}746}
747747
748fn Setter(attr: Attribute) type {748fn Setter(comptime attr: Attribute) type {
749 return struct {749 return struct {
750 fn set() void {750 fn set() void {
751 setAttribute(attr);751 setAttribute(attr);
test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig+4-4
...@@ -4,12 +4,12 @@ const S = struct {...@@ -4,12 +4,12 @@ const S = struct {
4};4};
5fn bar() void {}5fn bar() void {}
66
7fn foo(a: u8) S {7fn foo(comptime a: *u8) S {
8 return .{ .fnPtr = bar, .a = a };8 return .{ .fnPtr = bar, .a = a.* };
9}9}
10pub export fn entry() void {10pub export fn entry() void {
11 var a: u8 = 1;11 var a: u8 = 1;
12 _ = foo(a);12 _ = foo(&a);
13}13}
1414
15// error15// error
...@@ -18,6 +18,6 @@ pub export fn entry() void {...@@ -18,6 +18,6 @@ pub export fn entry() void {
18//18//
19// :12:13: error: unable to resolve comptime value19// :12:13: error: unable to resolve comptime value
20// :12:13: note: argument to function being called at comptime must be comptime known20// :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'21// :7:25: 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 field22// :2:12: note: struct requires comptime because of this field
23// :2:12: note: use '*const fn() void' for a function pointer type23// :2:12: note: use '*const fn() void' for a function pointer type
test/cases/compile_errors/non_comptime_param_in_comptime_function.zig created+36
...@@ -0,0 +1,36 @@
1fn F(val: anytype) type {
2 _ = val;
3 return struct {};
4}
5export fn entry() void {
6 _ = F(void{});
7}
8const S = struct {
9 foo: fn () void,
10};
11fn bar(_: u32) S {
12 return undefined;
13}
14export fn entry1() void {
15 _ = bar();
16}
17// prioritize other return type errors
18fn foo(a: u32) callconv(.C) comptime_int {
19 return a;
20}
21export fn entry2() void {
22 _ = foo(1);
23}
24
25// error
26// backend=stage2
27// target=native
28//
29// :1:20: error: function with comptime only return type 'type' requires all parameters to be comptime
30// :1:20: note: types are not available at runtime
31// :1:6: note: param 'val' is required to be comptime
32// :11:16: error: function with comptime only return type 'tmp.S' requires all parameters to be comptime
33// :9:10: note: struct requires comptime because of this field
34// :9:10: note: use '*const fn() void' for a function pointer type
35// :11:8: note: param is required to be comptime
36// :18:29: error: return type 'comptime_int' not allowed in function with calling convention 'C'