diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-08-24 19:52:52 +0300 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-08-24 21:31:02 +0300 |
| commit | cd1833044ab7505bc101c85f59889bd3ea3fac80 (patch) | |
| tree | d7958e47cab0b196cc2d731b74938343619a188c | |
| parent | d515d37934476365929401a0ba7e5639b09a648a (diff) | |
| download | zig-cd1833044ab7505bc101c85f59889bd3ea3fac80.tar.gz zig-cd1833044ab7505bc101c85f59889bd3ea3fac80.zip | |
Sema: do not construct nested partial function types
Closes #12616
| -rw-r--r-- | src/Sema.zig | 16 | ||||
| -rw-r--r-- | test/behavior/generics.zig | 15 | ||||
| -rw-r--r-- | test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig | 7 |
3 files changed, 26 insertions, 12 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 4f558ccae4..846b6af3bd 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -78,6 +78,9 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, err: ?*Module.ErrorMsg = null, /// True when analyzing a generic instantiation. Used to suppress some errors. is_generic_instantiation: bool = false, +/// Set to true when analyzing a func type instruction so that nested generic +/// function types will emit generic poison instead of a partial type. +no_partial_func_ty: bool = false, const std = @import("std"); const math = std.math; @@ -7917,6 +7920,7 @@ fn funcCommon( if (cc_workaround == .Inline and is_noinline) { return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); } + if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; break :fn_ty try Type.Tag.function.create(sema.arena, .{ .param_types = param_types, @@ -8097,25 +8101,19 @@ fn zirParam( // Make sure any nested param instructions don't clobber our work. const prev_params = block.params; const prev_preallocated_new_func = sema.preallocated_new_func; + const prev_no_partial_func_type = sema.no_partial_func_ty; block.params = .{}; sema.preallocated_new_func = null; + sema.no_partial_func_ty = true; defer { block.params.deinit(sema.gpa); block.params = prev_params; sema.preallocated_new_func = prev_preallocated_new_func; + sema.no_partial_func_ty = prev_no_partial_func_type; } if (sema.resolveBody(block, body, inst)) |param_ty_inst| { if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| { - if (param_ty.zigTypeTag() == .Fn and param_ty.fnInfo().is_generic) { - // zirFunc will not emit error.GenericPoison to build a - // partial type for generic functions but we still need to - // detect if a function parameter is a generic function - // to force the parent function to also be generic. - if (!sema.inst_map.contains(inst)) { - break :err error.GenericPoison; - } - } break :param_ty param_ty; } else |err| break :err err; } else |err| break :err err; diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index d930fb7d27..ba4bca0c1a 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -342,3 +342,18 @@ test "generic instantiation of tagged union with only one field" { try expect(S.foo(.{ .s = "a" }) == 1); try expect(S.foo(.{ .s = "ab" }) == 2); } + +test "nested generic function" { + const S = struct { + fn foo(comptime T: type, callback: *const fn (user_data: T) anyerror!void, data: T) anyerror!void { + try callback(data); + } + fn bar(a: u32) anyerror!void { + try expect(a == 123); + } + + fn g(_: *const fn (anytype) void) void {} + }; + try expect(@typeInfo(@TypeOf(S.g)).Fn.is_generic); + try S.foo(u32, S.bar, 123); +} diff --git a/test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig b/test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig index e4d9eed079..008d14f2fc 100644 --- a/test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig +++ b/test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig @@ -1,5 +1,6 @@ fn f(_: anytype) void {} -fn g(h: *const fn (anytype) void) void { +const T = *const fn (anytype) void; +fn g(h: T) void { h({}); } pub export fn entry() void { @@ -19,5 +20,5 @@ pub export fn entry1() void { // backend=stage2 // target=native // -// :2:6: error: parameter of type '*const fn(anytype) void' must be declared comptime -// :9:34: error: parameter of type 'comptime_int' must be declared comptime +// :3:6: error: parameter of type '*const fn(anytype) void' must be declared comptime +// :10:34: error: parameter of type 'comptime_int' must be declared comptime |
