mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
stage2: move union types and values to InternPool
This commit is contained in:
parent
8297f28546
commit
3ba099bfba
18 changed files with 688 additions and 546 deletions
|
|
@ -21,6 +21,13 @@ allocated_structs: std.SegmentedList(Module.Struct, 0) = .{},
|
||||||
/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.
|
/// When a Struct object is freed from `allocated_structs`, it is pushed into this stack.
|
||||||
structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},
|
structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{},
|
||||||
|
|
||||||
|
/// Union objects are stored in this data structure because:
|
||||||
|
/// * They contain pointers such as the field maps.
|
||||||
|
/// * They need to be mutated after creation.
|
||||||
|
allocated_unions: std.SegmentedList(Module.Union, 0) = .{},
|
||||||
|
/// When a Union object is freed from `allocated_unions`, it is pushed into this stack.
|
||||||
|
unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{},
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|
@ -59,10 +66,7 @@ pub const Key = union(enum) {
|
||||||
/// If `empty_struct_type` is handled separately, then this value may be
|
/// If `empty_struct_type` is handled separately, then this value may be
|
||||||
/// safely assumed to never be `none`.
|
/// safely assumed to never be `none`.
|
||||||
struct_type: StructType,
|
struct_type: StructType,
|
||||||
union_type: struct {
|
union_type: UnionType,
|
||||||
fields_len: u32,
|
|
||||||
// TODO move Module.Union data to InternPool
|
|
||||||
},
|
|
||||||
opaque_type: OpaqueType,
|
opaque_type: OpaqueType,
|
||||||
|
|
||||||
simple_value: SimpleValue,
|
simple_value: SimpleValue,
|
||||||
|
|
@ -87,6 +91,8 @@ pub const Key = union(enum) {
|
||||||
/// In the case of sentinel-terminated arrays, the sentinel value *is* stored,
|
/// In the case of sentinel-terminated arrays, the sentinel value *is* stored,
|
||||||
/// so the slice length will be one more than the type's array length.
|
/// so the slice length will be one more than the type's array length.
|
||||||
aggregate: Aggregate,
|
aggregate: Aggregate,
|
||||||
|
/// An instance of a union.
|
||||||
|
un: Union,
|
||||||
|
|
||||||
pub const IntType = std.builtin.Type.Int;
|
pub const IntType = std.builtin.Type.Int;
|
||||||
|
|
||||||
|
|
@ -145,13 +151,27 @@ pub const Key = union(enum) {
|
||||||
/// - index == .none
|
/// - index == .none
|
||||||
/// * A struct which has fields as well as a namepace.
|
/// * A struct which has fields as well as a namepace.
|
||||||
pub const StructType = struct {
|
pub const StructType = struct {
|
||||||
/// This will be `none` only in the case of `@TypeOf(.{})`
|
|
||||||
/// (`Index.empty_struct_type`).
|
|
||||||
namespace: Module.Namespace.OptionalIndex,
|
|
||||||
/// The `none` tag is used to represent two cases:
|
/// The `none` tag is used to represent two cases:
|
||||||
/// * `@TypeOf(.{})`, in which case `namespace` will also be `none`.
|
/// * `@TypeOf(.{})`, in which case `namespace` will also be `none`.
|
||||||
/// * A struct with no fields, in which case `namespace` will be populated.
|
/// * A struct with no fields, in which case `namespace` will be populated.
|
||||||
index: Module.Struct.OptionalIndex,
|
index: Module.Struct.OptionalIndex,
|
||||||
|
/// This will be `none` only in the case of `@TypeOf(.{})`
|
||||||
|
/// (`Index.empty_struct_type`).
|
||||||
|
namespace: Module.Namespace.OptionalIndex,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const UnionType = struct {
|
||||||
|
index: Module.Union.Index,
|
||||||
|
runtime_tag: RuntimeTag,
|
||||||
|
|
||||||
|
pub const RuntimeTag = enum { none, safety, tagged };
|
||||||
|
|
||||||
|
pub fn hasTag(self: UnionType) bool {
|
||||||
|
return switch (self.runtime_tag) {
|
||||||
|
.none => false,
|
||||||
|
.tagged, .safety => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Int = struct {
|
pub const Int = struct {
|
||||||
|
|
@ -198,6 +218,15 @@ pub const Key = union(enum) {
|
||||||
val: Index,
|
val: Index,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Union = struct {
|
||||||
|
/// This is the union type; not the field type.
|
||||||
|
ty: Index,
|
||||||
|
/// Indicates the active field.
|
||||||
|
tag: Index,
|
||||||
|
/// The value of the active field.
|
||||||
|
val: Index,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Aggregate = struct {
|
pub const Aggregate = struct {
|
||||||
ty: Index,
|
ty: Index,
|
||||||
fields: []const Index,
|
fields: []const Index,
|
||||||
|
|
@ -229,12 +258,10 @@ pub const Key = union(enum) {
|
||||||
.extern_func,
|
.extern_func,
|
||||||
.opt,
|
.opt,
|
||||||
.struct_type,
|
.struct_type,
|
||||||
|
.union_type,
|
||||||
|
.un,
|
||||||
=> |info| std.hash.autoHash(hasher, info),
|
=> |info| std.hash.autoHash(hasher, info),
|
||||||
|
|
||||||
.union_type => |union_type| {
|
|
||||||
_ = union_type;
|
|
||||||
@panic("TODO");
|
|
||||||
},
|
|
||||||
.opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl),
|
.opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl),
|
||||||
|
|
||||||
.int => |int| {
|
.int => |int| {
|
||||||
|
|
@ -320,6 +347,14 @@ pub const Key = union(enum) {
|
||||||
const b_info = b.struct_type;
|
const b_info = b.struct_type;
|
||||||
return std.meta.eql(a_info, b_info);
|
return std.meta.eql(a_info, b_info);
|
||||||
},
|
},
|
||||||
|
.union_type => |a_info| {
|
||||||
|
const b_info = b.union_type;
|
||||||
|
return std.meta.eql(a_info, b_info);
|
||||||
|
},
|
||||||
|
.un => |a_info| {
|
||||||
|
const b_info = b.un;
|
||||||
|
return std.meta.eql(a_info, b_info);
|
||||||
|
},
|
||||||
|
|
||||||
.ptr => |a_info| {
|
.ptr => |a_info| {
|
||||||
const b_info = b.ptr;
|
const b_info = b.ptr;
|
||||||
|
|
@ -371,14 +406,6 @@ pub const Key = union(enum) {
|
||||||
@panic("TODO");
|
@panic("TODO");
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => |a_info| {
|
|
||||||
const b_info = b.union_type;
|
|
||||||
|
|
||||||
_ = a_info;
|
|
||||||
_ = b_info;
|
|
||||||
@panic("TODO");
|
|
||||||
},
|
|
||||||
|
|
||||||
.opaque_type => |a_info| {
|
.opaque_type => |a_info| {
|
||||||
const b_info = b.opaque_type;
|
const b_info = b.opaque_type;
|
||||||
return a_info.decl == b_info.decl;
|
return a_info.decl == b_info.decl;
|
||||||
|
|
@ -411,6 +438,7 @@ pub const Key = union(enum) {
|
||||||
.extern_func,
|
.extern_func,
|
||||||
.enum_tag,
|
.enum_tag,
|
||||||
.aggregate,
|
.aggregate,
|
||||||
|
.un,
|
||||||
=> |x| return x.ty,
|
=> |x| return x.ty,
|
||||||
|
|
||||||
.simple_value => |s| switch (s) {
|
.simple_value => |s| switch (s) {
|
||||||
|
|
@ -838,6 +866,15 @@ pub const Tag = enum(u8) {
|
||||||
/// Module.Struct object allocated for it.
|
/// Module.Struct object allocated for it.
|
||||||
/// data is Module.Namespace.Index.
|
/// data is Module.Namespace.Index.
|
||||||
type_struct_ns,
|
type_struct_ns,
|
||||||
|
/// A tagged union type.
|
||||||
|
/// `data` is `Module.Union.Index`.
|
||||||
|
type_union_tagged,
|
||||||
|
/// An untagged union type. It also has no safety tag.
|
||||||
|
/// `data` is `Module.Union.Index`.
|
||||||
|
type_union_untagged,
|
||||||
|
/// An untagged union type which has a safety tag.
|
||||||
|
/// `data` is `Module.Union.Index`.
|
||||||
|
type_union_safety,
|
||||||
|
|
||||||
/// A value that can be represented with only an enum tag.
|
/// A value that can be represented with only an enum tag.
|
||||||
/// data is SimpleValue enum value.
|
/// data is SimpleValue enum value.
|
||||||
|
|
@ -908,6 +945,8 @@ pub const Tag = enum(u8) {
|
||||||
/// * A struct which has 0 fields.
|
/// * A struct which has 0 fields.
|
||||||
/// data is Index of the type, which is known to be zero bits at runtime.
|
/// data is Index of the type, which is known to be zero bits at runtime.
|
||||||
only_possible_value,
|
only_possible_value,
|
||||||
|
/// data is extra index to Key.Union.
|
||||||
|
union_value,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to
|
/// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to
|
||||||
|
|
@ -1141,6 +1180,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
|
||||||
ip.structs_free_list.deinit(gpa);
|
ip.structs_free_list.deinit(gpa);
|
||||||
ip.allocated_structs.deinit(gpa);
|
ip.allocated_structs.deinit(gpa);
|
||||||
|
|
||||||
|
ip.unions_free_list.deinit(gpa);
|
||||||
|
ip.allocated_unions.deinit(gpa);
|
||||||
|
|
||||||
ip.* = undefined;
|
ip.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1233,6 +1275,19 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||||
.namespace = @intToEnum(Module.Namespace.Index, data).toOptional(),
|
.namespace = @intToEnum(Module.Namespace.Index, data).toOptional(),
|
||||||
} },
|
} },
|
||||||
|
|
||||||
|
.type_union_untagged => .{ .union_type = .{
|
||||||
|
.index = @intToEnum(Module.Union.Index, data),
|
||||||
|
.runtime_tag = .none,
|
||||||
|
} },
|
||||||
|
.type_union_tagged => .{ .union_type = .{
|
||||||
|
.index = @intToEnum(Module.Union.Index, data),
|
||||||
|
.runtime_tag = .tagged,
|
||||||
|
} },
|
||||||
|
.type_union_safety => .{ .union_type = .{
|
||||||
|
.index = @intToEnum(Module.Union.Index, data),
|
||||||
|
.runtime_tag = .safety,
|
||||||
|
} },
|
||||||
|
|
||||||
.opt_null => .{ .opt = .{
|
.opt_null => .{ .opt = .{
|
||||||
.ty = @intToEnum(Index, data),
|
.ty = @intToEnum(Index, data),
|
||||||
.val = .none,
|
.val = .none,
|
||||||
|
|
@ -1303,6 +1358,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.union_value => .{ .un = ip.extraData(Key.Union, data) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1350,7 +1406,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||||
return @intToEnum(Index, ip.items.len - 1);
|
return @intToEnum(Index, ip.items.len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO introduce more pointer encodings
|
|
||||||
ip.items.appendAssumeCapacity(.{
|
ip.items.appendAssumeCapacity(.{
|
||||||
.tag = .type_pointer,
|
.tag = .type_pointer,
|
||||||
.data = try ip.addExtra(gpa, Pointer{
|
.data = try ip.addExtra(gpa, Pointer{
|
||||||
|
|
@ -1450,8 +1505,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => |union_type| {
|
.union_type => |union_type| {
|
||||||
_ = union_type;
|
ip.items.appendAssumeCapacity(.{
|
||||||
@panic("TODO");
|
.tag = switch (union_type.runtime_tag) {
|
||||||
|
.none => .type_union_untagged,
|
||||||
|
.safety => .type_union_safety,
|
||||||
|
.tagged => .type_union_tagged,
|
||||||
|
},
|
||||||
|
.data = @enumToInt(union_type.index),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
.opaque_type => |opaque_type| {
|
.opaque_type => |opaque_type| {
|
||||||
|
|
@ -1642,6 +1703,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||||
}
|
}
|
||||||
@panic("TODO");
|
@panic("TODO");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.un => |un| {
|
||||||
|
assert(un.ty != .none);
|
||||||
|
assert(un.tag != .none);
|
||||||
|
assert(un.val != .none);
|
||||||
|
ip.items.appendAssumeCapacity(.{
|
||||||
|
.tag = .union_value,
|
||||||
|
.data = try ip.addExtra(gpa, un),
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return @intToEnum(Index, ip.items.len - 1);
|
return @intToEnum(Index, ip.items.len - 1);
|
||||||
}
|
}
|
||||||
|
|
@ -1923,6 +1994,17 @@ pub fn indexToStruct(ip: *InternPool, val: Index) Module.Struct.OptionalIndex {
|
||||||
return @intToEnum(Module.Struct.Index, datas[@enumToInt(val)]).toOptional();
|
return @intToEnum(Module.Struct.Index, datas[@enumToInt(val)]).toOptional();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn indexToUnion(ip: *InternPool, val: Index) Module.Union.OptionalIndex {
|
||||||
|
const tags = ip.items.items(.tag);
|
||||||
|
if (val == .none) return .none;
|
||||||
|
switch (tags[@enumToInt(val)]) {
|
||||||
|
.type_union_tagged, .type_union_untagged, .type_union_safety => {},
|
||||||
|
else => return .none,
|
||||||
|
}
|
||||||
|
const datas = ip.items.items(.data);
|
||||||
|
return @intToEnum(Module.Union.Index, datas[@enumToInt(val)]).toOptional();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn isOptionalType(ip: InternPool, ty: Index) bool {
|
pub fn isOptionalType(ip: InternPool, ty: Index) bool {
|
||||||
const tags = ip.items.items(.tag);
|
const tags = ip.items.items(.tag);
|
||||||
if (ty == .none) return false;
|
if (ty == .none) return false;
|
||||||
|
|
@ -1937,15 +2019,22 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||||
const items_size = (1 + 4) * ip.items.len;
|
const items_size = (1 + 4) * ip.items.len;
|
||||||
const extra_size = 4 * ip.extra.items.len;
|
const extra_size = 4 * ip.extra.items.len;
|
||||||
const limbs_size = 8 * ip.limbs.items.len;
|
const limbs_size = 8 * ip.limbs.items.len;
|
||||||
|
const structs_size = ip.allocated_structs.len *
|
||||||
|
(@sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl));
|
||||||
|
const unions_size = ip.allocated_unions.len *
|
||||||
|
(@sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl));
|
||||||
|
|
||||||
// TODO: map overhead size is not taken into account
|
// TODO: map overhead size is not taken into account
|
||||||
const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size;
|
const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size +
|
||||||
|
structs_size + unions_size;
|
||||||
|
|
||||||
std.debug.print(
|
std.debug.print(
|
||||||
\\InternPool size: {d} bytes
|
\\InternPool size: {d} bytes
|
||||||
\\ {d} items: {d} bytes
|
\\ {d} items: {d} bytes
|
||||||
\\ {d} extra: {d} bytes
|
\\ {d} extra: {d} bytes
|
||||||
\\ {d} limbs: {d} bytes
|
\\ {d} limbs: {d} bytes
|
||||||
|
\\ {d} structs: {d} bytes
|
||||||
|
\\ {d} unions: {d} bytes
|
||||||
\\
|
\\
|
||||||
, .{
|
, .{
|
||||||
total_size,
|
total_size,
|
||||||
|
|
@ -1955,6 +2044,10 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||||
extra_size,
|
extra_size,
|
||||||
ip.limbs.items.len,
|
ip.limbs.items.len,
|
||||||
limbs_size,
|
limbs_size,
|
||||||
|
ip.allocated_structs.len,
|
||||||
|
structs_size,
|
||||||
|
ip.allocated_unions.len,
|
||||||
|
unions_size,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tags = ip.items.items(.tag);
|
const tags = ip.items.items(.tag);
|
||||||
|
|
@ -1980,8 +2073,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||||
.type_error_union => @sizeOf(ErrorUnion),
|
.type_error_union => @sizeOf(ErrorUnion),
|
||||||
.type_enum_simple => @sizeOf(EnumSimple),
|
.type_enum_simple => @sizeOf(EnumSimple),
|
||||||
.type_opaque => @sizeOf(Key.OpaqueType),
|
.type_opaque => @sizeOf(Key.OpaqueType),
|
||||||
.type_struct => 0,
|
.type_struct => @sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),
|
||||||
.type_struct_ns => 0,
|
.type_struct_ns => @sizeOf(Module.Namespace),
|
||||||
|
|
||||||
|
.type_union_tagged,
|
||||||
|
.type_union_untagged,
|
||||||
|
.type_union_safety,
|
||||||
|
=> @sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),
|
||||||
|
|
||||||
.simple_type => 0,
|
.simple_type => 0,
|
||||||
.simple_value => 0,
|
.simple_value => 0,
|
||||||
.ptr_int => @sizeOf(PtrInt),
|
.ptr_int => @sizeOf(PtrInt),
|
||||||
|
|
@ -2010,6 +2109,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||||
.extern_func => @panic("TODO"),
|
.extern_func => @panic("TODO"),
|
||||||
.func => @panic("TODO"),
|
.func => @panic("TODO"),
|
||||||
.only_possible_value => 0,
|
.only_possible_value => 0,
|
||||||
|
.union_value => @sizeOf(Key.Union),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const SortContext = struct {
|
const SortContext = struct {
|
||||||
|
|
@ -2041,6 +2141,10 @@ pub fn structPtrUnwrapConst(ip: InternPool, index: Module.Struct.OptionalIndex)
|
||||||
return structPtrConst(ip, index.unwrap() orelse return null);
|
return structPtrConst(ip, index.unwrap() orelse return null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union {
|
||||||
|
return ip.allocated_unions.at(@enumToInt(index));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn createStruct(
|
pub fn createStruct(
|
||||||
ip: *InternPool,
|
ip: *InternPool,
|
||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
|
|
@ -2059,3 +2163,22 @@ pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index
|
||||||
// allocation failures here, instead leaking the Struct until garbage collection.
|
// allocation failures here, instead leaking the Struct until garbage collection.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn createUnion(
|
||||||
|
ip: *InternPool,
|
||||||
|
gpa: Allocator,
|
||||||
|
initialization: Module.Union,
|
||||||
|
) Allocator.Error!Module.Union.Index {
|
||||||
|
if (ip.unions_free_list.popOrNull()) |index| return index;
|
||||||
|
const ptr = try ip.allocated_unions.addOne(gpa);
|
||||||
|
ptr.* = initialization;
|
||||||
|
return @intToEnum(Module.Union.Index, ip.allocated_unions.len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index) void {
|
||||||
|
ip.unionPtr(index).* = undefined;
|
||||||
|
ip.unions_free_list.append(gpa, index) catch {
|
||||||
|
// In order to keep `destroyUnion` a non-fallible function, we ignore memory
|
||||||
|
// allocation failures here, instead leaking the Union until garbage collection.
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -851,11 +851,10 @@ pub const Decl = struct {
|
||||||
|
|
||||||
/// If the Decl has a value and it is a union, return it,
|
/// If the Decl has a value and it is a union, return it,
|
||||||
/// otherwise null.
|
/// otherwise null.
|
||||||
pub fn getUnion(decl: *Decl) ?*Union {
|
pub fn getUnion(decl: *Decl, mod: *Module) ?*Union {
|
||||||
if (!decl.owns_tv) return null;
|
if (!decl.owns_tv) return null;
|
||||||
const ty = (decl.val.castTag(.ty) orelse return null).data;
|
const ty = (decl.val.castTag(.ty) orelse return null).data;
|
||||||
const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data;
|
return mod.typeToUnion(ty);
|
||||||
return union_obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the Decl has a value and it is a function, return it,
|
/// If the Decl has a value and it is a function, return it,
|
||||||
|
|
@ -896,10 +895,6 @@ pub const Decl = struct {
|
||||||
const enum_obj = ty.cast(Type.Payload.EnumFull).?.data;
|
const enum_obj = ty.cast(Type.Payload.EnumFull).?.data;
|
||||||
return enum_obj.namespace.toOptional();
|
return enum_obj.namespace.toOptional();
|
||||||
},
|
},
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
|
||||||
return union_obj.namespace.toOptional();
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return .none,
|
else => return .none,
|
||||||
}
|
}
|
||||||
|
|
@ -907,6 +902,10 @@ pub const Decl = struct {
|
||||||
else => return switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
|
else => return switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
|
||||||
.opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
|
.opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
|
||||||
.struct_type => |struct_type| struct_type.namespace,
|
.struct_type => |struct_type| struct_type.namespace,
|
||||||
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return union_obj.namespace.toOptional();
|
||||||
|
},
|
||||||
else => .none,
|
else => .none,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -1373,6 +1372,28 @@ pub const Union = struct {
|
||||||
requires_comptime: PropertyBoolean = .unknown,
|
requires_comptime: PropertyBoolean = .unknown,
|
||||||
assumed_runtime_bits: bool = false,
|
assumed_runtime_bits: bool = false,
|
||||||
|
|
||||||
|
pub const Index = enum(u32) {
|
||||||
|
_,
|
||||||
|
|
||||||
|
pub fn toOptional(i: Index) OptionalIndex {
|
||||||
|
return @intToEnum(OptionalIndex, @enumToInt(i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const OptionalIndex = enum(u32) {
|
||||||
|
none = std.math.maxInt(u32),
|
||||||
|
_,
|
||||||
|
|
||||||
|
pub fn init(oi: ?Index) OptionalIndex {
|
||||||
|
return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap(oi: OptionalIndex) ?Index {
|
||||||
|
if (oi == .none) return null;
|
||||||
|
return @intToEnum(Index, @enumToInt(oi));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const Field = struct {
|
pub const Field = struct {
|
||||||
/// undefined until `status` is `have_field_types` or `have_layout`.
|
/// undefined until `status` is `have_field_types` or `have_layout`.
|
||||||
ty: Type,
|
ty: Type,
|
||||||
|
|
@ -3639,6 +3660,10 @@ pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {
|
||||||
return mod.allocated_namespaces.at(@enumToInt(index));
|
return mod.allocated_namespaces.at(@enumToInt(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unionPtr(mod: *Module, index: Union.Index) *Union {
|
||||||
|
return mod.intern_pool.unionPtr(index);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {
|
pub fn structPtr(mod: *Module, index: Struct.Index) *Struct {
|
||||||
return mod.intern_pool.structPtr(index);
|
return mod.intern_pool.structPtr(index);
|
||||||
}
|
}
|
||||||
|
|
@ -4112,7 +4137,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decl.getUnion()) |union_obj| {
|
if (decl.getUnion(mod)) |union_obj| {
|
||||||
union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse {
|
union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse {
|
||||||
try file.deleted_decls.append(gpa, decl_index);
|
try file.deleted_decls.append(gpa, decl_index);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -5988,20 +6013,10 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void {
|
||||||
decl.analysis = .outdated;
|
decl.analysis = .outdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CreateNamespaceOptions = struct {
|
pub fn createNamespace(mod: *Module, initialization: Namespace) !Namespace.Index {
|
||||||
parent: Namespace.OptionalIndex,
|
|
||||||
file_scope: *File,
|
|
||||||
ty: Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn createNamespace(mod: *Module, options: CreateNamespaceOptions) !Namespace.Index {
|
|
||||||
if (mod.namespaces_free_list.popOrNull()) |index| return index;
|
if (mod.namespaces_free_list.popOrNull()) |index| return index;
|
||||||
const ptr = try mod.allocated_namespaces.addOne(mod.gpa);
|
const ptr = try mod.allocated_namespaces.addOne(mod.gpa);
|
||||||
ptr.* = .{
|
ptr.* = initialization;
|
||||||
.parent = options.parent,
|
|
||||||
.file_scope = options.file_scope,
|
|
||||||
.ty = options.ty,
|
|
||||||
};
|
|
||||||
return @intToEnum(Namespace.Index, mod.allocated_namespaces.len - 1);
|
return @intToEnum(Namespace.Index, mod.allocated_namespaces.len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6021,6 +6036,14 @@ pub fn destroyStruct(mod: *Module, index: Struct.Index) void {
|
||||||
return mod.intern_pool.destroyStruct(mod.gpa, index);
|
return mod.intern_pool.destroyStruct(mod.gpa, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn createUnion(mod: *Module, initialization: Union) Allocator.Error!Union.Index {
|
||||||
|
return mod.intern_pool.createUnion(mod.gpa, initialization);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroyUnion(mod: *Module, index: Union.Index) void {
|
||||||
|
return mod.intern_pool.destroyUnion(mod.gpa, index);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn allocateNewDecl(
|
pub fn allocateNewDecl(
|
||||||
mod: *Module,
|
mod: *Module,
|
||||||
namespace: Namespace.Index,
|
namespace: Namespace.Index,
|
||||||
|
|
@ -7068,6 +7091,15 @@ pub fn intValue_i64(mod: *Module, ty: Type, x: i64) Allocator.Error!Value {
|
||||||
return i.toValue();
|
return i.toValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unionValue(mod: *Module, union_ty: Type, tag: Value, val: Value) Allocator.Error!Value {
|
||||||
|
const i = try intern(mod, .{ .un = .{
|
||||||
|
.ty = union_ty.ip_index,
|
||||||
|
.tag = tag.ip_index,
|
||||||
|
.val = val.ip_index,
|
||||||
|
} });
|
||||||
|
return i.toValue();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type {
|
pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type {
|
||||||
return intType(mod, .unsigned, Type.smallestUnsignedBits(max));
|
return intType(mod, .unsigned, Type.smallestUnsignedBits(max));
|
||||||
}
|
}
|
||||||
|
|
@ -7276,3 +7308,8 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct {
|
||||||
const struct_index = mod.intern_pool.indexToStruct(ty.ip_index).unwrap() orelse return null;
|
const struct_index = mod.intern_pool.indexToStruct(ty.ip_index).unwrap() orelse return null;
|
||||||
return mod.structPtr(struct_index);
|
return mod.structPtr(struct_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn typeToUnion(mod: *Module, ty: Type) ?*Union {
|
||||||
|
const union_index = mod.intern_pool.indexToUnion(ty.ip_index).unwrap() orelse return null;
|
||||||
|
return mod.unionPtr(union_index);
|
||||||
|
}
|
||||||
|
|
|
||||||
381
src/Sema.zig
381
src/Sema.zig
|
|
@ -3123,6 +3123,8 @@ fn zirUnionDecl(
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
|
const mod = sema.mod;
|
||||||
|
const gpa = sema.gpa;
|
||||||
const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
|
const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
|
||||||
var extra_index: usize = extended.operand;
|
var extra_index: usize = extended.operand;
|
||||||
|
|
||||||
|
|
@ -3142,49 +3144,57 @@ fn zirUnionDecl(
|
||||||
break :blk decls_len;
|
break :blk decls_len;
|
||||||
} else 0;
|
} else 0;
|
||||||
|
|
||||||
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
|
var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
|
||||||
errdefer new_decl_arena.deinit();
|
errdefer new_decl_arena.deinit();
|
||||||
const new_decl_arena_allocator = new_decl_arena.allocator();
|
|
||||||
|
|
||||||
const union_obj = try new_decl_arena_allocator.create(Module.Union);
|
// Because these three things each reference each other, `undefined`
|
||||||
const type_tag = if (small.has_tag_type or small.auto_enum_tag)
|
// placeholders are used before being set after the union type gains an
|
||||||
Type.Tag.union_tagged
|
// InternPool index.
|
||||||
else if (small.layout != .Auto)
|
|
||||||
Type.Tag.@"union"
|
|
||||||
else switch (block.sema.mod.optimizeMode()) {
|
|
||||||
.Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
|
|
||||||
.ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
|
|
||||||
};
|
|
||||||
const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
|
|
||||||
union_payload.* = .{
|
|
||||||
.base = .{ .tag = type_tag },
|
|
||||||
.data = union_obj,
|
|
||||||
};
|
|
||||||
const union_ty = Type.initPayload(&union_payload.base);
|
|
||||||
const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
|
|
||||||
const mod = sema.mod;
|
|
||||||
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
|
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
|
||||||
.ty = Type.type,
|
.ty = Type.type,
|
||||||
.val = union_val,
|
.val = undefined,
|
||||||
}, small.name_strategy, "union", inst);
|
}, small.name_strategy, "union", inst);
|
||||||
const new_decl = mod.declPtr(new_decl_index);
|
const new_decl = mod.declPtr(new_decl_index);
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
errdefer mod.abortAnonDecl(new_decl_index);
|
errdefer mod.abortAnonDecl(new_decl_index);
|
||||||
union_obj.* = .{
|
|
||||||
|
const new_namespace_index = try mod.createNamespace(.{
|
||||||
|
.parent = block.namespace.toOptional(),
|
||||||
|
.ty = undefined,
|
||||||
|
.file_scope = block.getFileScope(mod),
|
||||||
|
});
|
||||||
|
const new_namespace = mod.namespacePtr(new_namespace_index);
|
||||||
|
errdefer mod.destroyNamespace(new_namespace_index);
|
||||||
|
|
||||||
|
const union_index = try mod.createUnion(.{
|
||||||
.owner_decl = new_decl_index,
|
.owner_decl = new_decl_index,
|
||||||
.tag_ty = Type.null,
|
.tag_ty = Type.null,
|
||||||
.fields = .{},
|
.fields = .{},
|
||||||
.zir_index = inst,
|
.zir_index = inst,
|
||||||
.layout = small.layout,
|
.layout = small.layout,
|
||||||
.status = .none,
|
.status = .none,
|
||||||
.namespace = try mod.createNamespace(.{
|
.namespace = new_namespace_index,
|
||||||
.parent = block.namespace.toOptional(),
|
});
|
||||||
.ty = union_ty,
|
errdefer mod.destroyUnion(union_index);
|
||||||
.file_scope = block.getFileScope(mod),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = try mod.scanNamespace(union_obj.namespace, extra_index, decls_len, new_decl);
|
const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{
|
||||||
|
.index = union_index,
|
||||||
|
.runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
|
||||||
|
.tagged
|
||||||
|
else if (small.layout != .Auto)
|
||||||
|
.none
|
||||||
|
else switch (block.sema.mod.optimizeMode()) {
|
||||||
|
.Debug, .ReleaseSafe => .safety,
|
||||||
|
.ReleaseFast, .ReleaseSmall => .none,
|
||||||
|
},
|
||||||
|
} });
|
||||||
|
errdefer mod.intern_pool.remove(union_ty);
|
||||||
|
|
||||||
|
new_decl.val = union_ty.toValue();
|
||||||
|
new_namespace.ty = union_ty.toType();
|
||||||
|
|
||||||
|
_ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
|
||||||
|
|
||||||
try new_decl.finalizeNewArena(&new_decl_arena);
|
try new_decl.finalizeNewArena(&new_decl_arena);
|
||||||
return sema.analyzeDeclVal(block, src, new_decl_index);
|
return sema.analyzeDeclVal(block, src, new_decl_index);
|
||||||
|
|
@ -4246,6 +4256,8 @@ fn validateUnionInit(
|
||||||
instrs: []const Zir.Inst.Index,
|
instrs: []const Zir.Inst.Index,
|
||||||
union_ptr: Air.Inst.Ref,
|
union_ptr: Air.Inst.Ref,
|
||||||
) CompileError!void {
|
) CompileError!void {
|
||||||
|
const mod = sema.mod;
|
||||||
|
|
||||||
if (instrs.len != 1) {
|
if (instrs.len != 1) {
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(
|
const msg = try sema.errMsg(
|
||||||
|
|
@ -4343,7 +4355,7 @@ fn validateUnionInit(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag_ty = union_ty.unionTagTypeHypothetical();
|
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
|
||||||
const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
||||||
const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
||||||
|
|
||||||
|
|
@ -8273,7 +8285,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||||
.Enum => operand,
|
.Enum => operand,
|
||||||
.Union => blk: {
|
.Union => blk: {
|
||||||
const union_ty = try sema.resolveTypeFields(operand_ty);
|
const union_ty = try sema.resolveTypeFields(operand_ty);
|
||||||
const tag_ty = union_ty.unionTagType() orelse {
|
const tag_ty = union_ty.unionTagType(mod) orelse {
|
||||||
return sema.fail(
|
return sema.fail(
|
||||||
block,
|
block,
|
||||||
operand_src,
|
operand_src,
|
||||||
|
|
@ -10158,7 +10170,7 @@ fn zirSwitchCapture(
|
||||||
const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;
|
const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;
|
||||||
if (operand_ty.zigTypeTag(mod) == .Union) {
|
if (operand_ty.zigTypeTag(mod) == .Union) {
|
||||||
const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);
|
const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);
|
||||||
const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(operand_ty).?;
|
||||||
const field_ty = union_obj.fields.values()[field_index].ty;
|
const field_ty = union_obj.fields.values()[field_index].ty;
|
||||||
if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {
|
if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {
|
||||||
if (is_ref) {
|
if (is_ref) {
|
||||||
|
|
@ -10229,7 +10241,7 @@ fn zirSwitchCapture(
|
||||||
|
|
||||||
switch (operand_ty.zigTypeTag(mod)) {
|
switch (operand_ty.zigTypeTag(mod)) {
|
||||||
.Union => {
|
.Union => {
|
||||||
const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(operand_ty).?;
|
||||||
const first_item = try sema.resolveInst(items[0]);
|
const first_item = try sema.resolveInst(items[0]);
|
||||||
// Previous switch validation ensured this will succeed
|
// Previous switch validation ensured this will succeed
|
||||||
const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;
|
const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;
|
||||||
|
|
@ -10403,7 +10415,7 @@ fn zirSwitchCond(
|
||||||
|
|
||||||
.Union => {
|
.Union => {
|
||||||
const union_ty = try sema.resolveTypeFields(operand_ty);
|
const union_ty = try sema.resolveTypeFields(operand_ty);
|
||||||
const enum_ty = union_ty.unionTagType() orelse {
|
const enum_ty = union_ty.unionTagType(mod) orelse {
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{});
|
const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{});
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
@ -11627,7 +11639,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||||
const analyze_body = if (union_originally and !special.is_inline)
|
const analyze_body = if (union_originally and !special.is_inline)
|
||||||
for (seen_enum_fields, 0..) |seen_field, index| {
|
for (seen_enum_fields, 0..) |seen_field, index| {
|
||||||
if (seen_field != null) continue;
|
if (seen_field != null) continue;
|
||||||
const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(maybe_union_ty).?;
|
||||||
const field_ty = union_obj.fields.values()[index].ty;
|
const field_ty = union_obj.fields.values()[index].ty;
|
||||||
if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
|
if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
|
||||||
} else false
|
} else false
|
||||||
|
|
@ -12068,7 +12080,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||||
}
|
}
|
||||||
break :hf switch (ty.zigTypeTag(mod)) {
|
break :hf switch (ty.zigTypeTag(mod)) {
|
||||||
.Struct => ty.structFields(mod).contains(field_name),
|
.Struct => ty.structFields(mod).contains(field_name),
|
||||||
.Union => ty.unionFields().contains(field_name),
|
.Union => ty.unionFields(mod).contains(field_name),
|
||||||
.Enum => ty.enumFields().contains(field_name),
|
.Enum => ty.enumFields().contains(field_name),
|
||||||
.Array => mem.eql(u8, field_name, "len"),
|
.Array => mem.eql(u8, field_name, "len"),
|
||||||
else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
|
else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
|
||||||
|
|
@ -15415,7 +15427,7 @@ fn analyzeCmpUnionTag(
|
||||||
) CompileError!Air.Inst.Ref {
|
) CompileError!Air.Inst.Ref {
|
||||||
const mod = sema.mod;
|
const mod = sema.mod;
|
||||||
const union_ty = try sema.resolveTypeFields(sema.typeOf(un));
|
const union_ty = try sema.resolveTypeFields(sema.typeOf(un));
|
||||||
const union_tag_ty = union_ty.unionTagType() orelse {
|
const union_tag_ty = union_ty.unionTagType(mod) orelse {
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
|
const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
@ -16403,7 +16415,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||||
try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
|
try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
|
||||||
const layout = union_ty.containerLayout(mod);
|
const layout = union_ty.containerLayout(mod);
|
||||||
|
|
||||||
const union_fields = union_ty.unionFields();
|
const union_fields = union_ty.unionFields(mod);
|
||||||
const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());
|
const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());
|
||||||
|
|
||||||
for (union_field_vals, 0..) |*field_val, i| {
|
for (union_field_vals, 0..) |*field_val, i| {
|
||||||
|
|
@ -16458,7 +16470,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||||
|
|
||||||
const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace(mod));
|
const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace(mod));
|
||||||
|
|
||||||
const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: {
|
const enum_tag_ty_val = if (union_ty.unionTagType(mod)) |tag_ty| v: {
|
||||||
const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
|
const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
|
||||||
break :v try Value.Tag.opt_payload.create(sema.arena, ty_val);
|
break :v try Value.Tag.opt_payload.create(sema.arena, ty_val);
|
||||||
} else Value.null;
|
} else Value.null;
|
||||||
|
|
@ -17877,12 +17889,13 @@ fn unionInit(
|
||||||
field_name: []const u8,
|
field_name: []const u8,
|
||||||
field_src: LazySrcLoc,
|
field_src: LazySrcLoc,
|
||||||
) CompileError!Air.Inst.Ref {
|
) CompileError!Air.Inst.Ref {
|
||||||
|
const mod = sema.mod;
|
||||||
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
|
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
|
||||||
const field = union_ty.unionFields().values()[field_index];
|
const field = union_ty.unionFields(mod).values()[field_index];
|
||||||
const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
|
const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
|
||||||
|
|
||||||
if (try sema.resolveMaybeUndefVal(init)) |init_val| {
|
if (try sema.resolveMaybeUndefVal(init)) |init_val| {
|
||||||
const tag_ty = union_ty.unionTagTypeHypothetical();
|
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
|
||||||
const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
||||||
const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
||||||
return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
|
return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
|
||||||
|
|
@ -17983,7 +17996,7 @@ fn zirStructInit(
|
||||||
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
|
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
|
||||||
const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
|
const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
|
||||||
const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
|
const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
|
||||||
const tag_ty = resolved_ty.unionTagTypeHypothetical();
|
const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
|
||||||
const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
||||||
const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
||||||
|
|
||||||
|
|
@ -18006,7 +18019,7 @@ fn zirStructInit(
|
||||||
const alloc = try block.addTy(.alloc, alloc_ty);
|
const alloc = try block.addTy(.alloc, alloc_ty);
|
||||||
const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);
|
const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);
|
||||||
try sema.storePtr(block, src, field_ptr, init_inst);
|
try sema.storePtr(block, src, field_ptr, init_inst);
|
||||||
const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);
|
const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(mod), tag_val);
|
||||||
_ = try block.addBinOp(.set_union_tag, alloc, new_tag);
|
_ = try block.addBinOp(.set_union_tag, alloc, new_tag);
|
||||||
return sema.makePtrConst(block, alloc);
|
return sema.makePtrConst(block, alloc);
|
||||||
}
|
}
|
||||||
|
|
@ -18544,7 +18557,7 @@ fn fieldType(
|
||||||
return sema.addType(field.ty);
|
return sema.addType(field.ty);
|
||||||
},
|
},
|
||||||
.Union => {
|
.Union => {
|
||||||
const union_obj = cur_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(cur_ty).?;
|
||||||
const field = union_obj.fields.get(field_name) orelse
|
const field = union_obj.fields.get(field_name) orelse
|
||||||
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
|
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
|
||||||
return sema.addType(field.ty);
|
return sema.addType(field.ty);
|
||||||
|
|
@ -18726,7 +18739,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||||
return sema.addStrLit(block, bytes);
|
return sema.addStrLit(block, bytes);
|
||||||
},
|
},
|
||||||
.Enum => operand_ty,
|
.Enum => operand_ty,
|
||||||
.Union => operand_ty.unionTagType() orelse {
|
.Union => operand_ty.unionTagType(mod) orelse {
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{
|
const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{
|
||||||
operand_ty.fmt(sema.mod),
|
operand_ty.fmt(sema.mod),
|
||||||
|
|
@ -19245,42 +19258,53 @@ fn zirReify(
|
||||||
errdefer new_decl_arena.deinit();
|
errdefer new_decl_arena.deinit();
|
||||||
const new_decl_arena_allocator = new_decl_arena.allocator();
|
const new_decl_arena_allocator = new_decl_arena.allocator();
|
||||||
|
|
||||||
const union_obj = try new_decl_arena_allocator.create(Module.Union);
|
// Because these three things each reference each other, `undefined`
|
||||||
const type_tag = if (!tag_type_val.isNull(mod))
|
// placeholders are used before being set after the union type gains an
|
||||||
Type.Tag.union_tagged
|
// InternPool index.
|
||||||
else if (layout != .Auto)
|
|
||||||
Type.Tag.@"union"
|
|
||||||
else switch (mod.optimizeMode()) {
|
|
||||||
.Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
|
|
||||||
.ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
|
|
||||||
};
|
|
||||||
const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
|
|
||||||
union_payload.* = .{
|
|
||||||
.base = .{ .tag = type_tag },
|
|
||||||
.data = union_obj,
|
|
||||||
};
|
|
||||||
const union_ty = Type.initPayload(&union_payload.base);
|
|
||||||
const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
|
|
||||||
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
|
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
|
||||||
.ty = Type.type,
|
.ty = Type.type,
|
||||||
.val = new_union_val,
|
.val = undefined,
|
||||||
}, name_strategy, "union", inst);
|
}, name_strategy, "union", inst);
|
||||||
const new_decl = mod.declPtr(new_decl_index);
|
const new_decl = mod.declPtr(new_decl_index);
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
errdefer mod.abortAnonDecl(new_decl_index);
|
errdefer mod.abortAnonDecl(new_decl_index);
|
||||||
union_obj.* = .{
|
|
||||||
|
const new_namespace_index = try mod.createNamespace(.{
|
||||||
|
.parent = block.namespace.toOptional(),
|
||||||
|
.ty = undefined,
|
||||||
|
.file_scope = block.getFileScope(mod),
|
||||||
|
});
|
||||||
|
const new_namespace = mod.namespacePtr(new_namespace_index);
|
||||||
|
errdefer mod.destroyNamespace(new_namespace_index);
|
||||||
|
|
||||||
|
const union_index = try mod.createUnion(.{
|
||||||
.owner_decl = new_decl_index,
|
.owner_decl = new_decl_index,
|
||||||
.tag_ty = Type.null,
|
.tag_ty = Type.null,
|
||||||
.fields = .{},
|
.fields = .{},
|
||||||
.zir_index = inst,
|
.zir_index = inst,
|
||||||
.layout = layout,
|
.layout = layout,
|
||||||
.status = .have_field_types,
|
.status = .have_field_types,
|
||||||
.namespace = try mod.createNamespace(.{
|
.namespace = new_namespace_index,
|
||||||
.parent = block.namespace.toOptional(),
|
});
|
||||||
.ty = union_ty,
|
const union_obj = mod.unionPtr(union_index);
|
||||||
.file_scope = block.getFileScope(mod),
|
errdefer mod.destroyUnion(union_index);
|
||||||
}),
|
|
||||||
};
|
const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{
|
||||||
|
.index = union_index,
|
||||||
|
.runtime_tag = if (!tag_type_val.isNull(mod))
|
||||||
|
.tagged
|
||||||
|
else if (layout != .Auto)
|
||||||
|
.none
|
||||||
|
else switch (mod.optimizeMode()) {
|
||||||
|
.Debug, .ReleaseSafe => .safety,
|
||||||
|
.ReleaseFast, .ReleaseSmall => .none,
|
||||||
|
},
|
||||||
|
} });
|
||||||
|
errdefer mod.intern_pool.remove(union_ty);
|
||||||
|
|
||||||
|
new_decl.val = union_ty.toValue();
|
||||||
|
new_namespace.ty = union_ty.toType();
|
||||||
|
|
||||||
// Tag type
|
// Tag type
|
||||||
var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
|
var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
|
||||||
|
|
@ -21981,8 +22005,8 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
|
||||||
ptr_ty_data.@"align" = blk: {
|
ptr_ty_data.@"align" = blk: {
|
||||||
if (mod.typeToStruct(parent_ty)) |struct_obj| {
|
if (mod.typeToStruct(parent_ty)) |struct_obj| {
|
||||||
break :blk struct_obj.fields.values()[field_index].abi_align;
|
break :blk struct_obj.fields.values()[field_index].abi_align;
|
||||||
} else if (parent_ty.cast(Type.Payload.Union)) |union_obj| {
|
} else if (mod.typeToUnion(parent_ty)) |union_obj| {
|
||||||
break :blk union_obj.data.fields.values()[field_index].abi_align;
|
break :blk union_obj.fields.values()[field_index].abi_align;
|
||||||
} else {
|
} else {
|
||||||
break :blk 0;
|
break :blk 0;
|
||||||
}
|
}
|
||||||
|
|
@ -23443,8 +23467,7 @@ fn explainWhyTypeIsComptimeInner(
|
||||||
.Union => {
|
.Union => {
|
||||||
if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
|
if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
|
||||||
|
|
||||||
if (ty.cast(Type.Payload.Union)) |payload| {
|
if (mod.typeToUnion(ty)) |union_obj| {
|
||||||
const union_obj = payload.data;
|
|
||||||
for (union_obj.fields.values(), 0..) |field, i| {
|
for (union_obj.fields.values(), 0..) |field, i| {
|
||||||
const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{
|
const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{
|
||||||
.index = i,
|
.index = i,
|
||||||
|
|
@ -24144,7 +24167,7 @@ fn fieldVal(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const union_ty = try sema.resolveTypeFields(child_type);
|
const union_ty = try sema.resolveTypeFields(child_type);
|
||||||
if (union_ty.unionTagType()) |enum_ty| {
|
if (union_ty.unionTagType(mod)) |enum_ty| {
|
||||||
if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {
|
if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {
|
||||||
const field_index = @intCast(u32, field_index_usize);
|
const field_index = @intCast(u32, field_index_usize);
|
||||||
return sema.addConstant(
|
return sema.addConstant(
|
||||||
|
|
@ -24358,7 +24381,7 @@ fn fieldPtr(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const union_ty = try sema.resolveTypeFields(child_type);
|
const union_ty = try sema.resolveTypeFields(child_type);
|
||||||
if (union_ty.unionTagType()) |enum_ty| {
|
if (union_ty.unionTagType(mod)) |enum_ty| {
|
||||||
if (enum_ty.enumFieldIndex(field_name)) |field_index| {
|
if (enum_ty.enumFieldIndex(field_name)) |field_index| {
|
||||||
const field_index_u32 = @intCast(u32, field_index);
|
const field_index_u32 = @intCast(u32, field_index);
|
||||||
var anon_decl = try block.startAnonDecl();
|
var anon_decl = try block.startAnonDecl();
|
||||||
|
|
@ -24489,7 +24512,7 @@ fn fieldCallBind(
|
||||||
},
|
},
|
||||||
.Union => {
|
.Union => {
|
||||||
const union_ty = try sema.resolveTypeFields(concrete_ty);
|
const union_ty = try sema.resolveTypeFields(concrete_ty);
|
||||||
const fields = union_ty.unionFields();
|
const fields = union_ty.unionFields(mod);
|
||||||
const field_index_usize = fields.getIndex(field_name) orelse break :find_field;
|
const field_index_usize = fields.getIndex(field_name) orelse break :find_field;
|
||||||
const field_index = @intCast(u32, field_index_usize);
|
const field_index = @intCast(u32, field_index_usize);
|
||||||
const field = fields.values()[field_index];
|
const field = fields.values()[field_index];
|
||||||
|
|
@ -24964,7 +24987,7 @@ fn unionFieldPtr(
|
||||||
|
|
||||||
const union_ptr_ty = sema.typeOf(union_ptr);
|
const union_ptr_ty = sema.typeOf(union_ptr);
|
||||||
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
|
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
|
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
|
||||||
const field = union_obj.fields.values()[field_index];
|
const field = union_obj.fields.values()[field_index];
|
||||||
const ptr_field_ty = try Type.ptr(arena, mod, .{
|
const ptr_field_ty = try Type.ptr(arena, mod, .{
|
||||||
|
|
@ -25028,7 +25051,7 @@ fn unionFieldPtr(
|
||||||
|
|
||||||
try sema.requireRuntimeBlock(block, src, null);
|
try sema.requireRuntimeBlock(block, src, null);
|
||||||
if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
|
if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
|
||||||
union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
|
union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
|
||||||
{
|
{
|
||||||
const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
||||||
const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
|
const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
|
||||||
|
|
@ -25057,7 +25080,7 @@ fn unionFieldVal(
|
||||||
assert(unresolved_union_ty.zigTypeTag(mod) == .Union);
|
assert(unresolved_union_ty.zigTypeTag(mod) == .Union);
|
||||||
|
|
||||||
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
|
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
|
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
|
||||||
const field = union_obj.fields.values()[field_index];
|
const field = union_obj.fields.values()[field_index];
|
||||||
const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
|
const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
|
||||||
|
|
@ -25103,7 +25126,7 @@ fn unionFieldVal(
|
||||||
|
|
||||||
try sema.requireRuntimeBlock(block, src, null);
|
try sema.requireRuntimeBlock(block, src, null);
|
||||||
if (union_obj.layout == .Auto and block.wantSafety() and
|
if (union_obj.layout == .Auto and block.wantSafety() and
|
||||||
union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
|
union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
|
||||||
{
|
{
|
||||||
const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
|
||||||
const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
|
const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
|
||||||
|
|
@ -26189,7 +26212,7 @@ fn coerceExtra(
|
||||||
},
|
},
|
||||||
.Union => blk: {
|
.Union => blk: {
|
||||||
// union to its own tag type
|
// union to its own tag type
|
||||||
const union_tag_ty = inst_ty.unionTagType() orelse break :blk;
|
const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk;
|
||||||
if (union_tag_ty.eql(dest_ty, sema.mod)) {
|
if (union_tag_ty.eql(dest_ty, sema.mod)) {
|
||||||
return sema.unionToTag(block, dest_ty, inst, inst_src);
|
return sema.unionToTag(block, dest_ty, inst, inst_src);
|
||||||
}
|
}
|
||||||
|
|
@ -28622,7 +28645,7 @@ fn coerceEnumToUnion(
|
||||||
const mod = sema.mod;
|
const mod = sema.mod;
|
||||||
const inst_ty = sema.typeOf(inst);
|
const inst_ty = sema.typeOf(inst);
|
||||||
|
|
||||||
const tag_ty = union_ty.unionTagType() orelse {
|
const tag_ty = union_ty.unionTagType(mod) orelse {
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
|
const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
|
||||||
union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
|
union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
|
||||||
|
|
@ -28649,7 +28672,7 @@ fn coerceEnumToUnion(
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const field = union_obj.fields.values()[field_index];
|
const field = union_obj.fields.values()[field_index];
|
||||||
const field_ty = try sema.resolveTypeFields(field.ty);
|
const field_ty = try sema.resolveTypeFields(field.ty);
|
||||||
if (field_ty.zigTypeTag(mod) == .NoReturn) {
|
if (field_ty.zigTypeTag(mod) == .NoReturn) {
|
||||||
|
|
@ -28679,10 +28702,7 @@ fn coerceEnumToUnion(
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
|
return sema.addConstant(union_ty, try mod.unionValue(union_ty, val, opv));
|
||||||
.tag = val,
|
|
||||||
.val = opv,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try sema.requireRuntimeBlock(block, inst_src, null);
|
try sema.requireRuntimeBlock(block, inst_src, null);
|
||||||
|
|
@ -28699,7 +28719,7 @@ fn coerceEnumToUnion(
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
{
|
{
|
||||||
var msg: ?*Module.ErrorMsg = null;
|
var msg: ?*Module.ErrorMsg = null;
|
||||||
errdefer if (msg) |some| some.destroy(sema.gpa);
|
errdefer if (msg) |some| some.destroy(sema.gpa);
|
||||||
|
|
@ -29350,10 +29370,13 @@ fn analyzeRef(
|
||||||
const operand_ty = sema.typeOf(operand);
|
const operand_ty = sema.typeOf(operand);
|
||||||
|
|
||||||
if (try sema.resolveMaybeUndefVal(operand)) |val| {
|
if (try sema.resolveMaybeUndefVal(operand)) |val| {
|
||||||
switch (val.tag()) {
|
switch (val.ip_index) {
|
||||||
.extern_fn, .function => {
|
.none => switch (val.tag()) {
|
||||||
const decl_index = val.pointerDecl().?;
|
.extern_fn, .function => {
|
||||||
return sema.analyzeDeclRef(decl_index);
|
const decl_index = val.pointerDecl().?;
|
||||||
|
return sema.analyzeDeclRef(decl_index);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
@ -31523,8 +31546,9 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
|
fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
|
||||||
|
const mod = sema.mod;
|
||||||
const resolved_ty = try sema.resolveTypeFields(ty);
|
const resolved_ty = try sema.resolveTypeFields(ty);
|
||||||
const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(resolved_ty).?;
|
||||||
switch (union_obj.status) {
|
switch (union_obj.status) {
|
||||||
.none, .have_field_types => {},
|
.none, .have_field_types => {},
|
||||||
.field_types_wip, .layout_wip => {
|
.field_types_wip, .layout_wip => {
|
||||||
|
|
@ -31617,27 +31641,6 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
|
||||||
switch (union_obj.requires_comptime) {
|
|
||||||
.no, .wip => return false,
|
|
||||||
.yes => return true,
|
|
||||||
.unknown => {
|
|
||||||
var requires_comptime = false;
|
|
||||||
union_obj.requires_comptime = .wip;
|
|
||||||
for (union_obj.fields.values()) |field| {
|
|
||||||
if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
|
|
||||||
}
|
|
||||||
if (requires_comptime) {
|
|
||||||
union_obj.requires_comptime = .yes;
|
|
||||||
} else {
|
|
||||||
union_obj.requires_comptime = .no;
|
|
||||||
}
|
|
||||||
return requires_comptime;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()),
|
.error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()),
|
||||||
.anyframe_T => {
|
.anyframe_T => {
|
||||||
const child_ty = ty.castTag(.anyframe_T).?.data;
|
const child_ty = ty.castTag(.anyframe_T).?.data;
|
||||||
|
|
@ -31734,10 +31737,31 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
switch (union_obj.requires_comptime) {
|
||||||
|
.no, .wip => return false,
|
||||||
|
.yes => return true,
|
||||||
|
.unknown => {
|
||||||
|
var requires_comptime = false;
|
||||||
|
union_obj.requires_comptime = .wip;
|
||||||
|
for (union_obj.fields.values()) |field| {
|
||||||
|
if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
|
||||||
|
}
|
||||||
|
if (requires_comptime) {
|
||||||
|
union_obj.requires_comptime = .yes;
|
||||||
|
} else {
|
||||||
|
union_obj.requires_comptime = .no;
|
||||||
|
}
|
||||||
|
return requires_comptime;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
.opaque_type => false,
|
.opaque_type => false,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -31829,8 +31853,9 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
|
||||||
fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
|
fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
|
||||||
try sema.resolveUnionLayout(ty);
|
try sema.resolveUnionLayout(ty);
|
||||||
|
|
||||||
|
const mod = sema.mod;
|
||||||
const resolved_ty = try sema.resolveTypeFields(ty);
|
const resolved_ty = try sema.resolveTypeFields(ty);
|
||||||
const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(resolved_ty).?;
|
||||||
switch (union_obj.status) {
|
switch (union_obj.status) {
|
||||||
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
|
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
|
||||||
.fully_resolved_wip, .fully_resolved => return,
|
.fully_resolved_wip, .fully_resolved => return,
|
||||||
|
|
@ -31858,15 +31883,8 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
|
||||||
const mod = sema.mod;
|
const mod = sema.mod;
|
||||||
|
|
||||||
switch (ty.ip_index) {
|
switch (ty.ip_index) {
|
||||||
.none => switch (ty.tag()) {
|
// TODO: After the InternPool transition is complete, change this to `unreachable`.
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
.none => return ty,
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
|
||||||
try sema.resolveTypeFieldsUnion(ty, union_obj);
|
|
||||||
return ty;
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return ty,
|
|
||||||
},
|
|
||||||
|
|
||||||
.u1_type,
|
.u1_type,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
|
|
@ -31957,7 +31975,12 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
|
||||||
try sema.resolveTypeFieldsStruct(ty, struct_obj);
|
try sema.resolveTypeFieldsStruct(ty, struct_obj);
|
||||||
return ty;
|
return ty;
|
||||||
},
|
},
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
try sema.resolveTypeFieldsUnion(ty, union_obj);
|
||||||
|
return ty;
|
||||||
|
},
|
||||||
|
|
||||||
else => return ty,
|
else => return ty,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -33123,32 +33146,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const resolved_ty = try sema.resolveTypeFields(ty);
|
|
||||||
const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
|
|
||||||
const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
|
|
||||||
return null;
|
|
||||||
const fields = union_obj.fields.values();
|
|
||||||
if (fields.len == 0) return Value.@"unreachable";
|
|
||||||
const only_field = fields[0];
|
|
||||||
if (only_field.ty.eql(resolved_ty, sema.mod)) {
|
|
||||||
const msg = try Module.ErrorMsg.create(
|
|
||||||
sema.gpa,
|
|
||||||
union_obj.srcLoc(sema.mod),
|
|
||||||
"union '{}' depends on itself",
|
|
||||||
.{ty.fmt(sema.mod)},
|
|
||||||
);
|
|
||||||
try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
|
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
|
||||||
}
|
|
||||||
const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse
|
|
||||||
return null;
|
|
||||||
// TODO make this not allocate.
|
|
||||||
return try Value.Tag.@"union".create(sema.arena, .{
|
|
||||||
.tag = tag_val,
|
|
||||||
.val = val_val,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
.array => {
|
.array => {
|
||||||
if (ty.arrayLen(mod) == 0)
|
if (ty.arrayLen(mod) == 0)
|
||||||
|
|
@ -33268,10 +33265,37 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||||
return empty.toValue();
|
return empty.toValue();
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const resolved_ty = try sema.resolveTypeFields(ty);
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
|
||||||
|
return null;
|
||||||
|
const fields = union_obj.fields.values();
|
||||||
|
if (fields.len == 0) return Value.@"unreachable";
|
||||||
|
const only_field = fields[0];
|
||||||
|
if (only_field.ty.eql(resolved_ty, sema.mod)) {
|
||||||
|
const msg = try Module.ErrorMsg.create(
|
||||||
|
sema.gpa,
|
||||||
|
union_obj.srcLoc(sema.mod),
|
||||||
|
"union '{}' depends on itself",
|
||||||
|
.{ty.fmt(sema.mod)},
|
||||||
|
);
|
||||||
|
try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
|
||||||
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
|
}
|
||||||
|
const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse
|
||||||
|
return null;
|
||||||
|
const only = try mod.intern(.{ .un = .{
|
||||||
|
.ty = resolved_ty.ip_index,
|
||||||
|
.tag = tag_val.ip_index,
|
||||||
|
.val = val_val.ip_index,
|
||||||
|
} });
|
||||||
|
return only.toValue();
|
||||||
|
},
|
||||||
.opaque_type => null,
|
.opaque_type => null,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -33710,30 +33734,6 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
|
||||||
switch (union_obj.requires_comptime) {
|
|
||||||
.no, .wip => return false,
|
|
||||||
.yes => return true,
|
|
||||||
.unknown => {
|
|
||||||
if (union_obj.status == .field_types_wip)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try sema.resolveTypeFieldsUnion(ty, union_obj);
|
|
||||||
|
|
||||||
union_obj.requires_comptime = .wip;
|
|
||||||
for (union_obj.fields.values()) |field| {
|
|
||||||
if (try sema.typeRequiresComptime(field.ty)) {
|
|
||||||
union_obj.requires_comptime = .yes;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
union_obj.requires_comptime = .no;
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),
|
.error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),
|
||||||
.anyframe_T => {
|
.anyframe_T => {
|
||||||
const child_ty = ty.castTag(.anyframe_T).?.data;
|
const child_ty = ty.castTag(.anyframe_T).?.data;
|
||||||
|
|
@ -33837,10 +33837,34 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
switch (union_obj.requires_comptime) {
|
||||||
|
.no, .wip => return false,
|
||||||
|
.yes => return true,
|
||||||
|
.unknown => {
|
||||||
|
if (union_obj.status == .field_types_wip)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try sema.resolveTypeFieldsUnion(ty, union_obj);
|
||||||
|
|
||||||
|
union_obj.requires_comptime = .wip;
|
||||||
|
for (union_obj.fields.values()) |field| {
|
||||||
|
if (try sema.typeRequiresComptime(field.ty)) {
|
||||||
|
union_obj.requires_comptime = .yes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
union_obj.requires_comptime = .no;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
.opaque_type => false,
|
.opaque_type => false,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -33905,8 +33929,9 @@ fn unionFieldIndex(
|
||||||
field_name: []const u8,
|
field_name: []const u8,
|
||||||
field_src: LazySrcLoc,
|
field_src: LazySrcLoc,
|
||||||
) !u32 {
|
) !u32 {
|
||||||
|
const mod = sema.mod;
|
||||||
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
|
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const field_index_usize = union_obj.fields.getIndex(field_name) orelse
|
const field_index_usize = union_obj.fields.getIndex(field_name) orelse
|
||||||
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
|
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
|
||||||
return @intCast(u32, field_index_usize);
|
return @intCast(u32, field_index_usize);
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ pub fn print(
|
||||||
try writer.writeAll(".{ ");
|
try writer.writeAll(".{ ");
|
||||||
|
|
||||||
try print(.{
|
try print(.{
|
||||||
.ty = ty.cast(Type.Payload.Union).?.data.tag_ty,
|
.ty = mod.unionPtr(mod.intern_pool.indexToKey(ty.ip_index).union_type.index).tag_ty,
|
||||||
.val = union_val.tag,
|
.val = union_val.tag,
|
||||||
}, writer, level - 1, mod);
|
}, writer, level - 1, mod);
|
||||||
try writer.writeAll(" = ");
|
try writer.writeAll(" = ");
|
||||||
|
|
@ -185,7 +185,7 @@ pub fn print(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) {
|
} else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) {
|
||||||
const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index];
|
const field_name = field_ptr.container_ty.unionFields(mod).keys()[field_ptr.field_index];
|
||||||
return writer.print(".{s}", .{field_name});
|
return writer.print(".{s}", .{field_name});
|
||||||
} else if (field_ptr.container_ty.isSlice(mod)) {
|
} else if (field_ptr.container_ty.isSlice(mod)) {
|
||||||
switch (field_ptr.field_index) {
|
switch (field_ptr.field_index) {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {
|
||||||
const invalid = std.math.maxInt(u8);
|
const invalid = std.math.maxInt(u8);
|
||||||
switch (ty.zigTypeTag(mod)) {
|
switch (ty.zigTypeTag(mod)) {
|
||||||
.Union => {
|
.Union => {
|
||||||
const fields = ty.unionFields();
|
const fields = ty.unionFields(mod);
|
||||||
var max_count: u8 = 0;
|
var max_count: u8 = 0;
|
||||||
for (fields.values()) |field| {
|
for (fields.values()) |field| {
|
||||||
const field_count = countFloats(field.ty, mod, maybe_float_bits);
|
const field_count = countFloats(field.ty, mod, maybe_float_bits);
|
||||||
|
|
@ -118,7 +118,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 {
|
||||||
pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type {
|
pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type {
|
||||||
switch (ty.zigTypeTag(mod)) {
|
switch (ty.zigTypeTag(mod)) {
|
||||||
.Union => {
|
.Union => {
|
||||||
const fields = ty.unionFields();
|
const fields = ty.unionFields(mod);
|
||||||
for (fields.values()) |field| {
|
for (fields.values()) |field| {
|
||||||
if (getFloatArrayType(field.ty, mod)) |some| return some;
|
if (getFloatArrayType(field.ty, mod)) |some| return some;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class {
|
||||||
const float_count = countFloats(ty, mod, &maybe_float_bits);
|
const float_count = countFloats(ty, mod, &maybe_float_bits);
|
||||||
if (float_count <= byval_float_count) return .byval;
|
if (float_count <= byval_float_count) return .byval;
|
||||||
|
|
||||||
for (ty.unionFields().values()) |field| {
|
for (ty.unionFields(mod).values()) |field| {
|
||||||
if (field.ty.bitSize(mod) > 32 or field.normalAlignment(mod) > 32) {
|
if (field.ty.bitSize(mod) > 32 or field.normalAlignment(mod) > 32) {
|
||||||
return Class.arrSize(bit_size, 64);
|
return Class.arrSize(bit_size, 64);
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +121,7 @@ fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u32 {
|
||||||
const invalid = std.math.maxInt(u32);
|
const invalid = std.math.maxInt(u32);
|
||||||
switch (ty.zigTypeTag(mod)) {
|
switch (ty.zigTypeTag(mod)) {
|
||||||
.Union => {
|
.Union => {
|
||||||
const fields = ty.unionFields();
|
const fields = ty.unionFields(mod);
|
||||||
var max_count: u32 = 0;
|
var max_count: u32 = 0;
|
||||||
for (fields.values()) |field| {
|
for (fields.values()) |field| {
|
||||||
const field_count = countFloats(field.ty, mod, maybe_float_bits);
|
const field_count = countFloats(field.ty, mod, maybe_float_bits);
|
||||||
|
|
|
||||||
|
|
@ -1739,8 +1739,8 @@ fn isByRef(ty: Type, mod: *Module) bool {
|
||||||
.Frame,
|
.Frame,
|
||||||
=> return ty.hasRuntimeBitsIgnoreComptime(mod),
|
=> return ty.hasRuntimeBitsIgnoreComptime(mod),
|
||||||
.Union => {
|
.Union => {
|
||||||
if (ty.castTag(.@"union")) |union_ty| {
|
if (mod.typeToUnion(ty)) |union_obj| {
|
||||||
if (union_ty.data.layout == .Packed) {
|
if (union_obj.layout == .Packed) {
|
||||||
return ty.abiSize(mod) > 8;
|
return ty.abiSize(mod) > 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3175,7 +3175,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
||||||
},
|
},
|
||||||
.Union => {
|
.Union => {
|
||||||
// in this case we have a packed union which will not be passed by reference.
|
// in this case we have a packed union which will not be passed by reference.
|
||||||
const union_ty = ty.cast(Type.Payload.Union).?.data;
|
const union_ty = mod.typeToUnion(ty).?;
|
||||||
const union_obj = val.castTag(.@"union").?.data;
|
const union_obj = val.castTag(.@"union").?.data;
|
||||||
const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?;
|
const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?;
|
||||||
const field_ty = union_ty.fields.values()[field_index].ty;
|
const field_ty = union_ty.fields.values()[field_index].ty;
|
||||||
|
|
@ -5086,12 +5086,12 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||||
const result = result: {
|
const result = result: {
|
||||||
const union_ty = func.typeOfIndex(inst);
|
const union_ty = func.typeOfIndex(inst);
|
||||||
const layout = union_ty.unionGetLayout(mod);
|
const layout = union_ty.unionGetLayout(mod);
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const field = union_obj.fields.values()[extra.field_index];
|
const field = union_obj.fields.values()[extra.field_index];
|
||||||
const field_name = union_obj.fields.keys()[extra.field_index];
|
const field_name = union_obj.fields.keys()[extra.field_index];
|
||||||
|
|
||||||
const tag_int = blk: {
|
const tag_int = blk: {
|
||||||
const tag_ty = union_ty.unionTagTypeHypothetical();
|
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
|
||||||
const enum_field_index = tag_ty.enumFieldIndex(field_name).?;
|
const enum_field_index = tag_ty.enumFieldIndex(field_name).?;
|
||||||
var tag_val_payload: Value.Payload.U32 = .{
|
var tag_val_payload: Value.Payload.U32 = .{
|
||||||
.base = .{ .tag = .enum_field_index },
|
.base = .{ .tag = .enum_field_index },
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,8 @@ pub fn classifyType(ty: Type, mod: *Module) [2]Class {
|
||||||
}
|
}
|
||||||
const layout = ty.unionGetLayout(mod);
|
const layout = ty.unionGetLayout(mod);
|
||||||
std.debug.assert(layout.tag_size == 0);
|
std.debug.assert(layout.tag_size == 0);
|
||||||
if (ty.unionFields().count() > 1) return memory;
|
if (ty.unionFields(mod).count() > 1) return memory;
|
||||||
return classifyType(ty.unionFields().values()[0].ty, mod);
|
return classifyType(ty.unionFields(mod).values()[0].ty, mod);
|
||||||
},
|
},
|
||||||
.ErrorUnion,
|
.ErrorUnion,
|
||||||
.Frame,
|
.Frame,
|
||||||
|
|
@ -111,11 +111,11 @@ pub fn scalarType(ty: Type, mod: *Module) Type {
|
||||||
if (ty.containerLayout(mod) != .Packed) {
|
if (ty.containerLayout(mod) != .Packed) {
|
||||||
const layout = ty.unionGetLayout(mod);
|
const layout = ty.unionGetLayout(mod);
|
||||||
if (layout.payload_size == 0 and layout.tag_size != 0) {
|
if (layout.payload_size == 0 and layout.tag_size != 0) {
|
||||||
return scalarType(ty.unionTagTypeSafety().?, mod);
|
return scalarType(ty.unionTagTypeSafety(mod).?, mod);
|
||||||
}
|
}
|
||||||
std.debug.assert(ty.unionFields().count() == 1);
|
std.debug.assert(ty.unionFields(mod).count() == 1);
|
||||||
}
|
}
|
||||||
return scalarType(ty.unionFields().values()[0].ty, mod);
|
return scalarType(ty.unionFields(mod).values()[0].ty, mod);
|
||||||
},
|
},
|
||||||
else => return ty,
|
else => return ty,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11410,9 +11410,9 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
|
||||||
const dst_mcv = try self.allocRegOrMem(inst, false);
|
const dst_mcv = try self.allocRegOrMem(inst, false);
|
||||||
|
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const field_name = union_obj.fields.keys()[extra.field_index];
|
const field_name = union_obj.fields.keys()[extra.field_index];
|
||||||
const tag_ty = union_ty.unionTagTypeSafety().?;
|
const tag_ty = union_obj.tag_ty;
|
||||||
const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
|
||||||
var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index };
|
var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index };
|
||||||
const tag_val = Value.initPayload(&tag_pl.base);
|
const tag_val = Value.initPayload(&tag_pl.base);
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,7 @@ pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class {
|
||||||
if (ty_size > 64)
|
if (ty_size > 64)
|
||||||
return memory_class;
|
return memory_class;
|
||||||
|
|
||||||
const fields = ty.unionFields();
|
const fields = ty.unionFields(mod);
|
||||||
for (fields.values()) |field| {
|
for (fields.values()) |field| {
|
||||||
if (field.abi_align != 0) {
|
if (field.abi_align != 0) {
|
||||||
if (field.abi_align < field.ty.abiAlignment(mod)) {
|
if (field.abi_align < field.ty.abiAlignment(mod)) {
|
||||||
|
|
|
||||||
|
|
@ -568,7 +568,7 @@ pub fn generateSymbol(
|
||||||
|
|
||||||
if (layout.payload_size == 0) {
|
if (layout.payload_size == 0) {
|
||||||
return generateSymbol(bin_file, src_loc, .{
|
return generateSymbol(bin_file, src_loc, .{
|
||||||
.ty = typed_value.ty.unionTagType().?,
|
.ty = typed_value.ty.unionTagType(mod).?,
|
||||||
.val = union_obj.tag,
|
.val = union_obj.tag,
|
||||||
}, code, debug_output, reloc_info);
|
}, code, debug_output, reloc_info);
|
||||||
}
|
}
|
||||||
|
|
@ -576,7 +576,7 @@ pub fn generateSymbol(
|
||||||
// Check if we should store the tag first.
|
// Check if we should store the tag first.
|
||||||
if (layout.tag_align >= layout.payload_align) {
|
if (layout.tag_align >= layout.payload_align) {
|
||||||
switch (try generateSymbol(bin_file, src_loc, .{
|
switch (try generateSymbol(bin_file, src_loc, .{
|
||||||
.ty = typed_value.ty.unionTagType().?,
|
.ty = typed_value.ty.unionTagType(mod).?,
|
||||||
.val = union_obj.tag,
|
.val = union_obj.tag,
|
||||||
}, code, debug_output, reloc_info)) {
|
}, code, debug_output, reloc_info)) {
|
||||||
.ok => {},
|
.ok => {},
|
||||||
|
|
@ -584,7 +584,7 @@ pub fn generateSymbol(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
|
const union_ty = mod.typeToUnion(typed_value.ty).?;
|
||||||
const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;
|
const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;
|
||||||
assert(union_ty.haveFieldTypes());
|
assert(union_ty.haveFieldTypes());
|
||||||
const field_ty = union_ty.fields.values()[field_index].ty;
|
const field_ty = union_ty.fields.values()[field_index].ty;
|
||||||
|
|
|
||||||
|
|
@ -853,7 +853,7 @@ pub const DeclGen = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeByte('{');
|
try writer.writeByte('{');
|
||||||
if (ty.unionTagTypeSafety()) |tag_ty| {
|
if (ty.unionTagTypeSafety(mod)) |tag_ty| {
|
||||||
const layout = ty.unionGetLayout(mod);
|
const layout = ty.unionGetLayout(mod);
|
||||||
if (layout.tag_size != 0) {
|
if (layout.tag_size != 0) {
|
||||||
try writer.writeAll(" .tag = ");
|
try writer.writeAll(" .tag = ");
|
||||||
|
|
@ -863,12 +863,12 @@ pub const DeclGen = struct {
|
||||||
if (layout.tag_size != 0) try writer.writeByte(',');
|
if (layout.tag_size != 0) try writer.writeByte(',');
|
||||||
try writer.writeAll(" .payload = {");
|
try writer.writeAll(" .payload = {");
|
||||||
}
|
}
|
||||||
for (ty.unionFields().values()) |field| {
|
for (ty.unionFields(mod).values()) |field| {
|
||||||
if (!field.ty.hasRuntimeBits(mod)) continue;
|
if (!field.ty.hasRuntimeBits(mod)) continue;
|
||||||
try dg.renderValue(writer, field.ty, val, initializer_type);
|
try dg.renderValue(writer, field.ty, val, initializer_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
|
if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
|
||||||
return writer.writeByte('}');
|
return writer.writeByte('}');
|
||||||
},
|
},
|
||||||
.ErrorUnion => {
|
.ErrorUnion => {
|
||||||
|
|
@ -1451,8 +1451,8 @@ pub const DeclGen = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const field_i = ty.unionTagFieldIndex(union_obj.tag, mod).?;
|
const field_i = ty.unionTagFieldIndex(union_obj.tag, mod).?;
|
||||||
const field_ty = ty.unionFields().values()[field_i].ty;
|
const field_ty = ty.unionFields(mod).values()[field_i].ty;
|
||||||
const field_name = ty.unionFields().keys()[field_i];
|
const field_name = ty.unionFields(mod).keys()[field_i];
|
||||||
if (ty.containerLayout(mod) == .Packed) {
|
if (ty.containerLayout(mod) == .Packed) {
|
||||||
if (field_ty.hasRuntimeBits(mod)) {
|
if (field_ty.hasRuntimeBits(mod)) {
|
||||||
if (field_ty.isPtrAtRuntime(mod)) {
|
if (field_ty.isPtrAtRuntime(mod)) {
|
||||||
|
|
@ -1472,7 +1472,7 @@ pub const DeclGen = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeByte('{');
|
try writer.writeByte('{');
|
||||||
if (ty.unionTagTypeSafety()) |tag_ty| {
|
if (ty.unionTagTypeSafety(mod)) |tag_ty| {
|
||||||
const layout = ty.unionGetLayout(mod);
|
const layout = ty.unionGetLayout(mod);
|
||||||
if (layout.tag_size != 0) {
|
if (layout.tag_size != 0) {
|
||||||
try writer.writeAll(" .tag = ");
|
try writer.writeAll(" .tag = ");
|
||||||
|
|
@ -1486,12 +1486,12 @@ pub const DeclGen = struct {
|
||||||
try writer.print(" .{ } = ", .{fmtIdent(field_name)});
|
try writer.print(" .{ } = ", .{fmtIdent(field_name)});
|
||||||
try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
|
try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
|
||||||
try writer.writeByte(' ');
|
try writer.writeByte(' ');
|
||||||
} else for (ty.unionFields().values()) |field| {
|
} else for (ty.unionFields(mod).values()) |field| {
|
||||||
if (!field.ty.hasRuntimeBits(mod)) continue;
|
if (!field.ty.hasRuntimeBits(mod)) continue;
|
||||||
try dg.renderValue(writer, field.ty, Value.undef, initializer_type);
|
try dg.renderValue(writer, field.ty, Value.undef, initializer_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');
|
if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
|
||||||
try writer.writeByte('}');
|
try writer.writeByte('}');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -5238,13 +5238,13 @@ fn fieldLocation(
|
||||||
.Auto, .Extern => {
|
.Auto, .Extern => {
|
||||||
const field_ty = container_ty.structFieldType(field_index, mod);
|
const field_ty = container_ty.structFieldType(field_index, mod);
|
||||||
if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))
|
if (!field_ty.hasRuntimeBitsIgnoreComptime(mod))
|
||||||
return if (container_ty.unionTagTypeSafety() != null and
|
return if (container_ty.unionTagTypeSafety(mod) != null and
|
||||||
!container_ty.unionHasAllZeroBitFieldTypes(mod))
|
!container_ty.unionHasAllZeroBitFieldTypes(mod))
|
||||||
.{ .field = .{ .identifier = "payload" } }
|
.{ .field = .{ .identifier = "payload" } }
|
||||||
else
|
else
|
||||||
.begin;
|
.begin;
|
||||||
const field_name = container_ty.unionFields().keys()[field_index];
|
const field_name = container_ty.unionFields(mod).keys()[field_index];
|
||||||
return .{ .field = if (container_ty.unionTagTypeSafety()) |_|
|
return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_|
|
||||||
.{ .payload_identifier = field_name }
|
.{ .payload_identifier = field_name }
|
||||||
else
|
else
|
||||||
.{ .identifier = field_name } };
|
.{ .identifier = field_name } };
|
||||||
|
|
@ -5424,37 +5424,6 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
else
|
else
|
||||||
.{ .identifier = struct_ty.structFieldName(extra.field_index, mod) },
|
.{ .identifier = struct_ty.structFieldName(extra.field_index, mod) },
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout(mod) == .Packed) {
|
|
||||||
const operand_lval = if (struct_byval == .constant) blk: {
|
|
||||||
const operand_local = try f.allocLocal(inst, struct_ty);
|
|
||||||
try f.writeCValue(writer, operand_local, .Other);
|
|
||||||
try writer.writeAll(" = ");
|
|
||||||
try f.writeCValue(writer, struct_byval, .Initializer);
|
|
||||||
try writer.writeAll(";\n");
|
|
||||||
break :blk operand_local;
|
|
||||||
} else struct_byval;
|
|
||||||
|
|
||||||
const local = try f.allocLocal(inst, inst_ty);
|
|
||||||
try writer.writeAll("memcpy(&");
|
|
||||||
try f.writeCValue(writer, local, .Other);
|
|
||||||
try writer.writeAll(", &");
|
|
||||||
try f.writeCValue(writer, operand_lval, .Other);
|
|
||||||
try writer.writeAll(", sizeof(");
|
|
||||||
try f.renderType(writer, inst_ty);
|
|
||||||
try writer.writeAll("));\n");
|
|
||||||
|
|
||||||
if (struct_byval == .constant) {
|
|
||||||
try freeLocal(f, inst, operand_lval.new_local, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return local;
|
|
||||||
} else field_name: {
|
|
||||||
const name = struct_ty.unionFields().keys()[extra.field_index];
|
|
||||||
break :field_name if (struct_ty.unionTagTypeSafety()) |_|
|
|
||||||
.{ .payload_identifier = name }
|
|
||||||
else
|
|
||||||
.{ .identifier = name };
|
|
||||||
},
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) {
|
else => switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) {
|
||||||
|
|
@ -5520,6 +5489,41 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
return local;
|
return local;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.union_type => |union_type| field_name: {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
if (union_obj.layout == .Packed) {
|
||||||
|
const operand_lval = if (struct_byval == .constant) blk: {
|
||||||
|
const operand_local = try f.allocLocal(inst, struct_ty);
|
||||||
|
try f.writeCValue(writer, operand_local, .Other);
|
||||||
|
try writer.writeAll(" = ");
|
||||||
|
try f.writeCValue(writer, struct_byval, .Initializer);
|
||||||
|
try writer.writeAll(";\n");
|
||||||
|
break :blk operand_local;
|
||||||
|
} else struct_byval;
|
||||||
|
|
||||||
|
const local = try f.allocLocal(inst, inst_ty);
|
||||||
|
try writer.writeAll("memcpy(&");
|
||||||
|
try f.writeCValue(writer, local, .Other);
|
||||||
|
try writer.writeAll(", &");
|
||||||
|
try f.writeCValue(writer, operand_lval, .Other);
|
||||||
|
try writer.writeAll(", sizeof(");
|
||||||
|
try f.renderType(writer, inst_ty);
|
||||||
|
try writer.writeAll("));\n");
|
||||||
|
|
||||||
|
if (struct_byval == .constant) {
|
||||||
|
try freeLocal(f, inst, operand_lval.new_local, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return local;
|
||||||
|
} else {
|
||||||
|
const name = union_obj.fields.keys()[extra.field_index];
|
||||||
|
break :field_name if (union_type.hasTag()) .{
|
||||||
|
.payload_identifier = name,
|
||||||
|
} else .{
|
||||||
|
.identifier = name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -6461,7 +6465,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const union_ty = f.typeOf(bin_op.lhs).childType(mod);
|
const union_ty = f.typeOf(bin_op.lhs).childType(mod);
|
||||||
const layout = union_ty.unionGetLayout(mod);
|
const layout = union_ty.unionGetLayout(mod);
|
||||||
if (layout.tag_size == 0) return .none;
|
if (layout.tag_size == 0) return .none;
|
||||||
const tag_ty = union_ty.unionTagTypeSafety().?;
|
const tag_ty = union_ty.unionTagTypeSafety(mod).?;
|
||||||
|
|
||||||
const writer = f.object.writer();
|
const writer = f.object.writer();
|
||||||
const a = try Assignment.start(f, writer, tag_ty);
|
const a = try Assignment.start(f, writer, tag_ty);
|
||||||
|
|
@ -6907,7 +6911,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||||
|
|
||||||
const union_ty = f.typeOfIndex(inst);
|
const union_ty = f.typeOfIndex(inst);
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const field_name = union_obj.fields.keys()[extra.field_index];
|
const field_name = union_obj.fields.keys()[extra.field_index];
|
||||||
const payload_ty = f.typeOf(extra.init);
|
const payload_ty = f.typeOf(extra.init);
|
||||||
const payload = try f.resolveInst(extra.init);
|
const payload = try f.resolveInst(extra.init);
|
||||||
|
|
@ -6923,7 +6927,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field: CValue = if (union_ty.unionTagTypeSafety()) |tag_ty| field: {
|
const field: CValue = if (union_ty.unionTagTypeSafety(mod)) |tag_ty| field: {
|
||||||
const layout = union_ty.unionGetLayout(mod);
|
const layout = union_ty.unionGetLayout(mod);
|
||||||
if (layout.tag_size != 0) {
|
if (layout.tag_size != 0) {
|
||||||
const field_index = tag_ty.enumFieldIndex(field_name).?;
|
const field_index = tag_ty.enumFieldIndex(field_name).?;
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ pub const CType = extern union {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs {
|
pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs {
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
const union_payload_align = union_obj.abiAlignment(mod, false);
|
const union_payload_align = union_obj.abiAlignment(mod, false);
|
||||||
return init(union_payload_align, union_payload_align);
|
return init(union_payload_align, union_payload_align);
|
||||||
}
|
}
|
||||||
|
|
@ -1498,7 +1498,7 @@ pub const CType = extern union {
|
||||||
if (lookup.isMutable()) {
|
if (lookup.isMutable()) {
|
||||||
for (0..switch (zig_ty_tag) {
|
for (0..switch (zig_ty_tag) {
|
||||||
.Struct => ty.structFieldCount(mod),
|
.Struct => ty.structFieldCount(mod),
|
||||||
.Union => ty.unionFields().count(),
|
.Union => ty.unionFields(mod).count(),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}) |field_i| {
|
}) |field_i| {
|
||||||
const field_ty = ty.structFieldType(field_i, mod);
|
const field_ty = ty.structFieldType(field_i, mod);
|
||||||
|
|
@ -1531,7 +1531,7 @@ pub const CType = extern union {
|
||||||
.payload => unreachable,
|
.payload => unreachable,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const tag_ty = ty.unionTagTypeSafety();
|
const tag_ty = ty.unionTagTypeSafety(mod);
|
||||||
const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
|
const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
|
||||||
const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
|
const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
|
@ -1580,7 +1580,7 @@ pub const CType = extern union {
|
||||||
var is_packed = false;
|
var is_packed = false;
|
||||||
for (0..switch (zig_ty_tag) {
|
for (0..switch (zig_ty_tag) {
|
||||||
.Struct => ty.structFieldCount(mod),
|
.Struct => ty.structFieldCount(mod),
|
||||||
.Union => ty.unionFields().count(),
|
.Union => ty.unionFields(mod).count(),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}) |field_i| {
|
}) |field_i| {
|
||||||
const field_ty = ty.structFieldType(field_i, mod);
|
const field_ty = ty.structFieldType(field_i, mod);
|
||||||
|
|
@ -1930,7 +1930,7 @@ pub const CType = extern union {
|
||||||
const zig_ty_tag = ty.zigTypeTag(mod);
|
const zig_ty_tag = ty.zigTypeTag(mod);
|
||||||
const fields_len = switch (zig_ty_tag) {
|
const fields_len = switch (zig_ty_tag) {
|
||||||
.Struct => ty.structFieldCount(mod),
|
.Struct => ty.structFieldCount(mod),
|
||||||
.Union => ty.unionFields().count(),
|
.Union => ty.unionFields(mod).count(),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1956,7 +1956,7 @@ pub const CType = extern union {
|
||||||
else
|
else
|
||||||
arena.dupeZ(u8, switch (zig_ty_tag) {
|
arena.dupeZ(u8, switch (zig_ty_tag) {
|
||||||
.Struct => ty.structFieldName(field_i, mod),
|
.Struct => ty.structFieldName(field_i, mod),
|
||||||
.Union => ty.unionFields().keys()[field_i],
|
.Union => ty.unionFields(mod).keys()[field_i],
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}),
|
}),
|
||||||
.type = store.set.typeToIndex(field_ty, mod, switch (kind) {
|
.type = store.set.typeToIndex(field_ty, mod, switch (kind) {
|
||||||
|
|
@ -1986,7 +1986,7 @@ pub const CType = extern union {
|
||||||
unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
|
unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
|
||||||
.fields = fields_pl,
|
.fields = fields_pl,
|
||||||
.owner_decl = ty.getOwnerDecl(mod),
|
.owner_decl = ty.getOwnerDecl(mod),
|
||||||
.id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable,
|
.id = if (ty.unionTagTypeSafety(mod)) |_| 0 else unreachable,
|
||||||
} };
|
} };
|
||||||
return initPayload(unnamed_pl);
|
return initPayload(unnamed_pl);
|
||||||
},
|
},
|
||||||
|
|
@ -2085,7 +2085,7 @@ pub const CType = extern union {
|
||||||
var c_field_i: usize = 0;
|
var c_field_i: usize = 0;
|
||||||
for (0..switch (zig_ty_tag) {
|
for (0..switch (zig_ty_tag) {
|
||||||
.Struct => ty.structFieldCount(mod),
|
.Struct => ty.structFieldCount(mod),
|
||||||
.Union => ty.unionFields().count(),
|
.Union => ty.unionFields(mod).count(),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}) |field_i| {
|
}) |field_i| {
|
||||||
const field_ty = ty.structFieldType(field_i, mod);
|
const field_ty = ty.structFieldType(field_i, mod);
|
||||||
|
|
@ -2106,7 +2106,7 @@ pub const CType = extern union {
|
||||||
std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
|
std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
|
||||||
else switch (zig_ty_tag) {
|
else switch (zig_ty_tag) {
|
||||||
.Struct => ty.structFieldName(field_i, mod),
|
.Struct => ty.structFieldName(field_i, mod),
|
||||||
.Union => ty.unionFields().keys()[field_i],
|
.Union => ty.unionFields(mod).keys()[field_i],
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
mem.span(c_field.name),
|
mem.span(c_field.name),
|
||||||
|
|
@ -2122,7 +2122,7 @@ pub const CType = extern union {
|
||||||
.packed_unnamed_union,
|
.packed_unnamed_union,
|
||||||
=> switch (self.kind) {
|
=> switch (self.kind) {
|
||||||
.forward, .forward_parameter, .complete, .parameter, .global => unreachable,
|
.forward, .forward_parameter, .complete, .parameter, .global => unreachable,
|
||||||
.payload => if (ty.unionTagTypeSafety()) |_| {
|
.payload => if (ty.unionTagTypeSafety(mod)) |_| {
|
||||||
const data = cty.cast(Payload.Unnamed).?.data;
|
const data = cty.cast(Payload.Unnamed).?.data;
|
||||||
return ty.getOwnerDecl(mod) == data.owner_decl and data.id == 0;
|
return ty.getOwnerDecl(mod) == data.owner_decl and data.id == 0;
|
||||||
} else unreachable,
|
} else unreachable,
|
||||||
|
|
@ -2211,7 +2211,7 @@ pub const CType = extern union {
|
||||||
const zig_ty_tag = ty.zigTypeTag(mod);
|
const zig_ty_tag = ty.zigTypeTag(mod);
|
||||||
for (0..switch (ty.zigTypeTag(mod)) {
|
for (0..switch (ty.zigTypeTag(mod)) {
|
||||||
.Struct => ty.structFieldCount(mod),
|
.Struct => ty.structFieldCount(mod),
|
||||||
.Union => ty.unionFields().count(),
|
.Union => ty.unionFields(mod).count(),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}) |field_i| {
|
}) |field_i| {
|
||||||
const field_ty = ty.structFieldType(field_i, mod);
|
const field_ty = ty.structFieldType(field_i, mod);
|
||||||
|
|
@ -2228,7 +2228,7 @@ pub const CType = extern union {
|
||||||
std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
|
std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
|
||||||
else switch (zig_ty_tag) {
|
else switch (zig_ty_tag) {
|
||||||
.Struct => ty.structFieldName(field_i, mod),
|
.Struct => ty.structFieldName(field_i, mod),
|
||||||
.Union => ty.unionFields().keys()[field_i],
|
.Union => ty.unionFields(mod).keys()[field_i],
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
});
|
});
|
||||||
autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");
|
autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align");
|
||||||
|
|
@ -2241,7 +2241,7 @@ pub const CType = extern union {
|
||||||
.packed_unnamed_union,
|
.packed_unnamed_union,
|
||||||
=> switch (self.kind) {
|
=> switch (self.kind) {
|
||||||
.forward, .forward_parameter, .complete, .parameter, .global => unreachable,
|
.forward, .forward_parameter, .complete, .parameter, .global => unreachable,
|
||||||
.payload => if (ty.unionTagTypeSafety()) |_| {
|
.payload => if (ty.unionTagTypeSafety(mod)) |_| {
|
||||||
autoHash(hasher, ty.getOwnerDecl(mod));
|
autoHash(hasher, ty.getOwnerDecl(mod));
|
||||||
autoHash(hasher, @as(u32, 0));
|
autoHash(hasher, @as(u32, 0));
|
||||||
} else unreachable,
|
} else unreachable,
|
||||||
|
|
|
||||||
|
|
@ -2178,7 +2178,7 @@ pub const Object = struct {
|
||||||
break :blk fwd_decl;
|
break :blk fwd_decl;
|
||||||
};
|
};
|
||||||
|
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
|
if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
|
||||||
const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
|
const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
|
||||||
dib.replaceTemporary(fwd_decl, union_di_ty);
|
dib.replaceTemporary(fwd_decl, union_di_ty);
|
||||||
|
|
@ -3063,7 +3063,7 @@ pub const DeclGen = struct {
|
||||||
gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
|
gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator());
|
||||||
|
|
||||||
const layout = t.unionGetLayout(mod);
|
const layout = t.unionGetLayout(mod);
|
||||||
const union_obj = t.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(t).?;
|
||||||
|
|
||||||
if (union_obj.layout == .Packed) {
|
if (union_obj.layout == .Packed) {
|
||||||
const bitsize = @intCast(c_uint, t.bitSize(mod));
|
const bitsize = @intCast(c_uint, t.bitSize(mod));
|
||||||
|
|
@ -3797,11 +3797,11 @@ pub const DeclGen = struct {
|
||||||
|
|
||||||
if (layout.payload_size == 0) {
|
if (layout.payload_size == 0) {
|
||||||
return lowerValue(dg, .{
|
return lowerValue(dg, .{
|
||||||
.ty = tv.ty.unionTagTypeSafety().?,
|
.ty = tv.ty.unionTagTypeSafety(mod).?,
|
||||||
.val = tag_and_val.tag,
|
.val = tag_and_val.tag,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const union_obj = tv.ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(tv.ty).?;
|
||||||
const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?;
|
const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?;
|
||||||
assert(union_obj.haveFieldTypes());
|
assert(union_obj.haveFieldTypes());
|
||||||
|
|
||||||
|
|
@ -3851,7 +3851,7 @@ pub const DeclGen = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const llvm_tag_value = try lowerValue(dg, .{
|
const llvm_tag_value = try lowerValue(dg, .{
|
||||||
.ty = tv.ty.unionTagTypeSafety().?,
|
.ty = tv.ty.unionTagTypeSafety(mod).?,
|
||||||
.val = tag_and_val.tag,
|
.val = tag_and_val.tag,
|
||||||
});
|
});
|
||||||
var fields: [3]*llvm.Value = undefined;
|
var fields: [3]*llvm.Value = undefined;
|
||||||
|
|
@ -9410,7 +9410,7 @@ pub const FuncGen = struct {
|
||||||
const union_ty = self.typeOfIndex(inst);
|
const union_ty = self.typeOfIndex(inst);
|
||||||
const union_llvm_ty = try self.dg.lowerType(union_ty);
|
const union_llvm_ty = try self.dg.lowerType(union_ty);
|
||||||
const layout = union_ty.unionGetLayout(mod);
|
const layout = union_ty.unionGetLayout(mod);
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(union_ty).?;
|
||||||
|
|
||||||
if (union_obj.layout == .Packed) {
|
if (union_obj.layout == .Packed) {
|
||||||
const big_bits = union_ty.bitSize(mod);
|
const big_bits = union_ty.bitSize(mod);
|
||||||
|
|
@ -9427,7 +9427,7 @@ pub const FuncGen = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag_int = blk: {
|
const tag_int = blk: {
|
||||||
const tag_ty = union_ty.unionTagTypeHypothetical();
|
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
|
||||||
const union_field_name = union_obj.fields.keys()[extra.field_index];
|
const union_field_name = union_obj.fields.keys()[extra.field_index];
|
||||||
const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?;
|
const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?;
|
||||||
var tag_val_payload: Value.Payload.U32 = .{
|
var tag_val_payload: Value.Payload.U32 = .{
|
||||||
|
|
|
||||||
|
|
@ -755,10 +755,10 @@ pub const DeclGen = struct {
|
||||||
const layout = ty.unionGetLayout(mod);
|
const layout = ty.unionGetLayout(mod);
|
||||||
|
|
||||||
if (layout.payload_size == 0) {
|
if (layout.payload_size == 0) {
|
||||||
return try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag);
|
return try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
const union_ty = ty.cast(Type.Payload.Union).?.data;
|
const union_ty = mod.typeToUnion(ty).?;
|
||||||
if (union_ty.layout == .Packed) {
|
if (union_ty.layout == .Packed) {
|
||||||
return dg.todo("packed union constants", .{});
|
return dg.todo("packed union constants", .{});
|
||||||
}
|
}
|
||||||
|
|
@ -770,7 +770,7 @@ pub const DeclGen = struct {
|
||||||
const tag_first = layout.tag_align >= layout.payload_align;
|
const tag_first = layout.tag_align >= layout.payload_align;
|
||||||
|
|
||||||
if (has_tag and tag_first) {
|
if (has_tag and tag_first) {
|
||||||
try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag);
|
try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {
|
const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {
|
||||||
|
|
@ -782,7 +782,7 @@ pub const DeclGen = struct {
|
||||||
try self.addUndef(payload_padding_len);
|
try self.addUndef(payload_padding_len);
|
||||||
|
|
||||||
if (has_tag and !tag_first) {
|
if (has_tag and !tag_first) {
|
||||||
try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag);
|
try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.addUndef(layout.padding);
|
try self.addUndef(layout.padding);
|
||||||
|
|
@ -1121,7 +1121,7 @@ pub const DeclGen = struct {
|
||||||
fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {
|
fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {
|
||||||
const mod = self.module;
|
const mod = self.module;
|
||||||
const layout = ty.unionGetLayout(mod);
|
const layout = ty.unionGetLayout(mod);
|
||||||
const union_ty = ty.cast(Type.Payload.Union).?.data;
|
const union_ty = mod.typeToUnion(ty).?;
|
||||||
|
|
||||||
if (union_ty.layout == .Packed) {
|
if (union_ty.layout == .Packed) {
|
||||||
return self.todo("packed union types", .{});
|
return self.todo("packed union types", .{});
|
||||||
|
|
|
||||||
|
|
@ -432,7 +432,7 @@ pub const DeclState = struct {
|
||||||
},
|
},
|
||||||
.Union => {
|
.Union => {
|
||||||
const layout = ty.unionGetLayout(mod);
|
const layout = ty.unionGetLayout(mod);
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;
|
const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0;
|
||||||
const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;
|
const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size;
|
||||||
const is_tagged = layout.tag_size > 0;
|
const is_tagged = layout.tag_size > 0;
|
||||||
|
|
@ -476,7 +476,7 @@ pub const DeclState = struct {
|
||||||
try dbg_info_buffer.writer().print("{s}\x00", .{union_name});
|
try dbg_info_buffer.writer().print("{s}\x00", .{union_name});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fields = ty.unionFields();
|
const fields = ty.unionFields(mod);
|
||||||
for (fields.keys()) |field_name| {
|
for (fields.keys()) |field_name| {
|
||||||
const field = fields.get(field_name).?;
|
const field = fields.get(field_name).?;
|
||||||
if (!field.ty.hasRuntimeBits(mod)) continue;
|
if (!field.ty.hasRuntimeBits(mod)) continue;
|
||||||
|
|
|
||||||
399
src/type.zig
399
src/type.zig
|
|
@ -68,11 +68,6 @@ pub const Type = struct {
|
||||||
.enum_simple,
|
.enum_simple,
|
||||||
.enum_numbered,
|
.enum_numbered,
|
||||||
=> return .Enum,
|
=> return .Enum,
|
||||||
|
|
||||||
.@"union",
|
|
||||||
.union_safety_tagged,
|
|
||||||
.union_tagged,
|
|
||||||
=> return .Union,
|
|
||||||
},
|
},
|
||||||
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
.int_type => return .Int,
|
.int_type => return .Int,
|
||||||
|
|
@ -140,6 +135,7 @@ pub const Type = struct {
|
||||||
},
|
},
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
.ptr => unreachable,
|
.ptr => unreachable,
|
||||||
|
|
@ -585,12 +581,6 @@ pub const Type = struct {
|
||||||
const b_enum_obj = (b.cast(Payload.EnumNumbered) orelse return false).data;
|
const b_enum_obj = (b.cast(Payload.EnumNumbered) orelse return false).data;
|
||||||
return a_enum_obj == b_enum_obj;
|
return a_enum_obj == b_enum_obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const a_union_obj = a.cast(Payload.Union).?.data;
|
|
||||||
const b_union_obj = (b.cast(Payload.Union) orelse return false).data;
|
|
||||||
return a_union_obj == b_union_obj;
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -752,12 +742,6 @@ pub const Type = struct {
|
||||||
std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
|
std.hash.autoHash(hasher, std.builtin.TypeId.Enum);
|
||||||
std.hash.autoHash(hasher, enum_obj);
|
std.hash.autoHash(hasher, enum_obj);
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data;
|
|
||||||
std.hash.autoHash(hasher, std.builtin.TypeId.Union);
|
|
||||||
std.hash.autoHash(hasher, union_obj);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -935,7 +919,6 @@ pub const Type = struct {
|
||||||
.error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
|
.error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
|
||||||
.error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
|
.error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
|
||||||
.error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
|
.error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
|
||||||
.@"union", .union_safety_tagged, .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union),
|
|
||||||
.enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
|
.enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
|
||||||
.enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),
|
.enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered),
|
||||||
.enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
|
.enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
|
||||||
|
|
@ -1011,12 +994,6 @@ pub const Type = struct {
|
||||||
while (true) {
|
while (true) {
|
||||||
const t = ty.tag();
|
const t = ty.tag();
|
||||||
switch (t) {
|
switch (t) {
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return writer.print("({s} decl={d})", .{
|
|
||||||
@tagName(t), union_obj.owner_decl,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
.enum_full, .enum_nonexhaustive => {
|
.enum_full, .enum_nonexhaustive => {
|
||||||
const enum_full = ty.cast(Payload.EnumFull).?.data;
|
const enum_full = ty.cast(Payload.EnumFull).?.data;
|
||||||
return writer.print("({s} decl={d})", .{
|
return writer.print("({s} decl={d})", .{
|
||||||
|
|
@ -1221,11 +1198,6 @@ pub const Type = struct {
|
||||||
.inferred_alloc_const => unreachable,
|
.inferred_alloc_const => unreachable,
|
||||||
.inferred_alloc_mut => unreachable,
|
.inferred_alloc_mut => unreachable,
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
const decl = mod.declPtr(union_obj.owner_decl);
|
|
||||||
try decl.renderFullyQualifiedName(mod, writer);
|
|
||||||
},
|
|
||||||
.enum_full, .enum_nonexhaustive => {
|
.enum_full, .enum_nonexhaustive => {
|
||||||
const enum_full = ty.cast(Payload.EnumFull).?.data;
|
const enum_full = ty.cast(Payload.EnumFull).?.data;
|
||||||
const decl = mod.declPtr(enum_full.owner_decl);
|
const decl = mod.declPtr(enum_full.owner_decl);
|
||||||
|
|
@ -1518,13 +1490,18 @@ pub const Type = struct {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
const decl = mod.declPtr(union_obj.owner_decl);
|
||||||
|
try decl.renderFullyQualifiedName(mod, writer);
|
||||||
|
},
|
||||||
.opaque_type => |opaque_type| {
|
.opaque_type => |opaque_type| {
|
||||||
const decl = mod.declPtr(opaque_type.decl);
|
const decl = mod.declPtr(opaque_type.decl);
|
||||||
try decl.renderFullyQualifiedName(mod, writer);
|
try decl.renderFullyQualifiedName(mod, writer);
|
||||||
},
|
},
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -1627,45 +1604,6 @@ pub const Type = struct {
|
||||||
return int_tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
|
return int_tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat);
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union" => {
|
|
||||||
const union_obj = ty.castTag(.@"union").?.data;
|
|
||||||
if (union_obj.status == .field_types_wip) {
|
|
||||||
// In this case, we guess that hasRuntimeBits() for this type is true,
|
|
||||||
// and then later if our guess was incorrect, we emit a compile error.
|
|
||||||
union_obj.assumed_runtime_bits = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
switch (strat) {
|
|
||||||
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
|
||||||
.eager => assert(union_obj.haveFieldTypes()),
|
|
||||||
.lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
|
|
||||||
}
|
|
||||||
for (union_obj.fields.values()) |value| {
|
|
||||||
if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (strat) {
|
|
||||||
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
|
||||||
.eager => assert(union_obj.haveFieldTypes()),
|
|
||||||
.lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
|
|
||||||
}
|
|
||||||
for (union_obj.fields.values()) |value| {
|
|
||||||
if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.array => return ty.arrayLen(mod) != 0 and
|
.array => return ty.arrayLen(mod) != 0 and
|
||||||
try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
|
try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
|
||||||
.array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
|
.array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
|
||||||
|
|
@ -1795,10 +1733,40 @@ pub const Type = struct {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
switch (union_type.runtime_tag) {
|
||||||
|
.none => {
|
||||||
|
if (union_obj.status == .field_types_wip) {
|
||||||
|
// In this case, we guess that hasRuntimeBits() for this type is true,
|
||||||
|
// and then later if our guess was incorrect, we emit a compile error.
|
||||||
|
union_obj.assumed_runtime_bits = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.safety, .tagged => {
|
||||||
|
if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
switch (strat) {
|
||||||
|
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
||||||
|
.eager => assert(union_obj.haveFieldTypes()),
|
||||||
|
.lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
|
||||||
|
}
|
||||||
|
for (union_obj.fields.values()) |value| {
|
||||||
|
if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
.opaque_type => true,
|
.opaque_type => true,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -1847,8 +1815,6 @@ pub const Type = struct {
|
||||||
=> ty.childType(mod).hasWellDefinedLayout(mod),
|
=> ty.childType(mod).hasWellDefinedLayout(mod),
|
||||||
|
|
||||||
.optional => ty.isPtrLikeOptional(mod),
|
.optional => ty.isPtrLikeOptional(mod),
|
||||||
.@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto,
|
|
||||||
.union_tagged => false,
|
|
||||||
},
|
},
|
||||||
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
.int_type => true,
|
.int_type => true,
|
||||||
|
|
@ -1912,10 +1878,14 @@ pub const Type = struct {
|
||||||
};
|
};
|
||||||
return struct_obj.layout != .Auto;
|
return struct_obj.layout != .Auto;
|
||||||
},
|
},
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| switch (union_type.runtime_tag) {
|
||||||
|
.none, .safety => mod.unionPtr(union_type.index).layout != .Auto,
|
||||||
|
.tagged => false,
|
||||||
|
},
|
||||||
.opaque_type => false,
|
.opaque_type => false,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -2146,14 +2116,6 @@ pub const Type = struct {
|
||||||
const int_tag_ty = try ty.intTagType(mod);
|
const int_tag_ty = try ty.intTagType(mod);
|
||||||
return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(mod) };
|
return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(mod) };
|
||||||
},
|
},
|
||||||
.@"union" => {
|
|
||||||
const union_obj = ty.castTag(.@"union").?.data;
|
|
||||||
return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, false);
|
|
||||||
},
|
|
||||||
.union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
.inferred_alloc_const,
|
.inferred_alloc_const,
|
||||||
.inferred_alloc_mut,
|
.inferred_alloc_mut,
|
||||||
|
|
@ -2312,10 +2274,14 @@ pub const Type = struct {
|
||||||
}
|
}
|
||||||
return AbiAlignmentAdvanced{ .scalar = big_align };
|
return AbiAlignmentAdvanced{ .scalar = big_align };
|
||||||
},
|
},
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
|
||||||
|
},
|
||||||
.opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
|
.opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 },
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -2508,14 +2474,6 @@ pub const Type = struct {
|
||||||
const int_tag_ty = try ty.intTagType(mod);
|
const int_tag_ty = try ty.intTagType(mod);
|
||||||
return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(mod) };
|
return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(mod) };
|
||||||
},
|
},
|
||||||
.@"union" => {
|
|
||||||
const union_obj = ty.castTag(.@"union").?.data;
|
|
||||||
return abiSizeAdvancedUnion(ty, mod, strat, union_obj, false);
|
|
||||||
},
|
|
||||||
.union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return abiSizeAdvancedUnion(ty, mod, strat, union_obj, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
.array => {
|
.array => {
|
||||||
const payload = ty.castTag(.array).?.data;
|
const payload = ty.castTag(.array).?.data;
|
||||||
|
|
@ -2737,10 +2695,14 @@ pub const Type = struct {
|
||||||
return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
|
return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag());
|
||||||
|
},
|
||||||
.opaque_type => unreachable, // no size available
|
.opaque_type => unreachable, // no size available
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -2860,21 +2822,6 @@ pub const Type = struct {
|
||||||
return try bitSizeAdvanced(int_tag_ty, mod, opt_sema);
|
return try bitSizeAdvanced(int_tag_ty, mod, opt_sema);
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
|
|
||||||
if (ty.containerLayout(mod) != .Packed) {
|
|
||||||
return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
|
|
||||||
}
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
assert(union_obj.haveFieldTypes());
|
|
||||||
|
|
||||||
var size: u64 = 0;
|
|
||||||
for (union_obj.fields.values()) |field| {
|
|
||||||
size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema));
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
},
|
|
||||||
|
|
||||||
.array => {
|
.array => {
|
||||||
const payload = ty.castTag(.array).?.data;
|
const payload = ty.castTag(.array).?.data;
|
||||||
const elem_size = std.math.max(payload.elem_type.abiAlignment(mod), payload.elem_type.abiSize(mod));
|
const elem_size = std.math.max(payload.elem_type.abiAlignment(mod), payload.elem_type.abiSize(mod));
|
||||||
|
|
@ -2996,10 +2943,24 @@ pub const Type = struct {
|
||||||
return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema);
|
return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema);
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
|
||||||
|
if (ty.containerLayout(mod) != .Packed) {
|
||||||
|
return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
|
||||||
|
}
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
assert(union_obj.haveFieldTypes());
|
||||||
|
|
||||||
|
var size: u64 = 0;
|
||||||
|
for (union_obj.fields.values()) |field| {
|
||||||
|
size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema));
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
},
|
||||||
.opaque_type => unreachable,
|
.opaque_type => unreachable,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -3022,8 +2983,8 @@ pub const Type = struct {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.Union => {
|
.Union => {
|
||||||
if (ty.cast(Payload.Union)) |union_ty| {
|
if (mod.typeToUnion(ty)) |union_obj| {
|
||||||
return union_ty.data.haveLayout();
|
return union_obj.haveLayout();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
@ -3413,76 +3374,71 @@ pub const Type = struct {
|
||||||
|
|
||||||
/// Returns the tag type of a union, if the type is a union and it has a tag type.
|
/// Returns the tag type of a union, if the type is a union and it has a tag type.
|
||||||
/// Otherwise, returns `null`.
|
/// Otherwise, returns `null`.
|
||||||
pub fn unionTagType(ty: Type) ?Type {
|
pub fn unionTagType(ty: Type, mod: *Module) ?Type {
|
||||||
return switch (ty.tag()) {
|
return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
.union_tagged => {
|
.union_type => |union_type| switch (union_type.runtime_tag) {
|
||||||
const union_obj = ty.castTag(.union_tagged).?.data;
|
.tagged => {
|
||||||
assert(union_obj.haveFieldTypes());
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
return union_obj.tag_ty;
|
assert(union_obj.haveFieldTypes());
|
||||||
|
return union_obj.tag_ty;
|
||||||
|
},
|
||||||
|
else => null,
|
||||||
},
|
},
|
||||||
|
|
||||||
else => null,
|
else => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `unionTagType` but includes safety tag.
|
/// Same as `unionTagType` but includes safety tag.
|
||||||
/// Codegen should use this version.
|
/// Codegen should use this version.
|
||||||
pub fn unionTagTypeSafety(ty: Type) ?Type {
|
pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
|
||||||
return switch (ty.tag()) {
|
return switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
.union_safety_tagged, .union_tagged => {
|
.union_type => |union_type| {
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
if (!union_type.hasTag()) return null;
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
assert(union_obj.haveFieldTypes());
|
assert(union_obj.haveFieldTypes());
|
||||||
return union_obj.tag_ty;
|
return union_obj.tag_ty;
|
||||||
},
|
},
|
||||||
|
|
||||||
else => null,
|
else => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts the type is a union; returns the tag type, even if the tag will
|
/// Asserts the type is a union; returns the tag type, even if the tag will
|
||||||
/// not be stored at runtime.
|
/// not be stored at runtime.
|
||||||
pub fn unionTagTypeHypothetical(ty: Type) Type {
|
pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type {
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
assert(union_obj.haveFieldTypes());
|
assert(union_obj.haveFieldTypes());
|
||||||
return union_obj.tag_ty;
|
return union_obj.tag_ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unionFields(ty: Type) Module.Union.Fields {
|
pub fn unionFields(ty: Type, mod: *Module) Module.Union.Fields {
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
assert(union_obj.haveFieldTypes());
|
assert(union_obj.haveFieldTypes());
|
||||||
return union_obj.fields;
|
return union_obj.fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {
|
pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
const index = ty.unionTagFieldIndex(enum_tag, mod).?;
|
const index = ty.unionTagFieldIndex(enum_tag, mod).?;
|
||||||
assert(union_obj.haveFieldTypes());
|
assert(union_obj.haveFieldTypes());
|
||||||
return union_obj.fields.values()[index].ty;
|
return union_obj.fields.values()[index].ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
|
pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;
|
const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;
|
||||||
const name = union_obj.tag_ty.enumFieldName(index);
|
const name = union_obj.tag_ty.enumFieldName(index);
|
||||||
return union_obj.fields.getIndex(name);
|
return union_obj.fields.getIndex(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {
|
pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {
|
||||||
return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes(mod);
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
|
return union_obj.hasAllZeroBitFieldTypes(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unionGetLayout(ty: Type, mod: *Module) Module.Union.Layout {
|
pub fn unionGetLayout(ty: Type, mod: *Module) Module.Union.Layout {
|
||||||
switch (ty.tag()) {
|
const union_type = mod.intern_pool.indexToKey(ty.ip_index).union_type;
|
||||||
.@"union" => {
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
const union_obj = ty.castTag(.@"union").?.data;
|
return union_obj.getLayout(mod, union_type.hasTag());
|
||||||
return union_obj.getLayout(mod, false);
|
|
||||||
},
|
|
||||||
.union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return union_obj.getLayout(mod, true);
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
|
pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
|
||||||
|
|
@ -3490,9 +3446,6 @@ pub const Type = struct {
|
||||||
.empty_struct_type => .Auto,
|
.empty_struct_type => .Auto,
|
||||||
.none => switch (ty.tag()) {
|
.none => switch (ty.tag()) {
|
||||||
.tuple, .anon_struct => .Auto,
|
.tuple, .anon_struct => .Auto,
|
||||||
.@"union" => ty.castTag(.@"union").?.data.layout,
|
|
||||||
.union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout,
|
|
||||||
.union_tagged => ty.castTag(.union_tagged).?.data.layout,
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
|
|
@ -3500,6 +3453,10 @@ pub const Type = struct {
|
||||||
const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;
|
const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto;
|
||||||
return struct_obj.layout;
|
return struct_obj.layout;
|
||||||
},
|
},
|
||||||
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return union_obj.layout;
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -3777,6 +3734,7 @@ pub const Type = struct {
|
||||||
.opaque_type => unreachable,
|
.opaque_type => unreachable,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -4038,16 +3996,6 @@ pub const Type = struct {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null;
|
|
||||||
if (union_obj.fields.count() == 0) return Value.@"unreachable";
|
|
||||||
const only_field = union_obj.fields.values()[0];
|
|
||||||
const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null;
|
|
||||||
_ = tag_val;
|
|
||||||
_ = val_val;
|
|
||||||
return Value.empty_struct;
|
|
||||||
},
|
|
||||||
|
|
||||||
.array => {
|
.array => {
|
||||||
if (ty.arrayLen(mod) == 0)
|
if (ty.arrayLen(mod) == 0)
|
||||||
|
|
@ -4153,10 +4101,23 @@ pub const Type = struct {
|
||||||
return empty.toValue();
|
return empty.toValue();
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null;
|
||||||
|
if (union_obj.fields.count() == 0) return Value.@"unreachable";
|
||||||
|
const only_field = union_obj.fields.values()[0];
|
||||||
|
const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null;
|
||||||
|
const only = try mod.intern(.{ .un = .{
|
||||||
|
.ty = ty.ip_index,
|
||||||
|
.tag = tag_val.ip_index,
|
||||||
|
.val = val_val.ip_index,
|
||||||
|
} });
|
||||||
|
return only.toValue();
|
||||||
|
},
|
||||||
.opaque_type => return null,
|
.opaque_type => return null,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -4216,20 +4177,6 @@ pub const Type = struct {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
|
||||||
switch (union_obj.requires_comptime) {
|
|
||||||
.wip, .unknown => {
|
|
||||||
// Return false to avoid incorrect dependency loops.
|
|
||||||
// This will be handled correctly once merged with
|
|
||||||
// `Sema.typeRequiresComptime`.
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
.no => return false,
|
|
||||||
.yes => return true,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.error_union => return ty.errorUnionPayload().comptimeOnly(mod),
|
.error_union => return ty.errorUnionPayload().comptimeOnly(mod),
|
||||||
.anyframe_T => {
|
.anyframe_T => {
|
||||||
const child_ty = ty.castTag(.anyframe_T).?.data;
|
const child_ty = ty.castTag(.anyframe_T).?.data;
|
||||||
|
|
@ -4321,10 +4268,24 @@ pub const Type = struct {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
switch (union_obj.requires_comptime) {
|
||||||
|
.wip, .unknown => {
|
||||||
|
// Return false to avoid incorrect dependency loops.
|
||||||
|
// This will be handled correctly once merged with
|
||||||
|
// `Sema.typeRequiresComptime`.
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
.no => return false,
|
||||||
|
.yes => return true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
.opaque_type => false,
|
.opaque_type => false,
|
||||||
|
|
||||||
// values, not types
|
// values, not types
|
||||||
|
.un => unreachable,
|
||||||
.simple_value => unreachable,
|
.simple_value => unreachable,
|
||||||
.extern_func => unreachable,
|
.extern_func => unreachable,
|
||||||
.int => unreachable,
|
.int => unreachable,
|
||||||
|
|
@ -4378,15 +4339,13 @@ pub const Type = struct {
|
||||||
.none => switch (ty.tag()) {
|
.none => switch (ty.tag()) {
|
||||||
.enum_full => ty.castTag(.enum_full).?.data.namespace.toOptional(),
|
.enum_full => ty.castTag(.enum_full).?.data.namespace.toOptional(),
|
||||||
.enum_nonexhaustive => ty.castTag(.enum_nonexhaustive).?.data.namespace.toOptional(),
|
.enum_nonexhaustive => ty.castTag(.enum_nonexhaustive).?.data.namespace.toOptional(),
|
||||||
.@"union" => ty.castTag(.@"union").?.data.namespace.toOptional(),
|
|
||||||
.union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.namespace.toOptional(),
|
|
||||||
.union_tagged => ty.castTag(.union_tagged).?.data.namespace.toOptional(),
|
|
||||||
|
|
||||||
else => .none,
|
else => .none,
|
||||||
},
|
},
|
||||||
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
.opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
|
.opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
|
||||||
.struct_type => |struct_type| struct_type.namespace,
|
.struct_type => |struct_type| struct_type.namespace,
|
||||||
|
.union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(),
|
||||||
|
|
||||||
else => .none,
|
else => .none,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -4474,20 +4433,23 @@ pub const Type = struct {
|
||||||
|
|
||||||
/// Asserts the type is an enum or a union.
|
/// Asserts the type is an enum or a union.
|
||||||
pub fn intTagType(ty: Type, mod: *Module) !Type {
|
pub fn intTagType(ty: Type, mod: *Module) !Type {
|
||||||
switch (ty.tag()) {
|
return switch (ty.ip_index) {
|
||||||
.enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty,
|
.none => switch (ty.tag()) {
|
||||||
.enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,
|
.enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.tag_ty,
|
||||||
.enum_simple => {
|
.enum_numbered => ty.castTag(.enum_numbered).?.data.tag_ty,
|
||||||
const enum_simple = ty.castTag(.enum_simple).?.data;
|
.enum_simple => {
|
||||||
const field_count = enum_simple.fields.count();
|
const enum_simple = ty.castTag(.enum_simple).?.data;
|
||||||
const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count);
|
const field_count = enum_simple.fields.count();
|
||||||
return mod.intType(.unsigned, bits);
|
const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count);
|
||||||
|
return mod.intType(.unsigned, bits);
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.union_tagged => {
|
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
return ty.castTag(.union_tagged).?.data.tag_ty.intTagType(mod);
|
.union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod),
|
||||||
|
else => unreachable,
|
||||||
},
|
},
|
||||||
else => unreachable,
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isNonexhaustiveEnum(ty: Type) bool {
|
pub fn isNonexhaustiveEnum(ty: Type) bool {
|
||||||
|
|
@ -4663,10 +4625,6 @@ pub const Type = struct {
|
||||||
pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
|
pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
|
||||||
return switch (ty.ip_index) {
|
return switch (ty.ip_index) {
|
||||||
.none => switch (ty.tag()) {
|
.none => switch (ty.tag()) {
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return union_obj.fields.values()[index].ty;
|
|
||||||
},
|
|
||||||
.tuple => return ty.castTag(.tuple).?.data.types[index],
|
.tuple => return ty.castTag(.tuple).?.data.types[index],
|
||||||
.anon_struct => return ty.castTag(.anon_struct).?.data.types[index],
|
.anon_struct => return ty.castTag(.anon_struct).?.data.types[index],
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
|
|
@ -4676,6 +4634,10 @@ pub const Type = struct {
|
||||||
const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
|
const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
|
||||||
return struct_obj.fields.values()[index].ty;
|
return struct_obj.fields.values()[index].ty;
|
||||||
},
|
},
|
||||||
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return union_obj.fields.values()[index].ty;
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -4684,10 +4646,6 @@ pub const Type = struct {
|
||||||
pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {
|
pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 {
|
||||||
switch (ty.ip_index) {
|
switch (ty.ip_index) {
|
||||||
.none => switch (ty.tag()) {
|
.none => switch (ty.tag()) {
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return union_obj.fields.values()[index].normalAlignment(mod);
|
|
||||||
},
|
|
||||||
.tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(mod),
|
.tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(mod),
|
||||||
.anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(mod),
|
.anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(mod),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
|
|
@ -4698,6 +4656,10 @@ pub const Type = struct {
|
||||||
assert(struct_obj.layout != .Packed);
|
assert(struct_obj.layout != .Packed);
|
||||||
return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout);
|
return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout);
|
||||||
},
|
},
|
||||||
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return union_obj.fields.values()[index].normalAlignment(mod);
|
||||||
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -4889,18 +4851,6 @@ pub const Type = struct {
|
||||||
return offset;
|
return offset;
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"union" => return 0,
|
|
||||||
.union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
const layout = union_obj.getLayout(mod, true);
|
|
||||||
if (layout.tag_align >= layout.payload_align) {
|
|
||||||
// {Tag, Payload}
|
|
||||||
return std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align);
|
|
||||||
} else {
|
|
||||||
// {Payload, Tag}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
|
||||||
|
|
@ -4917,6 +4867,20 @@ pub const Type = struct {
|
||||||
return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1));
|
return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.union_type => |union_type| {
|
||||||
|
if (!union_type.hasTag())
|
||||||
|
return 0;
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
const layout = union_obj.getLayout(mod, true);
|
||||||
|
if (layout.tag_align >= layout.payload_align) {
|
||||||
|
// {Tag, Payload}
|
||||||
|
return std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align);
|
||||||
|
} else {
|
||||||
|
// {Payload, Tag}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -4946,10 +4910,6 @@ pub const Type = struct {
|
||||||
const error_set = ty.castTag(.error_set).?.data;
|
const error_set = ty.castTag(.error_set).?.data;
|
||||||
return error_set.srcLoc(mod);
|
return error_set.srcLoc(mod);
|
||||||
},
|
},
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return union_obj.srcLoc(mod);
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return null,
|
else => return null,
|
||||||
},
|
},
|
||||||
|
|
@ -4958,7 +4918,10 @@ pub const Type = struct {
|
||||||
const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
|
const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
|
||||||
return struct_obj.srcLoc(mod);
|
return struct_obj.srcLoc(mod);
|
||||||
},
|
},
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return union_obj.srcLoc(mod);
|
||||||
|
},
|
||||||
.opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
|
.opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type),
|
||||||
else => null,
|
else => null,
|
||||||
},
|
},
|
||||||
|
|
@ -4985,10 +4948,6 @@ pub const Type = struct {
|
||||||
const error_set = ty.castTag(.error_set).?.data;
|
const error_set = ty.castTag(.error_set).?.data;
|
||||||
return error_set.owner_decl;
|
return error_set.owner_decl;
|
||||||
},
|
},
|
||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
|
||||||
const union_obj = ty.cast(Payload.Union).?.data;
|
|
||||||
return union_obj.owner_decl;
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return null,
|
else => return null,
|
||||||
},
|
},
|
||||||
|
|
@ -4997,7 +4956,10 @@ pub const Type = struct {
|
||||||
const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;
|
const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null;
|
||||||
return struct_obj.owner_decl;
|
return struct_obj.owner_decl;
|
||||||
},
|
},
|
||||||
.union_type => @panic("TODO"),
|
.union_type => |union_type| {
|
||||||
|
const union_obj = mod.unionPtr(union_type.index);
|
||||||
|
return union_obj.owner_decl;
|
||||||
|
},
|
||||||
.opaque_type => |opaque_type| opaque_type.decl,
|
.opaque_type => |opaque_type| opaque_type.decl,
|
||||||
else => null,
|
else => null,
|
||||||
},
|
},
|
||||||
|
|
@ -5039,9 +5001,6 @@ pub const Type = struct {
|
||||||
/// The type is the inferred error set of a specific function.
|
/// The type is the inferred error set of a specific function.
|
||||||
error_set_inferred,
|
error_set_inferred,
|
||||||
error_set_merged,
|
error_set_merged,
|
||||||
@"union",
|
|
||||||
union_safety_tagged,
|
|
||||||
union_tagged,
|
|
||||||
enum_simple,
|
enum_simple,
|
||||||
enum_numbered,
|
enum_numbered,
|
||||||
enum_full,
|
enum_full,
|
||||||
|
|
@ -5070,7 +5029,6 @@ pub const Type = struct {
|
||||||
.function => Payload.Function,
|
.function => Payload.Function,
|
||||||
.error_union => Payload.ErrorUnion,
|
.error_union => Payload.ErrorUnion,
|
||||||
.error_set_single => Payload.Name,
|
.error_set_single => Payload.Name,
|
||||||
.@"union", .union_safety_tagged, .union_tagged => Payload.Union,
|
|
||||||
.enum_full, .enum_nonexhaustive => Payload.EnumFull,
|
.enum_full, .enum_nonexhaustive => Payload.EnumFull,
|
||||||
.enum_simple => Payload.EnumSimple,
|
.enum_simple => Payload.EnumSimple,
|
||||||
.enum_numbered => Payload.EnumNumbered,
|
.enum_numbered => Payload.EnumNumbered,
|
||||||
|
|
@ -5373,11 +5331,6 @@ pub const Type = struct {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Union = struct {
|
|
||||||
base: Payload,
|
|
||||||
data: *Module.Union,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const EnumFull = struct {
|
pub const EnumFull = struct {
|
||||||
base: Payload,
|
base: Payload,
|
||||||
data: *Module.EnumFull,
|
data: *Module.EnumFull,
|
||||||
|
|
|
||||||
|
|
@ -715,7 +715,7 @@ pub const Value = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {
|
pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {
|
||||||
if (ty.zigTypeTag(mod) == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(), mod);
|
if (ty.zigTypeTag(mod) == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(mod), mod);
|
||||||
|
|
||||||
const field_index = switch (val.tag()) {
|
const field_index = switch (val.tag()) {
|
||||||
.enum_field_index => val.castTag(.enum_field_index).?.data,
|
.enum_field_index => val.castTag(.enum_field_index).?.data,
|
||||||
|
|
@ -1138,7 +1138,7 @@ pub const Value = struct {
|
||||||
.Extern => unreachable, // Handled in non-packed writeToMemory
|
.Extern => unreachable, // Handled in non-packed writeToMemory
|
||||||
.Packed => {
|
.Packed => {
|
||||||
const field_index = ty.unionTagFieldIndex(val.unionTag(), mod);
|
const field_index = ty.unionTagFieldIndex(val.unionTag(), mod);
|
||||||
const field_type = ty.unionFields().values()[field_index.?].ty;
|
const field_type = ty.unionFields(mod).values()[field_index.?].ty;
|
||||||
const field_val = try val.fieldValue(field_type, mod, field_index.?);
|
const field_val = try val.fieldValue(field_type, mod, field_index.?);
|
||||||
|
|
||||||
return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
|
return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
|
||||||
|
|
@ -2021,7 +2021,7 @@ pub const Value = struct {
|
||||||
const b_union = b.castTag(.@"union").?.data;
|
const b_union = b.castTag(.@"union").?.data;
|
||||||
switch (ty.containerLayout(mod)) {
|
switch (ty.containerLayout(mod)) {
|
||||||
.Packed, .Extern => {
|
.Packed, .Extern => {
|
||||||
const tag_ty = ty.unionTagTypeHypothetical();
|
const tag_ty = ty.unionTagTypeHypothetical(mod);
|
||||||
if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {
|
if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {
|
||||||
// In this case, we must disregard mismatching tags and compare
|
// In this case, we must disregard mismatching tags and compare
|
||||||
// based on the in-memory bytes of the payloads.
|
// based on the in-memory bytes of the payloads.
|
||||||
|
|
@ -2029,7 +2029,7 @@ pub const Value = struct {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Auto => {
|
.Auto => {
|
||||||
const tag_ty = ty.unionTagTypeHypothetical();
|
const tag_ty = ty.unionTagTypeHypothetical(mod);
|
||||||
if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {
|
if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2118,7 +2118,7 @@ pub const Value = struct {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const field_name = tuple.names[0];
|
const field_name = tuple.names[0];
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
const union_obj = mod.typeToUnion(ty).?;
|
||||||
const field_index = union_obj.fields.getIndex(field_name) orelse return false;
|
const field_index = union_obj.fields.getIndex(field_name) orelse return false;
|
||||||
const tag_and_val = b.castTag(.@"union").?.data;
|
const tag_and_val = b.castTag(.@"union").?.data;
|
||||||
var field_tag_buf: Value.Payload.U32 = .{
|
var field_tag_buf: Value.Payload.U32 = .{
|
||||||
|
|
@ -2297,7 +2297,7 @@ pub const Value = struct {
|
||||||
},
|
},
|
||||||
.Union => {
|
.Union => {
|
||||||
const union_obj = val.cast(Payload.Union).?.data;
|
const union_obj = val.cast(Payload.Union).?.data;
|
||||||
if (ty.unionTagType()) |tag_ty| {
|
if (ty.unionTagType(mod)) |tag_ty| {
|
||||||
union_obj.tag.hash(tag_ty, hasher, mod);
|
union_obj.tag.hash(tag_ty, hasher, mod);
|
||||||
}
|
}
|
||||||
const active_field_ty = ty.unionFieldType(union_obj.tag, mod);
|
const active_field_ty = ty.unionFieldType(union_obj.tag, mod);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue