zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 26fdb81c16760b5aabbd1905ef96cefdf596fc3d (tree)
parent 98640cbeb8a714a451821a51f3aa4ebbd488d291
Author: mlugg <mlugg@mlugg.co.uk>
Date:   Sat, 22 Mar 2025 01:58:13 +0000

Sema: fix in-memory coercion of functions introducing new generic parameters

While it is not allowed for a function coercion to change whether a
function is generic, it *is* okay to make existing concrete parameters
of a generic function also generic, or vice versa. Either of these cases
implies that the result is a generic function, so comptime type checks
will happen when the function is ultimately called.

Resolves: #21099

Diffstat:
Msrc/Sema.zig | 25+++++++++++--------------
Mtest/behavior/fn.zig | 24++++++++++++++++++++++++
2 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/src/Sema.zig b/src/Sema.zig @@ -30422,20 +30422,17 @@ fn coerceInMemoryAllowedFns( } }; } - switch (src_param_ty.toIntern()) { - .generic_poison_type => {}, - else => { - // Note: Cast direction is reversed here. - const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, dest_is_mut, target, dest_src, src_src, null); - if (param != .ok) { - return .{ .fn_param = .{ - .child = try param.dupe(sema.arena), - .actual = src_param_ty, - .wanted = dest_param_ty, - .index = param_i, - } }; - } - }, + if (!src_param_ty.isGenericPoison() and !dest_param_ty.isGenericPoison()) { + // Note: Cast direction is reversed here. + const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, dest_is_mut, target, dest_src, src_src, null); + if (param != .ok) { + return .{ .fn_param = .{ + .child = try param.dupe(sema.arena), + .actual = src_param_ty, + .wanted = dest_param_ty, + .index = param_i, + } }; + } } } diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig @@ -732,3 +732,27 @@ test "inline function return type is evaluated at comptime" { comptime assert(@TypeOf(result) == u16); try expect(result == 123); } + +test "coerce generic function making concrete parameter generic" { + const S = struct { + fn foo(_: anytype, x: u32) u32 { + comptime assert(@TypeOf(x) == u32); + return x; + } + }; + const coerced: fn (anytype, anytype) u32 = S.foo; + const result = coerced({}, 123); + try expect(result == 123); +} + +test "coerce generic function making generic parameter concrete" { + const S = struct { + fn foo(_: anytype, x: anytype) u32 { + comptime assert(@TypeOf(x) == u32); + return x; + } + }; + const coerced: fn (anytype, u32) u32 = S.foo; + const result = coerced({}, 123); + try expect(result == 123); +}