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(...@@ -7720,7 +7720,6 @@ fn funcCommon(
7720 noalias_bits: u32,7720 noalias_bits: u32,
7721 is_noinline: bool,7721 is_noinline: bool,
7722) CompileError!Air.Inst.Ref {7722) CompileError!Air.Inst.Ref {
7723 const fn_src = LazySrcLoc.nodeOffset(src_node_offset);
7724 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };7723 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
7725 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };7724 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
77267725
...@@ -7791,13 +7790,11 @@ fn funcCommon(...@@ -7791,13 +7790,11 @@ fn funcCommon(
7791 param_types[i] = param.ty;7790 param_types[i] = param.ty;
7792 sema.analyzeParameter(7791 sema.analyzeParameter(
7793 block,7792 block,
7794 fn_src,
7795 .unneeded,7793 .unneeded,
7796 param,7794 param,
7797 comptime_params,7795 comptime_params,
7798 i,7796 i,
7799 &is_generic,7797 &is_generic,
7800 is_extern,
7801 cc_workaround,7798 cc_workaround,
7802 has_body,7799 has_body,
7803 ) catch |err| switch (err) {7800 ) catch |err| switch (err) {
...@@ -7805,13 +7802,11 @@ fn funcCommon(...@@ -7805,13 +7802,11 @@ fn funcCommon(
7805 const decl = sema.mod.declPtr(block.src_decl);7802 const decl = sema.mod.declPtr(block.src_decl);
7806 try sema.analyzeParameter(7803 try sema.analyzeParameter(
7807 block,7804 block,
7808 fn_src,
7809 Module.paramSrc(src_node_offset, sema.gpa, decl, i),7805 Module.paramSrc(src_node_offset, sema.gpa, decl, i),
7810 param,7806 param,
7811 comptime_params,7807 comptime_params,
7812 i,7808 i,
7813 &is_generic,7809 &is_generic,
7814 is_extern,
7815 cc_workaround,7810 cc_workaround,
7816 has_body,7811 has_body,
7817 );7812 );
...@@ -7821,9 +7816,10 @@ fn funcCommon(...@@ -7821,9 +7816,10 @@ fn funcCommon(
7821 };7816 };
7822 }7817 }
78237818
7819 var is_comptime_ret = false;
7824 const ret_poison = if (!is_generic) rp: {7820 const ret_poison = if (!is_generic) rp: {
7825 if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| {7821 if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| {
7826 is_generic = ret_comptime;7822 is_comptime_ret = ret_comptime;
7827 break :rp bare_return_type.tag() == .generic_poison;7823 break :rp bare_return_type.tag() == .generic_poison;
7828 } else |err| switch (err) {7824 } else |err| switch (err) {
7829 error.GenericPoison => {7825 error.GenericPoison => {
...@@ -7920,6 +7916,8 @@ fn funcCommon(...@@ -7920,6 +7916,8 @@ fn funcCommon(
7920 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});7916 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
7921 }7917 }
7922 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;7918 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
7924 break :fn_ty try Type.Tag.function.create(sema.arena, .{7922 break :fn_ty try Type.Tag.function.create(sema.arena, .{
7925 .param_types = param_types,7923 .param_types = param_types,
...@@ -8010,31 +8008,20 @@ fn funcCommon(...@@ -8010,31 +8008,20 @@ fn funcCommon(
8010fn analyzeParameter(8008fn analyzeParameter(
8011 sema: *Sema,8009 sema: *Sema,
8012 block: *Block,8010 block: *Block,
8013 func_src: LazySrcLoc,
8014 param_src: LazySrcLoc,8011 param_src: LazySrcLoc,
8015 param: Block.Param,8012 param: Block.Param,
8016 comptime_params: []bool,8013 comptime_params: []bool,
8017 i: usize,8014 i: usize,
8018 is_generic: *bool,8015 is_generic: *bool,
8019 is_extern: bool,
8020 cc: std.builtin.CallingConvention,8016 cc: std.builtin.CallingConvention,
8021 has_body: bool,8017 has_body: bool,
8022) !void {8018) !void {
8023 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);8019 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
8024 comptime_params[i] = param.is_comptime or requires_comptime;8020 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;
8026 is_generic.* = is_generic.* or this_generic;8022 is_generic.* = is_generic.* or this_generic;
8027 if (is_extern and this_generic) {8023 if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) {
8028 // TODO this check should exist somewhere for notes.8024 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
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);
8038 }8025 }
8039 if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) {8026 if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) {
8040 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});8027 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" {...@@ -235,3 +235,14 @@ test "local variable" {
235 try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));235 try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));
236 try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));236 try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));
237}237}
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{...@@ -6,4 +6,4 @@ export fn foo(comptime x: anytype, y: i32) i32{
6// backend=stage26// backend=stage2
7// target=native7// target=native
8//8//
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; }...@@ -12,9 +12,6 @@ comptime { _ = entry2; }
12// backend=stage212// backend=stage2
13// target=native13// target=native
14//14//
15// :5:12: error: extern function cannot be generic15// :1:15: error: comptime parameters not allowed in function with calling convention 'C'
16// :5:30: note: function is generic because of this parameter16// :5:30: error: comptime parameters not allowed in function with calling convention 'C'
17// :6:12: error: extern function cannot be generic17// :6:30: error: generic parameters not allowed in function with calling convention 'C'
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