aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/type.zig')
-rw-r--r--src/type.zig175
1 files changed, 151 insertions, 24 deletions
diff --git a/src/type.zig b/src/type.zig
index 8084da34de..6e58f7a42f 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -131,6 +131,7 @@ pub const Type = extern union {
.export_options,
.extern_options,
.tuple,
+ .anon_struct,
=> return .Struct,
.enum_full,
@@ -792,6 +793,42 @@ pub const Type = extern union {
return true;
},
+ .anon_struct => {
+ const a_struct_obj = a.castTag(.anon_struct).?.data;
+ const b_struct_obj = (b.castTag(.anon_struct) orelse return false).data;
+
+ if (a_struct_obj.types.len != b_struct_obj.types.len) return false;
+
+ for (a_struct_obj.names) |a_name, i| {
+ const b_name = b_struct_obj.names[i];
+ if (!std.mem.eql(u8, a_name, b_name)) return false;
+ }
+
+ for (a_struct_obj.types) |a_ty, i| {
+ const b_ty = b_struct_obj.types[i];
+ if (!eql(a_ty, b_ty)) return false;
+ }
+
+ for (a_struct_obj.values) |a_val, i| {
+ const ty = a_struct_obj.types[i];
+ const b_val = b_struct_obj.values[i];
+ if (a_val.tag() == .unreachable_value) {
+ if (b_val.tag() == .unreachable_value) {
+ continue;
+ } else {
+ return false;
+ }
+ } else {
+ if (b_val.tag() == .unreachable_value) {
+ return false;
+ } else {
+ if (!Value.eql(a_val, b_val, ty)) return false;
+ }
+ }
+ }
+
+ return true;
+ },
// we can't compare these based on tags because it wouldn't detect if,
// for example, a was resolved into .@"struct" but b was one of these tags.
@@ -1062,6 +1099,20 @@ pub const Type = extern union {
field_val.hash(field_ty, hasher);
}
},
+ .anon_struct => {
+ const struct_obj = ty.castTag(.anon_struct).?.data;
+ std.hash.autoHash(hasher, std.builtin.TypeId.Struct);
+ std.hash.autoHash(hasher, struct_obj.types.len);
+
+ for (struct_obj.types) |field_ty, i| {
+ const field_name = struct_obj.names[i];
+ const field_val = struct_obj.values[i];
+ hasher.update(field_name);
+ hashWithHasher(field_ty, hasher);
+ if (field_val.tag() == .unreachable_value) continue;
+ field_val.hash(field_ty, hasher);
+ }
+ },
// we can't hash these based on tags because they wouldn't match the expanded version.
.call_options,
@@ -1279,6 +1330,26 @@ pub const Type = extern union {
.values = values,
});
},
+ .anon_struct => {
+ const payload = self.castTag(.anon_struct).?.data;
+ const names = try allocator.alloc([]const u8, payload.names.len);
+ const types = try allocator.alloc(Type, payload.types.len);
+ const values = try allocator.alloc(Value, payload.values.len);
+ for (payload.names) |name, i| {
+ names[i] = try allocator.dupe(u8, name);
+ }
+ for (payload.types) |ty, i| {
+ types[i] = try ty.copy(allocator);
+ }
+ for (payload.values) |val, i| {
+ values[i] = try val.copy(allocator);
+ }
+ return Tag.anon_struct.create(allocator, .{
+ .names = names,
+ .types = types,
+ .values = values,
+ });
+ },
.function => {
const payload = self.castTag(.function).?.data;
const param_types = try allocator.alloc(Type, payload.param_types.len);
@@ -1533,6 +1604,26 @@ pub const Type = extern union {
try writer.writeAll("}");
return;
},
+ .anon_struct => {
+ const anon_struct = ty.castTag(.anon_struct).?.data;
+ try writer.writeAll("struct{");
+ for (anon_struct.types) |field_ty, i| {
+ if (i != 0) try writer.writeAll(", ");
+ const val = anon_struct.values[i];
+ if (val.tag() != .unreachable_value) {
+ try writer.writeAll("comptime ");
+ }
+ try writer.writeAll(anon_struct.names[i]);
+ try writer.writeAll(": ");
+ try field_ty.format("", .{}, writer);
+ if (val.tag() != .unreachable_value) {
+ try writer.writeAll(" = ");
+ try val.format("", .{}, writer);
+ }
+ }
+ try writer.writeAll("}");
+ return;
+ },
.single_const_pointer => {
const pointee_type = ty.castTag(.single_const_pointer).?.data;
try writer.writeAll("*const ");
@@ -2020,8 +2111,8 @@ pub const Type = extern union {
return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits();
},
- .tuple => {
- const tuple = ty.castTag(.tuple).?.data;
+ .tuple, .anon_struct => {
+ const tuple = ty.tupleFields();
for (tuple.types) |field_ty, i| {
const val = tuple.values[i];
if (val.tag() != .unreachable_value) continue; // comptime field
@@ -2292,8 +2383,8 @@ pub const Type = extern union {
return big_align;
},
- .tuple => {
- const tuple = self.castTag(.tuple).?.data;
+ .tuple, .anon_struct => {
+ const tuple = self.tupleFields();
var big_align: u32 = 0;
for (tuple.types) |field_ty, i| {
const val = tuple.values[i];
@@ -2375,7 +2466,7 @@ pub const Type = extern union {
.void,
=> 0,
- .@"struct", .tuple => switch (self.containerLayout()) {
+ .@"struct", .tuple, .anon_struct => switch (self.containerLayout()) {
.Packed => {
const struct_obj = self.castTag(.@"struct").?.data;
var buf: Type.Payload.Bits = undefined;
@@ -2575,6 +2666,13 @@ pub const Type = extern union {
.bound_fn => unreachable,
.void => 0,
+ .bool, .u1 => 1,
+ .u8, .i8 => 8,
+ .i16, .u16, .f16 => 16,
+ .i32, .u32, .f32 => 32,
+ .i64, .u64, .f64 => 64,
+ .f80 => 80,
+ .u128, .i128, .f128 => 128,
.@"struct" => {
const field_count = ty.structFieldCount();
@@ -2595,8 +2693,13 @@ pub const Type = extern union {
}
},
- .tuple => {
- @panic("TODO bitSize tuples");
+ .tuple, .anon_struct => {
+ const tuple = ty.tupleFields();
+ var total: u64 = 0;
+ for (tuple.types) |field_ty| {
+ total += field_ty.bitSize(target);
+ }
+ return total;
},
.enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
@@ -2608,10 +2711,6 @@ pub const Type = extern union {
@panic("TODO bitSize unions");
},
- .u8, .i8 => 8,
-
- .bool, .u1 => 1,
-
.vector => {
const payload = ty.castTag(.vector).?.data;
const elem_bit_size = payload.elem_type.bitSize(target);
@@ -2634,11 +2733,6 @@ pub const Type = extern union {
);
return payload.len * 8 * elem_size + payload.elem_type.bitSize(target);
},
- .i16, .u16, .f16 => 16,
- .i32, .u32, .f32 => 32,
- .i64, .u64, .f64 => 64,
- .f80 => 80,
- .u128, .i128, .f128 => 128,
.isize,
.usize,
@@ -3295,7 +3389,7 @@ pub const Type = extern union {
pub fn containerLayout(ty: Type) std.builtin.TypeInfo.ContainerLayout {
return switch (ty.tag()) {
- .tuple, .empty_struct_literal => .Auto,
+ .tuple, .empty_struct_literal, .anon_struct => .Auto,
.@"struct" => ty.castTag(.@"struct").?.data.layout,
.@"union" => ty.castTag(.@"union").?.data.layout,
.union_tagged => ty.castTag(.union_tagged).?.data.layout,
@@ -3369,6 +3463,7 @@ pub const Type = extern union {
.array_u8 => ty.castTag(.array_u8).?.data,
.array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data,
.tuple => ty.castTag(.tuple).?.data.types.len,
+ .anon_struct => ty.castTag(.anon_struct).?.data.types.len,
.@"struct" => ty.castTag(.@"struct").?.data.fields.count(),
else => unreachable,
@@ -3383,6 +3478,7 @@ pub const Type = extern union {
return switch (ty.tag()) {
.vector => @intCast(u32, ty.castTag(.vector).?.data.len),
.tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len),
+ .anon_struct => @intCast(u32, ty.castTag(.anon_struct).?.data.types.len),
else => unreachable,
};
}
@@ -3849,8 +3945,8 @@ pub const Type = extern union {
return Value.initTag(.empty_struct_value);
},
- .tuple => {
- const tuple = ty.castTag(.tuple).?.data;
+ .tuple, .anon_struct => {
+ const tuple = ty.tupleFields();
for (tuple.values) |val| {
if (val.tag() == .unreachable_value) {
return null; // non-comptime field
@@ -4048,8 +4144,8 @@ pub const Type = extern union {
return ty.optionalChild(&buf).comptimeOnly();
},
- .tuple => {
- const tuple = ty.castTag(.tuple).?.data;
+ .tuple, .anon_struct => {
+ const tuple = ty.tupleFields();
for (tuple.types) |field_ty, i| {
const have_comptime_val = tuple.values[i].tag() != .unreachable_value;
if (!have_comptime_val and field_ty.comptimeOnly()) return true;
@@ -4350,6 +4446,7 @@ pub const Type = extern union {
},
.empty_struct, .empty_struct_literal => return 0,
.tuple => return ty.castTag(.tuple).?.data.types.len,
+ .anon_struct => return ty.castTag(.anon_struct).?.data.types.len,
else => unreachable,
}
}
@@ -4366,6 +4463,7 @@ pub const Type = extern union {
return union_obj.fields.values()[index].ty;
},
.tuple => return ty.castTag(.tuple).?.data.types[index],
+ .anon_struct => return ty.castTag(.anon_struct).?.data.types[index],
else => unreachable,
}
}
@@ -4424,8 +4522,8 @@ pub const Type = extern union {
return std.mem.alignForwardGeneric(u64, it.offset, it.big_align);
},
- .tuple => {
- const tuple = ty.castTag(.tuple).?.data;
+ .tuple, .anon_struct => {
+ const tuple = ty.tupleFields();
var offset: u64 = 0;
var big_align: u32 = 0;
@@ -4700,6 +4798,8 @@ pub const Type = extern union {
vector,
/// Possible Value tags for this: @"struct"
tuple,
+ /// Possible Value tags for this: @"struct"
+ anon_struct,
pointer,
single_const_pointer,
single_mut_pointer,
@@ -4846,6 +4946,7 @@ pub const Type = extern union {
.enum_numbered => Payload.EnumNumbered,
.empty_struct => Payload.ContainerScope,
.tuple => Payload.Tuple,
+ .anon_struct => Payload.AnonStruct,
};
}
@@ -4869,12 +4970,26 @@ pub const Type = extern union {
};
pub fn isTuple(ty: Type) bool {
- return ty.tag() == .tuple or ty.tag() == .empty_struct_literal;
+ return switch (ty.tag()) {
+ .tuple, .empty_struct_literal => true,
+ else => false,
+ };
+ }
+
+ pub fn isTupleOrAnonStruct(ty: Type) bool {
+ return switch (ty.tag()) {
+ .tuple, .empty_struct_literal, .anon_struct => true,
+ else => false,
+ };
}
pub fn tupleFields(ty: Type) Payload.Tuple.Data {
return switch (ty.tag()) {
.tuple => ty.castTag(.tuple).?.data,
+ .anon_struct => .{
+ .types = ty.castTag(.anon_struct).?.data.types,
+ .values = ty.castTag(.anon_struct).?.data.values,
+ },
.empty_struct_literal => .{ .types = &.{}, .values = &.{} },
else => unreachable,
};
@@ -5042,6 +5157,18 @@ pub const Type = extern union {
};
};
+ pub const AnonStruct = struct {
+ base: Payload = .{ .tag = .anon_struct },
+ data: Data,
+
+ pub const Data = struct {
+ names: []const []const u8,
+ types: []Type,
+ /// unreachable_value elements are used to indicate runtime-known.
+ values: []Value,
+ };
+ };
+
pub const Union = struct {
base: Payload,
data: *Module.Union,