authorgravatar for 51252236+xdBronch@users.noreply.github.comxdBronch <51252236+xdBronch@users.noreply.github.com> 2025-10-02 09:26:54-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-10-07 22:13:10+01:00
log2c0aa1c6f551a38ee359065cce09eadb3b34cc2d
tree6ede62fc5feb54fa61a136ddd681108bc1c9fa91
parent27aba2d776caf59bb6569934626af587fdba9c75

don't make anonymous tuple fields referencing `comptime var`s `comptime`


2 files changed, 36 insertions(+), 2 deletions(-)

src/Sema.zig+27-2
...@@ -20048,10 +20048,14 @@ fn arrayInitAnon(...@@ -20048,10 +20048,14 @@ fn arrayInitAnon(
20048 const types = try sema.arena.alloc(InternPool.Index, operands.len);20048 const types = try sema.arena.alloc(InternPool.Index, operands.len);
20049 const values = try sema.arena.alloc(InternPool.Index, operands.len);20049 const values = try sema.arena.alloc(InternPool.Index, operands.len);
2005020050
20051 var any_comptime = false;
20051 const opt_runtime_src = rs: {20052 const opt_runtime_src = rs: {
20052 var runtime_src: ?LazySrcLoc = null;20053 var runtime_src: ?LazySrcLoc = null;
20053 for (operands, 0..) |operand, i| {20054 for (operands, 0..) |operand, i| {
20054 const operand_src = src; // TODO better source location20055 const operand_src = block.src(.{ .init_elem = .{
20056 .init_node_offset = src.offset.node_offset.x,
20057 .elem_index = @intCast(i),
20058 } });
20055 const elem = try sema.resolveInst(operand);20059 const elem = try sema.resolveInst(operand);
20056 types[i] = sema.typeOf(elem).toIntern();20060 types[i] = sema.typeOf(elem).toIntern();
20057 if (Type.fromInterned(types[i]).zigTypeTag(zcu) == .@"opaque") {20061 if (Type.fromInterned(types[i]).zigTypeTag(zcu) == .@"opaque") {
...@@ -20066,6 +20070,7 @@ fn arrayInitAnon(...@@ -20066,6 +20070,7 @@ fn arrayInitAnon(
20066 }20070 }
20067 if (try sema.resolveValue(elem)) |val| {20071 if (try sema.resolveValue(elem)) |val| {
20068 values[i] = val.toIntern();20072 values[i] = val.toIntern();
20073 any_comptime = true;
20069 } else {20074 } else {
20070 values[i] = .none;20075 values[i] = .none;
20071 runtime_src = operand_src;20076 runtime_src = operand_src;
...@@ -20074,9 +20079,21 @@ fn arrayInitAnon(...@@ -20074,9 +20079,21 @@ fn arrayInitAnon(
20074 break :rs runtime_src;20079 break :rs runtime_src;
20075 };20080 };
2007620081
20082 // A field can't be `comptime` if it references a `comptime var` but the aggregate can still be comptime-known.
20083 // Replace these fields with `.none` only for generating the type.
20084 const values_no_comptime = if (!any_comptime) values else blk: {
20085 const new_values = try sema.arena.alloc(InternPool.Index, operands.len);
20086 for (values, new_values) |val, *new_val| {
20087 if (val != .none and Value.fromInterned(val).canMutateComptimeVarState(zcu)) {
20088 new_val.* = .none;
20089 } else new_val.* = val;
20090 }
20091 break :blk new_values;
20092 };
20093
20077 const tuple_ty: Type = .fromInterned(try ip.getTupleType(gpa, pt.tid, .{20094 const tuple_ty: Type = .fromInterned(try ip.getTupleType(gpa, pt.tid, .{
20078 .types = types,20095 .types = types,
20079 .values = values,20096 .values = values_no_comptime,
20080 }));20097 }));
2008120098
20082 const runtime_src = opt_runtime_src orelse {20099 const runtime_src = opt_runtime_src orelse {
...@@ -20086,6 +20103,14 @@ fn arrayInitAnon(...@@ -20086,6 +20103,14 @@ fn arrayInitAnon(
2008620103
20087 try sema.requireRuntimeBlock(block, src, runtime_src);20104 try sema.requireRuntimeBlock(block, src, runtime_src);
2008820105
20106 for (operands, 0..) |operand, i| {
20107 const operand_src = block.src(.{ .init_elem = .{
20108 .init_node_offset = src.offset.node_offset.x,
20109 .elem_index = @intCast(i),
20110 } });
20111 try sema.validateRuntimeValue(block, operand_src, try sema.resolveInst(operand));
20112 }
20113
20089 if (is_ref) {20114 if (is_ref) {
20090 const target = sema.pt.zcu.getTarget();20115 const target = sema.pt.zcu.getTarget();
20091 const alloc_ty = try pt.ptrTypeSema(.{20116 const alloc_ty = try pt.ptrTypeSema(.{
test/behavior/tuple.zig+9
...@@ -486,6 +486,15 @@ test "tuple with comptime fields with non empty initializer" {...@@ -486,6 +486,15 @@ test "tuple with comptime fields with non empty initializer" {
486 _ = a;486 _ = a;
487}487}
488488
489test "anon tuple field referencing comptime var isn't comptime" {
490 comptime var a: u8 = 0;
491 const tuple = .{&a};
492 // field isn't comptime but tuple is still comptime-known
493 comptime assert(@TypeOf(tuple) == struct { *u8 });
494 a = 1;
495 comptime assert(tuple[0].* == 1);
496}
497
489test "tuple with runtime value coerced into a slice with a sentinel" {498test "tuple with runtime value coerced into a slice with a sentinel" {
490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO500 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO