authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-25 11:52:58+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-25 16:29:23+03:00
log4405188cf728755d41439e2606b2cba55af96ad9
tree1d01a36137bf6df9b946146abea335905d3ae585
parent3a7ea0b65e4edb3e13218023eb667792ab2d0d51

Sema: ignore comptime params in partial func type check

This fixes a bug exposed by cd1833044ab7505bc101c85f59889bd3ea3fac80 where a function type would be converted to generic_poison even after being instantiated due to containing comptime only types. This could also be fixed by just checking `is_generic_instantiation` but this way also provides better type names. Closes #12625

4 files changed, 22 insertions(+), 27 deletions(-)

src/Sema.zig+7-20
......@@ -7720,7 +7720,6 @@ fn funcCommon(
77207720 noalias_bits: u32,
77217721 is_noinline: bool,
77227722) CompileError!Air.Inst.Ref {
7723 const fn_src = LazySrcLoc.nodeOffset(src_node_offset);
77247723 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
77257724 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
77267725
......@@ -7791,13 +7790,11 @@ fn funcCommon(
77917790 param_types[i] = param.ty;
77927791 sema.analyzeParameter(
77937792 block,
7794 fn_src,
77957793 .unneeded,
77967794 param,
77977795 comptime_params,
77987796 i,
77997797 &is_generic,
7800 is_extern,
78017798 cc_workaround,
78027799 has_body,
78037800 ) catch |err| switch (err) {
......@@ -7805,13 +7802,11 @@ fn funcCommon(
78057802 const decl = sema.mod.declPtr(block.src_decl);
78067803 try sema.analyzeParameter(
78077804 block,
7808 fn_src,
78097805 Module.paramSrc(src_node_offset, sema.gpa, decl, i),
78107806 param,
78117807 comptime_params,
78127808 i,
78137809 &is_generic,
7814 is_extern,
78157810 cc_workaround,
78167811 has_body,
78177812 );
......@@ -7821,9 +7816,10 @@ fn funcCommon(
78217816 };
78227817 }
78237818
7819 var is_comptime_ret = false;
78247820 const ret_poison = if (!is_generic) rp: {
78257821 if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| {
7826 is_generic = ret_comptime;
7822 is_comptime_ret = ret_comptime;
78277823 break :rp bare_return_type.tag() == .generic_poison;
78287824 } else |err| switch (err) {
78297825 error.GenericPoison => {
......@@ -7920,6 +7916,8 @@ fn funcCommon(
79207916 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
79217917 }
79227918 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
7919 for (comptime_params) |ct| is_generic = is_generic or ct;
7920 is_generic = is_generic or is_comptime_ret;
79237921
79247922 break :fn_ty try Type.Tag.function.create(sema.arena, .{
79257923 .param_types = param_types,
......@@ -8010,31 +8008,20 @@ fn funcCommon(
80108008fn analyzeParameter(
80118009 sema: *Sema,
80128010 block: *Block,
8013 func_src: LazySrcLoc,
80148011 param_src: LazySrcLoc,
80158012 param: Block.Param,
80168013 comptime_params: []bool,
80178014 i: usize,
80188015 is_generic: *bool,
8019 is_extern: bool,
80208016 cc: std.builtin.CallingConvention,
80218017 has_body: bool,
80228018) !void {
80238019 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
80248020 comptime_params[i] = param.is_comptime or requires_comptime;
8025 const this_generic = comptime_params[i] or param.ty.tag() == .generic_poison;
8021 const this_generic = param.ty.tag() == .generic_poison;
80268022 is_generic.* = is_generic.* or this_generic;
8027 if (is_extern and this_generic) {
8028 // TODO this check should exist somewhere for notes.
8029 if (param_src == .unneeded) return error.NeededSourceLocation;
8030 const msg = msg: {
8031 const msg = try sema.errMsg(block, func_src, "extern function cannot be generic", .{});
8032 errdefer msg.destroy(sema.gpa);
8033
8034 try sema.errNote(block, param_src, msg, "function is generic because of this parameter", .{});
8035 break :msg msg;
8036 };
8037 return sema.failWithOwnedErrorMsg(msg);
8023 if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) {
8024 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
80388025 }
80398026 if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) {
80408027 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
test/behavior/typename.zig+11
......@@ -235,3 +235,14 @@ test "local variable" {
235235 try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));
236236 try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));
237237}
238
239test "comptime parameters not converted to anytype in function type" {
240 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
241 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
242 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
243 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
244 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
245
246 const T = fn (fn (type) void, void) void;
247 try expectEqualStrings("fn(fn(type) void, void) void", @typeName(T));
248}
test/cases/compile_errors/export_function_with_comptime_parameter.zig+1-1
......@@ -6,4 +6,4 @@ export fn foo(comptime x: anytype, y: i32) i32{
66// backend=stage2
77// target=native
88//
9// :1:15: error: generic parameters not allowed in function with calling convention 'C'
9// :1:15: error: comptime parameters not allowed in function with calling convention 'C'
test/cases/compile_errors/extern_function_with_comptime_parameter.zig+3-6
......@@ -12,9 +12,6 @@ comptime { _ = entry2; }
1212// backend=stage2
1313// target=native
1414//
15// :5:12: error: extern function cannot be generic
16// :5:30: note: function is generic because of this parameter
17// :6:12: error: extern function cannot be generic
18// :6:30: note: function is generic because of this parameter
19// :1:8: error: extern function cannot be generic
20// :1:15: note: function is generic because of this parameter
15// :1:15: error: comptime parameters not allowed in function with calling convention 'C'
16// :5:30: error: comptime parameters not allowed in function with calling convention 'C'
17// :6:30: error: generic parameters not allowed in function with calling convention 'C'