From 2c0aa1c6f551a38ee359065cce09eadb3b34cc2d Mon Sep 17 00:00:00 2001 From: xdBronch <51252236+xdBronch@users.noreply.github.com> Date: Thu, 2 Oct 2025 09:26:54 -0400 Subject: [PATCH] don't make anonymous tuple fields referencing `comptime var`s `comptime` --- src/Sema.zig | 29 +++++++++++++++++++++++++++-- test/behavior/tuple.zig | 9 +++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 640185b749..b08112d554 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20048,10 +20048,14 @@ fn arrayInitAnon( const types = try sema.arena.alloc(InternPool.Index, operands.len); const values = try sema.arena.alloc(InternPool.Index, operands.len); + var any_comptime = false; const opt_runtime_src = rs: { var runtime_src: ?LazySrcLoc = null; for (operands, 0..) |operand, i| { - const operand_src = src; // TODO better source location + const operand_src = block.src(.{ .init_elem = .{ + .init_node_offset = src.offset.node_offset.x, + .elem_index = @intCast(i), + } }); const elem = try sema.resolveInst(operand); types[i] = sema.typeOf(elem).toIntern(); if (Type.fromInterned(types[i]).zigTypeTag(zcu) == .@"opaque") { @@ -20066,6 +20070,7 @@ fn arrayInitAnon( } if (try sema.resolveValue(elem)) |val| { values[i] = val.toIntern(); + any_comptime = true; } else { values[i] = .none; runtime_src = operand_src; @@ -20074,9 +20079,21 @@ fn arrayInitAnon( break :rs runtime_src; }; + // A field can't be `comptime` if it references a `comptime var` but the aggregate can still be comptime-known. + // Replace these fields with `.none` only for generating the type. + const values_no_comptime = if (!any_comptime) values else blk: { + const new_values = try sema.arena.alloc(InternPool.Index, operands.len); + for (values, new_values) |val, *new_val| { + if (val != .none and Value.fromInterned(val).canMutateComptimeVarState(zcu)) { + new_val.* = .none; + } else new_val.* = val; + } + break :blk new_values; + }; + const tuple_ty: Type = .fromInterned(try ip.getTupleType(gpa, pt.tid, .{ .types = types, - .values = values, + .values = values_no_comptime, })); const runtime_src = opt_runtime_src orelse { @@ -20086,6 +20103,14 @@ fn arrayInitAnon( try sema.requireRuntimeBlock(block, src, runtime_src); + for (operands, 0..) |operand, i| { + const operand_src = block.src(.{ .init_elem = .{ + .init_node_offset = src.offset.node_offset.x, + .elem_index = @intCast(i), + } }); + try sema.validateRuntimeValue(block, operand_src, try sema.resolveInst(operand)); + } + if (is_ref) { const target = sema.pt.zcu.getTarget(); const alloc_ty = try pt.ptrTypeSema(.{ diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 62a25a2e0e..8c11f73235 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -486,6 +486,15 @@ test "tuple with comptime fields with non empty initializer" { _ = a; } +test "anon tuple field referencing comptime var isn't comptime" { + comptime var a: u8 = 0; + const tuple = .{&a}; + // field isn't comptime but tuple is still comptime-known + comptime assert(@TypeOf(tuple) == struct { *u8 }); + a = 1; + comptime assert(tuple[0].* == 1); +} + test "tuple with runtime value coerced into a slice with a sentinel" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO