Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand All @@ -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;
Expand All @@ -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 {
Expand All @@ -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(.{
Expand Down
9 changes: 9 additions & 0 deletions test/behavior/tuple.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down