Commit e2dc77ab62

Veikka Tuominen <git@vexu.eu>
2022-08-28 13:00:26
Sema: correct one possible value for tuples
Closes #12376
1 parent 776caaf
Changed files (3)
src
test
behavior
src/Sema.zig
@@ -22248,8 +22248,7 @@ fn tupleField(
 
     if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {
         if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
-        const field_values = tuple_val.castTag(.aggregate).?.data;
-        return sema.addConstant(field_ty, field_values[field_index]);
+        return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index));
     }
 
     try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
@@ -28848,10 +28847,11 @@ pub fn typeHasOnePossibleValue(
 
         .tuple, .anon_struct => {
             const tuple = ty.tupleFields();
-            for (tuple.values) |val| {
-                if (val.tag() == .unreachable_value) {
-                    return null; // non-comptime field
-                }
+            for (tuple.values) |val, i| {
+                const is_comptime = val.tag() != .unreachable_value;
+                if (is_comptime) continue;
+                if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue; 
+                return null;
             }
             return Value.initTag(.empty_struct_value);
         },
src/type.zig
@@ -4979,19 +4979,20 @@ pub const Type = extern union {
                 const s = ty.castTag(.@"struct").?.data;
                 assert(s.haveFieldTypes());
                 for (s.fields.values()) |field| {
-                    if (field.ty.onePossibleValue() == null) {
-                        return null;
-                    }
+                    if (field.is_comptime) continue;
+                    if (field.ty.onePossibleValue() != null) continue;
+                    return null;
                 }
                 return Value.initTag(.empty_struct_value);
             },
 
             .tuple, .anon_struct => {
                 const tuple = ty.tupleFields();
-                for (tuple.values) |val| {
-                    if (val.tag() == .unreachable_value) {
-                        return null; // non-comptime field
-                    }
+                for (tuple.values) |val, i| {
+                    const is_comptime = val.tag() != .unreachable_value;
+                    if (is_comptime) continue;
+                    if (tuple.types[i].onePossibleValue() != null) continue;
+                    return null;
                 }
                 return Value.initTag(.empty_struct_value);
             },
test/behavior/tuple.zig
@@ -301,3 +301,30 @@ test "tuple type with void field" {
     const x = T{{}};
     try expect(@TypeOf(x[0]) == void);
 }
+
+test "zero sized struct in tuple handled correctly" {
+    const State = struct {
+        const Self = @This();
+        data: @Type(.{
+            .Struct = .{
+                .is_tuple = true,
+                .layout = .Auto,
+                .decls = &.{},
+                .fields = &.{.{
+                    .name = "0",
+                    .field_type = struct {},
+                    .default_value = null,
+                    .is_comptime = false,
+                    .alignment = 0,
+                }},
+            },
+        }),
+
+        pub fn do(this: Self) usize {
+            return @sizeOf(@TypeOf(this));
+        }
+    };
+
+    var s: State = undefined;
+    try expect(s.do() == 0);
+}