Commit 26fdb81c16

mlugg <mlugg@mlugg.co.uk>
2025-03-22 02:58:13
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
1 parent 98640cb
Changed files (2)
src
test
behavior
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,
+                } };
+            }
         }
     }
 
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);
+}