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:
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);
+}