commit efe73c787a89f71de37bf876c3ef7bcfddebebba (tree)
parent 7208ca510cbab5d91c566c053b27f554617cfe16
Author: Ryan Mehri <rmehri01@tutamail.com>
Date: Thu, 18 Jun 2026 20:33:35 -0400
Sema: also do comptime check on bound arg
Currently, if there is a bound arg then `analyzeArg` will break out of
the uncoerced arg block immediately without checking if the bound arg
is not comptime known despite the block or parameter being comptime.
This makes it so that we do the same checks on the bound and regular
args but only do resolution on regular args.
Diffstat:
2 files changed, 43 insertions(+), 21 deletions(-)
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -6468,22 +6468,6 @@ const CallArgsInfo = union(enum) {
const uncoerced_arg: Air.Inst.Ref = switch (cai) {
inline .resolved, .call_builtin => |resolved| resolved.args[arg_index],
.zir_call => |zir_call| arg_val: {
- const has_bound_arg = zir_call.bound_arg != .none;
- if (arg_index == 0 and has_bound_arg) {
- break :arg_val zir_call.bound_arg;
- }
- const real_arg_idx = arg_index - @intFromBool(has_bound_arg);
-
- const arg_body = if (real_arg_idx == 0) blk: {
- const start = zir_call.num_args;
- const end = @intFromEnum(zir_call.args_body[0]);
- break :blk zir_call.args_body[start..end];
- } else blk: {
- const start = @intFromEnum(zir_call.args_body[real_arg_idx - 1]);
- const end = @intFromEnum(zir_call.args_body[real_arg_idx]);
- break :blk zir_call.args_body[start..end];
- };
-
// Generate args to comptime params in comptime block
const parent_comptime = block.comptime_reason;
defer block.comptime_reason = parent_comptime;
@@ -6505,11 +6489,27 @@ const CallArgsInfo = union(enum) {
};
}
}
- // Give the arg its result type
- const provide_param_ty: Type = maybe_param_ty orelse .generic_poison;
- sema.inst_map.putAssumeCapacity(zir_call.call_inst, Air.internedToRef(provide_param_ty.toIntern()));
- // Resolve the arg!
- const uncoerced_arg = try sema.resolveInlineBody(block, arg_body, zir_call.call_inst);
+
+ const has_bound_arg = zir_call.bound_arg != .none;
+ const uncoerced_arg = if (arg_index == 0 and has_bound_arg) zir_call.bound_arg else arg: {
+ const real_arg_idx = arg_index - @intFromBool(has_bound_arg);
+
+ const arg_body = if (real_arg_idx == 0) blk: {
+ const start = zir_call.num_args;
+ const end = @intFromEnum(zir_call.args_body[0]);
+ break :blk zir_call.args_body[start..end];
+ } else blk: {
+ const start = @intFromEnum(zir_call.args_body[real_arg_idx - 1]);
+ const end = @intFromEnum(zir_call.args_body[real_arg_idx]);
+ break :blk zir_call.args_body[start..end];
+ };
+
+ // Give the arg its result type
+ const provide_param_ty: Type = maybe_param_ty orelse .generic_poison;
+ sema.inst_map.putAssumeCapacity(zir_call.call_inst, Air.internedToRef(provide_param_ty.toIntern()));
+ // Resolve the arg!
+ break :arg try sema.resolveInlineBody(block, arg_body, zir_call.call_inst);
+ };
if (block.isComptime() and !try sema.isComptimeKnown(uncoerced_arg)) {
return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null);
diff --git a/test/cases/compile_errors/runtime_bound_arg_with_comptime_param.zig b/test/cases/compile_errors/runtime_bound_arg_with_comptime_param.zig
@@ -0,0 +1,22 @@
+pub const A = enum {
+ a1,
+ a2,
+
+ pub fn x(comptime _: A) usize {
+ return 0;
+ }
+
+ pub fn y(self: A) usize {
+ return self.x();
+ }
+};
+
+pub fn main() void {
+ _ = A.y(.a1);
+}
+
+// error
+//
+// :10:20: error: unable to resolve comptime value
+// :10:20: note: argument to comptime parameter must be comptime-known
+// :5:14: note: parameter declared comptime here