Commit 60be67d3c0
Changed files (4)
test
behavior
cases
compile_errors
src/Sema.zig
@@ -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 => {
src/Type.zig
@@ -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,
- }
+ });
},
}
},
test/behavior/tuple.zig
@@ -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);
+}
test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig
@@ -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