diff --git a/src/Sema.zig b/src/Sema.zig index b08112d554..338980d56f 100644 --- a/src/Sema.zig +++ b/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 => { diff --git a/src/Type.zig b/src/Type.zig index cdce964356..c57d0df506 100644 --- a/src/Type.zig +++ b/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, - } + }); }, } }, diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 8c11f73235..dfd72fea7a 100644 --- a/test/behavior/tuple.zig +++ b/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); +} diff --git a/test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig b/test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig index 1c691f76ea..281d0e194a 100644 --- a/test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig +++ b/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