authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-24 19:52:52+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-24 21:31:02+03:00
logcd1833044ab7505bc101c85f59889bd3ea3fac80
treed7958e47cab0b196cc2d731b74938343619a188c
parentd515d37934476365929401a0ba7e5639b09a648a

Sema: do not construct nested partial function types

Closes #12616

3 files changed, 26 insertions(+), 12 deletions(-)

src/Sema.zig+7-9
...@@ -78,6 +78,9 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},...@@ -78,6 +78,9 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
78err: ?*Module.ErrorMsg = null,78err: ?*Module.ErrorMsg = null,
79/// True when analyzing a generic instantiation. Used to suppress some errors.79/// True when analyzing a generic instantiation. Used to suppress some errors.
80is_generic_instantiation: bool = false,80is_generic_instantiation: bool = false,
81/// Set to true when analyzing a func type instruction so that nested generic
82/// function types will emit generic poison instead of a partial type.
83no_partial_func_ty: bool = false,
8184
82const std = @import("std");85const std = @import("std");
83const math = std.math;86const math = std.math;
...@@ -7917,6 +7920,7 @@ fn funcCommon(...@@ -7917,6 +7920,7 @@ fn funcCommon(
7917 if (cc_workaround == .Inline and is_noinline) {7920 if (cc_workaround == .Inline and is_noinline) {
7918 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});7921 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
7919 }7922 }
7923 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
79207924
7921 break :fn_ty try Type.Tag.function.create(sema.arena, .{7925 break :fn_ty try Type.Tag.function.create(sema.arena, .{
7922 .param_types = param_types,7926 .param_types = param_types,
...@@ -8097,25 +8101,19 @@ fn zirParam(...@@ -8097,25 +8101,19 @@ fn zirParam(
8097 // Make sure any nested param instructions don't clobber our work.8101 // Make sure any nested param instructions don't clobber our work.
8098 const prev_params = block.params;8102 const prev_params = block.params;
8099 const prev_preallocated_new_func = sema.preallocated_new_func;8103 const prev_preallocated_new_func = sema.preallocated_new_func;
8104 const prev_no_partial_func_type = sema.no_partial_func_ty;
8100 block.params = .{};8105 block.params = .{};
8101 sema.preallocated_new_func = null;8106 sema.preallocated_new_func = null;
8107 sema.no_partial_func_ty = true;
8102 defer {8108 defer {
8103 block.params.deinit(sema.gpa);8109 block.params.deinit(sema.gpa);
8104 block.params = prev_params;8110 block.params = prev_params;
8105 sema.preallocated_new_func = prev_preallocated_new_func;8111 sema.preallocated_new_func = prev_preallocated_new_func;
8112 sema.no_partial_func_ty = prev_no_partial_func_type;
8106 }8113 }
81078114
8108 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {8115 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
8109 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {8116 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
8110 if (param_ty.zigTypeTag() == .Fn and param_ty.fnInfo().is_generic) {
8111 // zirFunc will not emit error.GenericPoison to build a
8112 // partial type for generic functions but we still need to
8113 // detect if a function parameter is a generic function
8114 // to force the parent function to also be generic.
8115 if (!sema.inst_map.contains(inst)) {
8116 break :err error.GenericPoison;
8117 }
8118 }
8119 break :param_ty param_ty;8117 break :param_ty param_ty;
8120 } else |err| break :err err;8118 } else |err| break :err err;
8121 } else |err| break :err err;8119 } else |err| break :err err;
test/behavior/generics.zig+15
...@@ -342,3 +342,18 @@ test "generic instantiation of tagged union with only one field" {...@@ -342,3 +342,18 @@ test "generic instantiation of tagged union with only one field" {
342 try expect(S.foo(.{ .s = "a" }) == 1);342 try expect(S.foo(.{ .s = "a" }) == 1);
343 try expect(S.foo(.{ .s = "ab" }) == 2);343 try expect(S.foo(.{ .s = "ab" }) == 2);
344}344}
345
346test "nested generic function" {
347 const S = struct {
348 fn foo(comptime T: type, callback: *const fn (user_data: T) anyerror!void, data: T) anyerror!void {
349 try callback(data);
350 }
351 fn bar(a: u32) anyerror!void {
352 try expect(a == 123);
353 }
354
355 fn g(_: *const fn (anytype) void) void {}
356 };
357 try expect(@typeInfo(@TypeOf(S.g)).Fn.is_generic);
358 try S.foo(u32, S.bar, 123);
359}
test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig+4-3
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1fn f(_: anytype) void {}1fn f(_: anytype) void {}
2fn g(h: *const fn (anytype) void) void {2const T = *const fn (anytype) void;
3fn g(h: T) void {
3 h({});4 h({});
4}5}
5pub export fn entry() void {6pub export fn entry() void {
...@@ -19,5 +20,5 @@ pub export fn entry1() void {...@@ -19,5 +20,5 @@ pub export fn entry1() void {
19// backend=stage220// backend=stage2
20// target=native21// target=native
21//22//
22// :2:6: error: parameter of type '*const fn(anytype) void' must be declared comptime23// :3:6: error: parameter of type '*const fn(anytype) void' must be declared comptime
23// :9:34: error: parameter of type 'comptime_int' must be declared comptime24// :10:34: error: parameter of type 'comptime_int' must be declared comptime