authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-03-22 01:58:13+00:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-03-24 07:02:05+01:00
logeedfce92b0363af1b6783ab626690be0aebf4e94
tree46737c202817453f4ebe2bcbf529b29c51946d09
parent7b9e482ed6aaf9c1ec25970f599ae8f7ef83ad47
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

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

2 files changed, 35 insertions(+), 14 deletions(-)

src/Sema.zig+11-14
...@@ -31031,20 +31031,17 @@ fn coerceInMemoryAllowedFns(...@@ -31031,20 +31031,17 @@ fn coerceInMemoryAllowedFns(
31031 } };31031 } };
31032 }31032 }
3103331033
31034 switch (src_param_ty.toIntern()) {31034 if (!src_param_ty.isGenericPoison() and !dest_param_ty.isGenericPoison()) {
31035 .generic_poison_type => {},31035 // Note: Cast direction is reversed here.
31036 else => {31036 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, dest_is_mut, target, dest_src, src_src, null);
31037 // Note: Cast direction is reversed here.31037 if (param != .ok) {
31038 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, dest_is_mut, target, dest_src, src_src, null);31038 return .{ .fn_param = .{
31039 if (param != .ok) {31039 .child = try param.dupe(sema.arena),
31040 return .{ .fn_param = .{31040 .actual = src_param_ty,
31041 .child = try param.dupe(sema.arena),31041 .wanted = dest_param_ty,
31042 .actual = src_param_ty,31042 .index = param_i,
31043 .wanted = dest_param_ty,31043 } };
31044 .index = param_i,31044 }
31045 } };
31046 }
31047 },
31048 }31045 }
31049 }31046 }
3105031047
test/behavior/fn.zig+24
...@@ -732,3 +732,27 @@ test "inline function return type is evaluated at comptime" {...@@ -732,3 +732,27 @@ test "inline function return type is evaluated at comptime" {
732 comptime assert(@TypeOf(result) == u16);732 comptime assert(@TypeOf(result) == u16);
733 try expect(result == 123);733 try expect(result == 123);
734}734}
735
736test "coerce generic function making concrete parameter generic" {
737 const S = struct {
738 fn foo(_: anytype, x: u32) u32 {
739 comptime assert(@TypeOf(x) == u32);
740 return x;
741 }
742 };
743 const coerced: fn (anytype, anytype) u32 = S.foo;
744 const result = coerced({}, 123);
745 try expect(result == 123);
746}
747
748test "coerce generic function making generic parameter concrete" {
749 const S = struct {
750 fn foo(_: anytype, x: anytype) u32 {
751 comptime assert(@TypeOf(x) == u32);
752 return x;
753 }
754 };
755 const coerced: fn (anytype, u32) u32 = S.foo;
756 const result = coerced({}, 123);
757 try expect(result == 123);
758}