authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-03-22 01:58:13+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-03-24 04:32:45+00:00
log26fdb81c16760b5aabbd1905ef96cefdf596fc3d
tree1468581a8ea931bdc0ae4ad1ca962b682ec95901
parent98640cbeb8a714a451821a51f3aa4ebbd488d291

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
......@@ -30422,20 +30422,17 @@ fn coerceInMemoryAllowedFns(
3042230422 } };
3042330423 }
3042430424
30425 switch (src_param_ty.toIntern()) {
30426 .generic_poison_type => {},
30427 else => {
30428 // Note: Cast direction is reversed here.
30429 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, dest_is_mut, target, dest_src, src_src, null);
30430 if (param != .ok) {
30431 return .{ .fn_param = .{
30432 .child = try param.dupe(sema.arena),
30433 .actual = src_param_ty,
30434 .wanted = dest_param_ty,
30435 .index = param_i,
30436 } };
30437 }
30438 },
30425 if (!src_param_ty.isGenericPoison() and !dest_param_ty.isGenericPoison()) {
30426 // Note: Cast direction is reversed here.
30427 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, dest_is_mut, target, dest_src, src_src, null);
30428 if (param != .ok) {
30429 return .{ .fn_param = .{
30430 .child = try param.dupe(sema.arena),
30431 .actual = src_param_ty,
30432 .wanted = dest_param_ty,
30433 .index = param_i,
30434 } };
30435 }
3043930436 }
3044030437 }
3044130438
test/behavior/fn.zig+24
......@@ -732,3 +732,27 @@ test "inline function return type is evaluated at comptime" {
732732 comptime assert(@TypeOf(result) == u16);
733733 try expect(result == 123);
734734}
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}