don't make OPV tuple fields comptime

This commit is contained in:
xdBronch 2025-10-04 00:12:26 -04:00 committed by Matthew Lugg
parent 60a332406c
commit 60be67d3c0
4 changed files with 85 additions and 46 deletions

View File

@ -2824,9 +2824,6 @@ fn zirTupleDecl(
}
break :init field_init_val.toIntern();
}
if (try sema.typeHasOnePossibleValue(field_type)) |opv| {
break :init opv.toIntern();
}
break :init .none;
};
}
@ -21479,18 +21476,8 @@ fn reifyTuple(
return sema.fail(block, src, "non-comptime tuple fields cannot specify default initialization value", .{});
}
const default_or_opv: InternPool.Index = default: {
if (field_default_value != .none) {
break :default field_default_value;
}
if (try sema.typeHasOnePossibleValue(field_type)) |opv| {
break :default opv.toIntern();
}
break :default .none;
};
field_ty.* = field_type.toIntern();
field_init.* = default_or_opv;
field_init.* = field_default_value;
}
return Air.internedToRef(try zcu.intern_pool.getTupleType(gpa, pt.tid, .{
@ -36282,13 +36269,31 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
},
.tuple_type => |tuple| {
for (tuple.values.get(ip)) |val| {
if (val == .none) return null;
try ty.resolveLayout(pt);
if (tuple.types.len == 0) {
return try pt.aggregateValue(ty, &.{});
}
// In this case the struct has all comptime-known fields and
// therefore has one possible value.
// TODO: write something like getCoercedInts to avoid needing to dupe
return try pt.aggregateValue(ty, try sema.arena.dupe(InternPool.Index, tuple.values.get(ip)));
const field_vals = try sema.arena.alloc(
InternPool.Index,
tuple.types.len,
);
for (
field_vals,
tuple.types.get(ip),
tuple.values.get(ip),
) |*field_val, field_ty, field_comptime_val| {
if (field_comptime_val != .none) {
field_val.* = field_comptime_val;
continue;
}
if (try sema.typeHasOnePossibleValue(.fromInterned(field_ty))) |opv| {
field_val.* = opv.toIntern();
} else return null;
}
return try pt.aggregateValue(ty, field_vals);
},
.union_type => {

View File

@ -2581,15 +2581,30 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
},
.tuple_type => |tuple| {
for (tuple.values.get(ip)) |val| {
if (val == .none) return null;
if (tuple.types.len == 0) {
return try pt.aggregateValue(ty, &.{});
}
// In this case the struct has all comptime-known fields and
// therefore has one possible value.
// TODO: write something like getCoercedInts to avoid needing to dupe
const duped_values = try zcu.gpa.dupe(InternPool.Index, tuple.values.get(ip));
defer zcu.gpa.free(duped_values);
return try pt.aggregateValue(ty, duped_values);
const field_vals = try zcu.gpa.alloc(
InternPool.Index,
tuple.types.len,
);
defer zcu.gpa.free(field_vals);
for (
field_vals,
tuple.types.get(ip),
tuple.values.get(ip),
) |*field_val, field_ty, field_comptime_val| {
if (field_comptime_val != .none) {
field_val.* = field_comptime_val;
continue;
}
if (try Type.fromInterned(field_ty).onePossibleValue(pt)) |opv| {
field_val.* = opv.toIntern();
} else return null;
}
return try pt.aggregateValue(ty, field_vals);
},
.union_type => {
@ -2630,24 +2645,22 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
.auto, .explicit => {
if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null;
switch (enum_type.names.len) {
0 => {
const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });
return Value.fromInterned(only);
},
1 => {
if (enum_type.values.len == 0) {
const only = try pt.intern(.{ .enum_tag = .{
.ty = ty.toIntern(),
.int = (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern(),
} });
return Value.fromInterned(only);
} else {
return Value.fromInterned(enum_type.values.get(ip)[0]);
}
},
return Value.fromInterned(switch (enum_type.names.len) {
0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }),
1 => try pt.intern(.{ .enum_tag = .{
.ty = ty.toIntern(),
.int = if (enum_type.values.len == 0)
(try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
else
try ip.getCoercedInts(
zcu.gpa,
pt.tid,
ip.indexToKey(enum_type.values.get(ip)[0]).int,
enum_type.tag_ty,
),
} }),
else => return null,
}
});
},
}
},

View File

@ -611,3 +611,24 @@ test "field pointer of underaligned tuple" {
try S.doTheTest();
try comptime S.doTheTest();
}
test "OPV tuple fields aren't comptime" {
const T = struct { void };
const t_info = @typeInfo(T);
try expect(!t_info.@"struct".fields[0].is_comptime);
const T2 = @Type(.{ .@"struct" = .{
.layout = .auto,
.fields = &.{.{
.name = "0",
.type = void,
.default_value_ptr = null,
.is_comptime = false,
.alignment = @alignOf(void),
}},
.decls = &.{},
.is_tuple = true,
} });
const t2_info = @typeInfo(T2);
try expect(!t2_info.@"struct".fields[0].is_comptime);
}

View File

@ -8,5 +8,5 @@ export fn entry() void {
// error
//
// :6:31: error: expected type 'tmp.S', found 'struct { comptime void = {} }'
// :6:31: error: expected type 'tmp.S', found 'struct { void }'
// :1:11: note: struct declared here