Tuple mutation fails in `comptime` context
Zig Version
0.10.0-dev.3351+90f23e131
Steps to Reproduce
fn foo() void {
var x: u32 = 1;
var y = .{ x, x + 1 };
y = .{ 3, 4 };
if (y[0] != 3) unreachable;
if (y[1] != 4) unreachable;
}
test {
foo(); // OK on stage1 and stage2
comptime foo(); // Encounters `unreachable` on stage1, compile error on stage2
}
Related: #11983
Expected Behavior
This function call should work the same at runtime and at comptime.
Actual Behavior
Stage 1:
./test.zig:5:20: error: reached unreachable code
if (y[0] != 3) unreachable;
^
./test.zig:11:17: note: called from here
comptime foo();
^
./test.zig:9:6: note: called from here
test {
^
Stage 2:
test.zig:4:12: error: value stored in comptime field does not match the default value of the field
y = .{ 3, 4 };
^
test.zig:11:17: note: called from here
comptime foo();
~~~^~
It's not obvious to me how to best fix this.
Tuple fields are all inferred to be comptime in a comptime context, but this ends up restricting the mutability of those fields.
I think the solution is to change how we infer "comptime-ness" of tuple fields in a comptime context. The alternative, allowing mutation of comptime fields, invites a lot of additional complications.
What if we made all tuples fully immutable? Are there strong use cases for tuple mutability?
Would that restriction be "upwardly" viral, so that tuples can't be put in any mutable container or be the target of a mutable pointer? Seems like that would mean some generics like std.ArrayList(std.meta.Tuple(&.{f32, f16})) would no longer work
no it would be only as if it was a [N]const Ts a mutable list of const tuples would still be fine
I think it would have to be upwardly viral in order to make any sense, since you can't overwrite it after it's been created no matter what. This would also mean that tuples can't get defined values after being heap allocated, which is a bit weird but not necessarily a problem IMO.
What do you think of the alternative solution of treating var in a comptime context differently than comptime var?
The main idea would be that only explicitly comptime objects (i.e. comptime var, literals, comptime params, and const objects with explicitly comptime initializers) are treated as comptime for the purpose of type inference/semantics.
Meanwhile, a comptime context would not affect type inference - it is just emulation, so a var would always be "semantically runtime-known" despite being evaluated at compile-time.