authorgravatar for 51252236+xdBronch@users.noreply.github.comxdBronch <51252236+xdBronch@users.noreply.github.com> 2025-10-04 00:12:26-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-10-08 18:04:25+01:00
log60be67d3c0ba6ae15fa7115596734ab1e74fbcd3
tree4679e250207c5215d5df51d79a307d41443fd4eb
parent60a332406c10be922568e11dcc5144bb0f2d7a85

don't make OPV tuple fields `comptime`


4 files changed, 85 insertions(+), 46 deletions(-)

src/Sema.zig+25-20
......@@ -2824,9 +2824,6 @@ fn zirTupleDecl(
28242824 }
28252825 break :init field_init_val.toIntern();
28262826 }
2827 if (try sema.typeHasOnePossibleValue(field_type)) |opv| {
2828 break :init opv.toIntern();
2829 }
28302827 break :init .none;
28312828 };
28322829 }
......@@ -21479,18 +21476,8 @@ fn reifyTuple(
2147921476 return sema.fail(block, src, "non-comptime tuple fields cannot specify default initialization value", .{});
2148021477 }
2148121478
21482 const default_or_opv: InternPool.Index = default: {
21483 if (field_default_value != .none) {
21484 break :default field_default_value;
21485 }
21486 if (try sema.typeHasOnePossibleValue(field_type)) |opv| {
21487 break :default opv.toIntern();
21488 }
21489 break :default .none;
21490 };
21491
2149221479 field_ty.* = field_type.toIntern();
21493 field_init.* = default_or_opv;
21480 field_init.* = field_default_value;
2149421481 }
2149521482
2149621483 return Air.internedToRef(try zcu.intern_pool.getTupleType(gpa, pt.tid, .{
......@@ -36282,13 +36269,31 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3628236269 },
3628336270
3628436271 .tuple_type => |tuple| {
36285 for (tuple.values.get(ip)) |val| {
36286 if (val == .none) return null;
36272 try ty.resolveLayout(pt);
36273
36274 if (tuple.types.len == 0) {
36275 return try pt.aggregateValue(ty, &.{});
3628736276 }
36288 // In this case the struct has all comptime-known fields and
36289 // therefore has one possible value.
36290 // TODO: write something like getCoercedInts to avoid needing to dupe
36291 return try pt.aggregateValue(ty, try sema.arena.dupe(InternPool.Index, tuple.values.get(ip)));
36277
36278 const field_vals = try sema.arena.alloc(
36279 InternPool.Index,
36280 tuple.types.len,
36281 );
36282 for (
36283 field_vals,
36284 tuple.types.get(ip),
36285 tuple.values.get(ip),
36286 ) |*field_val, field_ty, field_comptime_val| {
36287 if (field_comptime_val != .none) {
36288 field_val.* = field_comptime_val;
36289 continue;
36290 }
36291 if (try sema.typeHasOnePossibleValue(.fromInterned(field_ty))) |opv| {
36292 field_val.* = opv.toIntern();
36293 } else return null;
36294 }
36295
36296 return try pt.aggregateValue(ty, field_vals);
3629236297 },
3629336298
3629436299 .union_type => {
src/Type.zig+38-25
......@@ -2581,15 +2581,30 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
25812581 },
25822582
25832583 .tuple_type => |tuple| {
2584 for (tuple.values.get(ip)) |val| {
2585 if (val == .none) return null;
2584 if (tuple.types.len == 0) {
2585 return try pt.aggregateValue(ty, &.{});
25862586 }
2587 // In this case the struct has all comptime-known fields and
2588 // therefore has one possible value.
2589 // TODO: write something like getCoercedInts to avoid needing to dupe
2590 const duped_values = try zcu.gpa.dupe(InternPool.Index, tuple.values.get(ip));
2591 defer zcu.gpa.free(duped_values);
2592 return try pt.aggregateValue(ty, duped_values);
2587
2588 const field_vals = try zcu.gpa.alloc(
2589 InternPool.Index,
2590 tuple.types.len,
2591 );
2592 defer zcu.gpa.free(field_vals);
2593 for (
2594 field_vals,
2595 tuple.types.get(ip),
2596 tuple.values.get(ip),
2597 ) |*field_val, field_ty, field_comptime_val| {
2598 if (field_comptime_val != .none) {
2599 field_val.* = field_comptime_val;
2600 continue;
2601 }
2602 if (try Type.fromInterned(field_ty).onePossibleValue(pt)) |opv| {
2603 field_val.* = opv.toIntern();
2604 } else return null;
2605 }
2606
2607 return try pt.aggregateValue(ty, field_vals);
25932608 },
25942609
25952610 .union_type => {
......@@ -2630,24 +2645,22 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
26302645 .auto, .explicit => {
26312646 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null;
26322647
2633 switch (enum_type.names.len) {
2634 0 => {
2635 const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });
2636 return Value.fromInterned(only);
2637 },
2638 1 => {
2639 if (enum_type.values.len == 0) {
2640 const only = try pt.intern(.{ .enum_tag = .{
2641 .ty = ty.toIntern(),
2642 .int = (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern(),
2643 } });
2644 return Value.fromInterned(only);
2645 } else {
2646 return Value.fromInterned(enum_type.values.get(ip)[0]);
2647 }
2648 },
2648 return Value.fromInterned(switch (enum_type.names.len) {
2649 0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }),
2650 1 => try pt.intern(.{ .enum_tag = .{
2651 .ty = ty.toIntern(),
2652 .int = if (enum_type.values.len == 0)
2653 (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
2654 else
2655 try ip.getCoercedInts(
2656 zcu.gpa,
2657 pt.tid,
2658 ip.indexToKey(enum_type.values.get(ip)[0]).int,
2659 enum_type.tag_ty,
2660 ),
2661 } }),
26492662 else => return null,
2650 }
2663 });
26512664 },
26522665 }
26532666 },
test/behavior/tuple.zig+21
......@@ -611,3 +611,24 @@ test "field pointer of underaligned tuple" {
611611 try S.doTheTest();
612612 try comptime S.doTheTest();
613613}
614
615test "OPV tuple fields aren't comptime" {
616 const T = struct { void };
617 const t_info = @typeInfo(T);
618 try expect(!t_info.@"struct".fields[0].is_comptime);
619
620 const T2 = @Type(.{ .@"struct" = .{
621 .layout = .auto,
622 .fields = &.{.{
623 .name = "0",
624 .type = void,
625 .default_value_ptr = null,
626 .is_comptime = false,
627 .alignment = @alignOf(void),
628 }},
629 .decls = &.{},
630 .is_tuple = true,
631 } });
632 const t2_info = @typeInfo(T2);
633 try expect(!t2_info.@"struct".fields[0].is_comptime);
634}
test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig+1-1
......@@ -8,5 +8,5 @@ export fn entry() void {
88
99// error
1010//
11// :6:31: error: expected type 'tmp.S', found 'struct { comptime void = {} }'
11// :6:31: error: expected type 'tmp.S', found 'struct { void }'
1212// :1:11: note: struct declared here