stage2: move enum tag values into the InternPool
I'm seeing a new assertion trip: the call to `enumTagFieldIndex` in the implementation of `@Type` is attempting to query the field index of an union's enum tag, but the type of the enum tag value provided is not the same as the union's tag type. Most likely this is a problem with type coercion, since values are now typed. Another problem is that I added some hacks in std.builtin because I didn't see any convenient way to access them from Sema. That should definitely be cleaned up before merging this branch.
This commit is contained in:
@@ -223,6 +223,13 @@ pub const SourceLocation = struct {
|
||||
pub const TypeId = std.meta.Tag(Type);
|
||||
pub const TypeInfo = @compileError("deprecated; use Type");
|
||||
|
||||
/// TODO this is a temporary alias because I don't see any handy methods in
|
||||
/// Sema for accessing inner declarations.
|
||||
pub const PtrSize = Type.Pointer.Size;
|
||||
/// TODO this is a temporary alias because I don't see any handy methods in
|
||||
/// Sema for accessing inner declarations.
|
||||
pub const TmpContainerLayoutAlias = Type.ContainerLayout;
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Type = union(enum) {
|
||||
|
||||
@@ -845,6 +845,7 @@ pub const Inst = struct {
|
||||
|
||||
pub const Ref = enum(u32) {
|
||||
u1_type = @enumToInt(InternPool.Index.u1_type),
|
||||
u5_type = @enumToInt(InternPool.Index.u5_type),
|
||||
u8_type = @enumToInt(InternPool.Index.u8_type),
|
||||
i8_type = @enumToInt(InternPool.Index.i8_type),
|
||||
u16_type = @enumToInt(InternPool.Index.u16_type),
|
||||
@@ -913,6 +914,8 @@ pub const Inst = struct {
|
||||
zero_u8 = @enumToInt(InternPool.Index.zero_u8),
|
||||
one = @enumToInt(InternPool.Index.one),
|
||||
one_usize = @enumToInt(InternPool.Index.one_usize),
|
||||
one_u5 = @enumToInt(InternPool.Index.one_u5),
|
||||
four_u5 = @enumToInt(InternPool.Index.four_u5),
|
||||
negative_one = @enumToInt(InternPool.Index.negative_one),
|
||||
calling_convention_c = @enumToInt(InternPool.Index.calling_convention_c),
|
||||
calling_convention_inline = @enumToInt(InternPool.Index.calling_convention_inline),
|
||||
|
||||
@@ -144,6 +144,9 @@ pub const Key = union(enum) {
|
||||
opaque_type: OpaqueType,
|
||||
enum_type: EnumType,
|
||||
|
||||
/// Typed `undefined`. This will never be `none`; untyped `undefined` is represented
|
||||
/// via `simple_value` and has a named `Index` tag for it.
|
||||
undef: Index,
|
||||
simple_value: SimpleValue,
|
||||
extern_func: struct {
|
||||
ty: Index,
|
||||
@@ -155,13 +158,12 @@ pub const Key = union(enum) {
|
||||
lib_name: u32,
|
||||
},
|
||||
int: Key.Int,
|
||||
/// A specific enum tag, indicated by the integer tag value.
|
||||
enum_tag: Key.EnumTag,
|
||||
float: Key.Float,
|
||||
ptr: Ptr,
|
||||
opt: Opt,
|
||||
enum_tag: struct {
|
||||
ty: Index,
|
||||
tag: BigIntConst,
|
||||
},
|
||||
|
||||
/// An instance of a struct, array, or vector.
|
||||
/// Each element/field stored as an `Index`.
|
||||
/// In the case of sentinel-terminated arrays, the sentinel value *is* stored,
|
||||
@@ -284,21 +286,33 @@ pub const Key = union(enum) {
|
||||
};
|
||||
|
||||
/// Look up field index based on field name.
|
||||
pub fn nameIndex(self: EnumType, ip: InternPool, name: NullTerminatedString) ?usize {
|
||||
pub fn nameIndex(self: EnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
|
||||
const map = &ip.maps.items[@enumToInt(self.names_map.unwrap().?)];
|
||||
const adapter: NullTerminatedString.Adapter = .{ .strings = self.names };
|
||||
return map.getIndexAdapted(name, adapter);
|
||||
const field_index = map.getIndexAdapted(name, adapter) orelse return null;
|
||||
return @intCast(u32, field_index);
|
||||
}
|
||||
|
||||
/// Look up field index based on tag value.
|
||||
/// Asserts that `values_map` is not `none`.
|
||||
/// This function returns `null` when `tag_val` does not have the
|
||||
/// integer tag type of the enum.
|
||||
pub fn tagValueIndex(self: EnumType, ip: InternPool, tag_val: Index) ?usize {
|
||||
pub fn tagValueIndex(self: EnumType, ip: *const InternPool, tag_val: Index) ?u32 {
|
||||
assert(tag_val != .none);
|
||||
const map = &ip.maps.items[@enumToInt(self.values_map.unwrap().?)];
|
||||
const adapter: Index.Adapter = .{ .indexes = self.values };
|
||||
return map.getIndexAdapted(tag_val, adapter);
|
||||
if (self.values_map.unwrap()) |values_map| {
|
||||
const map = &ip.maps.items[@enumToInt(values_map)];
|
||||
const adapter: Index.Adapter = .{ .indexes = self.values };
|
||||
const field_index = map.getIndexAdapted(tag_val, adapter) orelse return null;
|
||||
return @intCast(u32, field_index);
|
||||
}
|
||||
// Auto-numbered enum. Convert `tag_val` to field index.
|
||||
switch (ip.indexToKey(tag_val).int.storage) {
|
||||
.u64 => |x| {
|
||||
if (x >= self.names.len) return null;
|
||||
return @intCast(u32, x);
|
||||
},
|
||||
.i64, .big_int => return null, // out of range
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -362,6 +376,13 @@ pub const Key = union(enum) {
|
||||
};
|
||||
};
|
||||
|
||||
pub const EnumTag = struct {
|
||||
/// The enum type.
|
||||
ty: Index,
|
||||
/// The integer tag value which has the integer tag type of the enum.
|
||||
int: Index,
|
||||
};
|
||||
|
||||
pub const Float = struct {
|
||||
ty: Index,
|
||||
/// The storage used must match the size of the float type being represented.
|
||||
@@ -436,6 +457,8 @@ pub const Key = union(enum) {
|
||||
.struct_type,
|
||||
.union_type,
|
||||
.un,
|
||||
.undef,
|
||||
.enum_tag,
|
||||
=> |info| std.hash.autoHash(hasher, info),
|
||||
|
||||
.opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl),
|
||||
@@ -471,12 +494,6 @@ pub const Key = union(enum) {
|
||||
}
|
||||
},
|
||||
|
||||
.enum_tag => |enum_tag| {
|
||||
std.hash.autoHash(hasher, enum_tag.ty);
|
||||
std.hash.autoHash(hasher, enum_tag.tag.positive);
|
||||
for (enum_tag.tag.limbs) |limb| std.hash.autoHash(hasher, limb);
|
||||
},
|
||||
|
||||
.aggregate => |aggregate| {
|
||||
std.hash.autoHash(hasher, aggregate.ty);
|
||||
for (aggregate.fields) |field| std.hash.autoHash(hasher, field);
|
||||
@@ -522,6 +539,10 @@ pub const Key = union(enum) {
|
||||
const b_info = b.simple_value;
|
||||
return a_info == b_info;
|
||||
},
|
||||
.undef => |a_info| {
|
||||
const b_info = b.undef;
|
||||
return a_info == b_info;
|
||||
},
|
||||
.extern_func => |a_info| {
|
||||
const b_info = b.extern_func;
|
||||
return std.meta.eql(a_info, b_info);
|
||||
@@ -542,6 +563,10 @@ pub const Key = union(enum) {
|
||||
const b_info = b.un;
|
||||
return std.meta.eql(a_info, b_info);
|
||||
},
|
||||
.enum_tag => |a_info| {
|
||||
const b_info = b.enum_tag;
|
||||
return std.meta.eql(a_info, b_info);
|
||||
},
|
||||
|
||||
.ptr => |a_info| {
|
||||
const b_info = b.ptr;
|
||||
@@ -612,13 +637,6 @@ pub const Key = union(enum) {
|
||||
};
|
||||
},
|
||||
|
||||
.enum_tag => |a_info| {
|
||||
const b_info = b.enum_tag;
|
||||
_ = a_info;
|
||||
_ = b_info;
|
||||
@panic("TODO");
|
||||
},
|
||||
|
||||
.opaque_type => |a_info| {
|
||||
const b_info = b.opaque_type;
|
||||
return a_info.decl == b_info.decl;
|
||||
@@ -636,7 +654,7 @@ pub const Key = union(enum) {
|
||||
}
|
||||
|
||||
pub fn typeOf(key: Key) Index {
|
||||
switch (key) {
|
||||
return switch (key) {
|
||||
.int_type,
|
||||
.ptr_type,
|
||||
.array_type,
|
||||
@@ -648,7 +666,7 @@ pub const Key = union(enum) {
|
||||
.union_type,
|
||||
.opaque_type,
|
||||
.enum_type,
|
||||
=> return .type_type,
|
||||
=> .type_type,
|
||||
|
||||
inline .ptr,
|
||||
.int,
|
||||
@@ -658,18 +676,20 @@ pub const Key = union(enum) {
|
||||
.enum_tag,
|
||||
.aggregate,
|
||||
.un,
|
||||
=> |x| return x.ty,
|
||||
=> |x| x.ty,
|
||||
|
||||
.undef => |x| x,
|
||||
|
||||
.simple_value => |s| switch (s) {
|
||||
.undefined => return .undefined_type,
|
||||
.void => return .void_type,
|
||||
.null => return .null_type,
|
||||
.false, .true => return .bool_type,
|
||||
.empty_struct => return .empty_struct_type,
|
||||
.@"unreachable" => return .noreturn_type,
|
||||
.undefined => .undefined_type,
|
||||
.void => .void_type,
|
||||
.null => .null_type,
|
||||
.false, .true => .bool_type,
|
||||
.empty_struct => .empty_struct_type,
|
||||
.@"unreachable" => .noreturn_type,
|
||||
.generic_poison => unreachable,
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -693,6 +713,7 @@ pub const Index = enum(u32) {
|
||||
pub const last_value: Index = .empty_struct;
|
||||
|
||||
u1_type,
|
||||
u5_type,
|
||||
u8_type,
|
||||
i8_type,
|
||||
u16_type,
|
||||
@@ -769,6 +790,10 @@ pub const Index = enum(u32) {
|
||||
one,
|
||||
/// `1` (usize)
|
||||
one_usize,
|
||||
/// `1` (u5)
|
||||
one_u5,
|
||||
/// `4` (u5)
|
||||
four_u5,
|
||||
/// `-1` (comptime_int)
|
||||
negative_one,
|
||||
/// `std.builtin.CallingConvention.C`
|
||||
@@ -834,6 +859,12 @@ pub const static_keys = [_]Key{
|
||||
.bits = 1,
|
||||
} },
|
||||
|
||||
// u5_type
|
||||
.{ .int_type = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = 5,
|
||||
} },
|
||||
|
||||
.{ .int_type = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = 8,
|
||||
@@ -1021,25 +1052,30 @@ pub const static_keys = [_]Key{
|
||||
.storage = .{ .u64 = 1 },
|
||||
} },
|
||||
|
||||
// one_u5
|
||||
.{ .int = .{
|
||||
.ty = .u5_type,
|
||||
.storage = .{ .u64 = 1 },
|
||||
} },
|
||||
// four_u5
|
||||
.{ .int = .{
|
||||
.ty = .u5_type,
|
||||
.storage = .{ .u64 = 4 },
|
||||
} },
|
||||
// negative_one
|
||||
.{ .int = .{
|
||||
.ty = .comptime_int_type,
|
||||
.storage = .{ .i64 = -1 },
|
||||
} },
|
||||
|
||||
// calling_convention_c
|
||||
.{ .enum_tag = .{
|
||||
.ty = .calling_convention_type,
|
||||
.tag = .{
|
||||
.limbs = &.{@enumToInt(std.builtin.CallingConvention.C)},
|
||||
.positive = true,
|
||||
},
|
||||
.int = .one_u5,
|
||||
} },
|
||||
|
||||
// calling_convention_inline
|
||||
.{ .enum_tag = .{
|
||||
.ty = .calling_convention_type,
|
||||
.tag = .{
|
||||
.limbs = &.{@enumToInt(std.builtin.CallingConvention.Inline)},
|
||||
.positive = true,
|
||||
},
|
||||
.int = .four_u5,
|
||||
} },
|
||||
|
||||
.{ .simple_value = .void },
|
||||
@@ -1118,6 +1154,10 @@ pub const Tag = enum(u8) {
|
||||
/// `data` is `Module.Union.Index`.
|
||||
type_union_safety,
|
||||
|
||||
/// Typed `undefined`.
|
||||
/// `data` is `Index` of the type.
|
||||
/// Untyped `undefined` is stored instead via `simple_value`.
|
||||
undef,
|
||||
/// A value that can be represented with only an enum tag.
|
||||
/// data is SimpleValue enum value.
|
||||
simple_value,
|
||||
@@ -1132,7 +1172,7 @@ pub const Tag = enum(u8) {
|
||||
/// already contains the optional type corresponding to this payload.
|
||||
opt_payload,
|
||||
/// An optional value that is null.
|
||||
/// data is Index of the payload type.
|
||||
/// data is Index of the optional type.
|
||||
opt_null,
|
||||
/// Type: u8
|
||||
/// data is integer value
|
||||
@@ -1155,18 +1195,18 @@ pub const Tag = enum(u8) {
|
||||
/// A comptime_int that fits in an i32.
|
||||
/// data is integer value bitcasted to u32.
|
||||
int_comptime_int_i32,
|
||||
/// An integer value that fits in 32 bits with an explicitly provided type.
|
||||
/// data is extra index of `IntSmall`.
|
||||
int_small,
|
||||
/// A positive integer value.
|
||||
/// data is a limbs index to Int.
|
||||
/// data is a limbs index to `Int`.
|
||||
int_positive,
|
||||
/// A negative integer value.
|
||||
/// data is a limbs index to Int.
|
||||
/// data is a limbs index to `Int`.
|
||||
int_negative,
|
||||
/// An enum tag identified by a positive integer value.
|
||||
/// data is a limbs index to Int.
|
||||
enum_tag_positive,
|
||||
/// An enum tag identified by a negative integer value.
|
||||
/// data is a limbs index to Int.
|
||||
enum_tag_negative,
|
||||
/// An enum tag value.
|
||||
/// data is extra index of `Key.EnumTag`.
|
||||
enum_tag,
|
||||
/// An f16 value.
|
||||
/// data is float value bitcasted to u16 and zero-extended.
|
||||
float_f16,
|
||||
@@ -1404,6 +1444,11 @@ pub const Int = struct {
|
||||
limbs_len: u32,
|
||||
};
|
||||
|
||||
pub const IntSmall = struct {
|
||||
ty: Index,
|
||||
value: u32,
|
||||
};
|
||||
|
||||
/// A f64 value, broken up into 2 u32 parts.
|
||||
pub const Float64 = struct {
|
||||
piece0: u32,
|
||||
@@ -1479,15 +1524,28 @@ pub fn init(ip: *InternPool, gpa: Allocator) !void {
|
||||
try ip.items.ensureUnusedCapacity(gpa, static_keys.len);
|
||||
try ip.map.ensureUnusedCapacity(gpa, static_keys.len);
|
||||
try ip.extra.ensureUnusedCapacity(gpa, static_keys.len);
|
||||
try ip.limbs.ensureUnusedCapacity(gpa, 2);
|
||||
|
||||
// This inserts all the statically-known values into the intern pool in the
|
||||
// order expected.
|
||||
for (static_keys) |key| _ = ip.get(gpa, key) catch unreachable;
|
||||
|
||||
// Sanity check.
|
||||
assert(ip.indexToKey(.bool_true).simple_value == .true);
|
||||
assert(ip.indexToKey(.bool_false).simple_value == .false);
|
||||
if (std.debug.runtime_safety) {
|
||||
// Sanity check.
|
||||
assert(ip.indexToKey(.bool_true).simple_value == .true);
|
||||
assert(ip.indexToKey(.bool_false).simple_value == .false);
|
||||
|
||||
const cc_inline = ip.indexToKey(.calling_convention_inline).enum_tag.int;
|
||||
const cc_c = ip.indexToKey(.calling_convention_c).enum_tag.int;
|
||||
|
||||
assert(ip.indexToKey(cc_inline).int.storage.u64 ==
|
||||
@enumToInt(std.builtin.CallingConvention.Inline));
|
||||
|
||||
assert(ip.indexToKey(cc_c).int.storage.u64 ==
|
||||
@enumToInt(std.builtin.CallingConvention.C));
|
||||
|
||||
assert(ip.indexToKey(ip.typeOf(cc_inline)).int_type.bits ==
|
||||
@typeInfo(@typeInfo(std.builtin.CallingConvention).Enum.tag_type).Int.bits);
|
||||
}
|
||||
|
||||
assert(ip.items.len == static_keys.len);
|
||||
}
|
||||
@@ -1634,6 +1692,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||
.type_enum_explicit => indexToKeyEnum(ip, data, .explicit),
|
||||
.type_enum_nonexhaustive => indexToKeyEnum(ip, data, .nonexhaustive),
|
||||
|
||||
.undef => .{ .undef = @intToEnum(Index, data) },
|
||||
.opt_null => .{ .opt = .{
|
||||
.ty = @intToEnum(Index, data),
|
||||
.val = .none,
|
||||
@@ -1687,8 +1746,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||
} },
|
||||
.int_positive => indexToKeyBigInt(ip, data, true),
|
||||
.int_negative => indexToKeyBigInt(ip, data, false),
|
||||
.enum_tag_positive => @panic("TODO"),
|
||||
.enum_tag_negative => @panic("TODO"),
|
||||
.int_small => {
|
||||
const info = ip.extraData(IntSmall, data);
|
||||
return .{ .int = .{
|
||||
.ty = info.ty,
|
||||
.storage = .{ .u64 = info.value },
|
||||
} };
|
||||
},
|
||||
.float_f16 => .{ .float = .{
|
||||
.ty = .f16_type,
|
||||
.storage = .{ .f16 = @bitCast(f16, @intCast(u16, data)) },
|
||||
@@ -1734,6 +1798,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
||||
};
|
||||
},
|
||||
.union_value => .{ .un = ip.extraData(Key.Union, data) },
|
||||
.enum_tag => .{ .enum_tag = ip.extraData(Key.EnumTag, data) },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1896,6 +1961,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
.data = @enumToInt(simple_value),
|
||||
});
|
||||
},
|
||||
.undef => |ty| {
|
||||
assert(ty != .none);
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .undef,
|
||||
.data = @enumToInt(ty),
|
||||
});
|
||||
},
|
||||
|
||||
.struct_type => |struct_type| {
|
||||
ip.items.appendAssumeCapacity(if (struct_type.index.unwrap()) |i| .{
|
||||
@@ -2112,10 +2184,32 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
}
|
||||
switch (int.storage) {
|
||||
.big_int => |big_int| {
|
||||
if (big_int.to(u32)) |casted| {
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .int_small,
|
||||
.data = try ip.addExtra(gpa, IntSmall{
|
||||
.ty = int.ty,
|
||||
.value = casted,
|
||||
}),
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
} else |_| {}
|
||||
|
||||
const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
|
||||
try addInt(ip, gpa, int.ty, tag, big_int.limbs);
|
||||
},
|
||||
inline .i64, .u64 => |x| {
|
||||
inline .u64, .i64 => |x| {
|
||||
if (std.math.cast(u32, x)) |casted| {
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .int_small,
|
||||
.data = try ip.addExtra(gpa, IntSmall{
|
||||
.ty = int.ty,
|
||||
.value = casted,
|
||||
}),
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
}
|
||||
|
||||
var buf: [2]Limb = undefined;
|
||||
const big_int = BigIntMutable.init(&buf, x).toConst();
|
||||
const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
|
||||
@@ -2124,6 +2218,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
}
|
||||
},
|
||||
|
||||
.enum_tag => |enum_tag| {
|
||||
assert(enum_tag.ty != .none);
|
||||
assert(enum_tag.int != .none);
|
||||
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .enum_tag,
|
||||
.data = try ip.addExtra(gpa, enum_tag),
|
||||
});
|
||||
},
|
||||
|
||||
.float => |float| {
|
||||
switch (float.ty) {
|
||||
.f16_type => ip.items.appendAssumeCapacity(.{
|
||||
@@ -2164,11 +2268,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
}
|
||||
},
|
||||
|
||||
.enum_tag => |enum_tag| {
|
||||
const tag: Tag = if (enum_tag.tag.positive) .enum_tag_positive else .enum_tag_negative;
|
||||
try addInt(ip, gpa, enum_tag.ty, tag, enum_tag.tag.limbs);
|
||||
},
|
||||
|
||||
.aggregate => |aggregate| {
|
||||
if (aggregate.fields.len == 0) {
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
@@ -2671,44 +2770,59 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index {
|
||||
|
||||
/// Given an existing value, returns the same value but with the supplied type.
|
||||
/// Only some combinations are allowed:
|
||||
/// * int to int
|
||||
/// * int <=> int
|
||||
/// * int <=> enum
|
||||
pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
|
||||
switch (ip.indexToKey(val)) {
|
||||
.int => |int| {
|
||||
// The key cannot be passed directly to `get`, otherwise in the case of
|
||||
// big_int storage, the limbs would be invalidated before they are read.
|
||||
// Here we pre-reserve the limbs to ensure that the logic in `addInt` will
|
||||
// not use an invalidated limbs pointer.
|
||||
switch (int.storage) {
|
||||
.u64 => |x| return ip.get(gpa, .{ .int = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .u64 = x },
|
||||
} }),
|
||||
.i64 => |x| return ip.get(gpa, .{ .int = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .i64 = x },
|
||||
} }),
|
||||
|
||||
.big_int => |big_int| {
|
||||
const positive = big_int.positive;
|
||||
const limbs = ip.limbsSliceToIndex(big_int.limbs);
|
||||
// This line invalidates the limbs slice, but the indexes computed in the
|
||||
// previous line are still correct.
|
||||
try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len);
|
||||
return ip.get(gpa, .{ .int = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .big_int = .{
|
||||
.limbs = ip.limbsIndexToSlice(limbs),
|
||||
.positive = positive,
|
||||
} },
|
||||
} });
|
||||
},
|
||||
}
|
||||
.int => |int| switch (ip.indexToKey(new_ty)) {
|
||||
.enum_type => return ip.get(gpa, .{ .enum_tag = .{
|
||||
.ty = new_ty,
|
||||
.int = val,
|
||||
} }),
|
||||
else => return getCoercedInts(ip, gpa, int, new_ty),
|
||||
},
|
||||
.enum_tag => |enum_tag| {
|
||||
// Assume new_ty is an integer type.
|
||||
return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts `val` has an integer type.
|
||||
/// Assumes `new_ty` is an integer type.
|
||||
pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Index) Allocator.Error!Index {
|
||||
// The key cannot be passed directly to `get`, otherwise in the case of
|
||||
// big_int storage, the limbs would be invalidated before they are read.
|
||||
// Here we pre-reserve the limbs to ensure that the logic in `addInt` will
|
||||
// not use an invalidated limbs pointer.
|
||||
switch (int.storage) {
|
||||
.u64 => |x| return ip.get(gpa, .{ .int = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .u64 = x },
|
||||
} }),
|
||||
.i64 => |x| return ip.get(gpa, .{ .int = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .i64 = x },
|
||||
} }),
|
||||
|
||||
.big_int => |big_int| {
|
||||
const positive = big_int.positive;
|
||||
const limbs = ip.limbsSliceToIndex(big_int.limbs);
|
||||
// This line invalidates the limbs slice, but the indexes computed in the
|
||||
// previous line are still correct.
|
||||
try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len);
|
||||
return ip.get(gpa, .{ .int = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .big_int = .{
|
||||
.limbs = ip.limbsIndexToSlice(limbs),
|
||||
.positive = positive,
|
||||
} },
|
||||
} });
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indexToStruct(ip: *InternPool, val: Index) Module.Struct.OptionalIndex {
|
||||
const tags = ip.items.items(.tag);
|
||||
if (val == .none) return .none;
|
||||
@@ -2805,6 +2919,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||
.type_union_safety,
|
||||
=> @sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl),
|
||||
|
||||
.undef => 0,
|
||||
.simple_type => 0,
|
||||
.simple_value => 0,
|
||||
.ptr_int => @sizeOf(PtrInt),
|
||||
@@ -2817,15 +2932,15 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||
.int_usize => 0,
|
||||
.int_comptime_int_u32 => 0,
|
||||
.int_comptime_int_i32 => 0,
|
||||
.int_small => @sizeOf(IntSmall),
|
||||
|
||||
.int_positive,
|
||||
.int_negative,
|
||||
.enum_tag_positive,
|
||||
.enum_tag_negative,
|
||||
=> b: {
|
||||
const int = ip.limbData(Int, data);
|
||||
break :b @sizeOf(Int) + int.limbs_len * 8;
|
||||
},
|
||||
.enum_tag => @sizeOf(Key.EnumTag),
|
||||
|
||||
.float_f16 => 0,
|
||||
.float_f32 => 0,
|
||||
@@ -2958,3 +3073,9 @@ pub fn stringToSlice(ip: InternPool, s: NullTerminatedString) [:0]const u8 {
|
||||
pub fn typeOf(ip: InternPool, index: Index) Index {
|
||||
return ip.indexToKey(index).typeOf();
|
||||
}
|
||||
|
||||
/// Assumes that the enum's field indexes equal its value tags.
|
||||
pub fn toEnum(ip: InternPool, comptime E: type, i: Index) E {
|
||||
const int = ip.indexToKey(i).enum_tag.int;
|
||||
return @intToEnum(E, ip.indexToKey(int).int.storage.u64);
|
||||
}
|
||||
|
||||
@@ -6896,6 +6896,43 @@ pub fn ptrIntValue_ptronly(mod: *Module, ty: Type, x: u64) Allocator.Error!Value
|
||||
return i.toValue();
|
||||
}
|
||||
|
||||
/// Creates an enum tag value based on the integer tag value.
|
||||
pub fn enumValue(mod: *Module, ty: Type, tag_int: InternPool.Index) Allocator.Error!Value {
|
||||
if (std.debug.runtime_safety) {
|
||||
const tag = ty.zigTypeTag(mod);
|
||||
assert(tag == .Enum);
|
||||
}
|
||||
const i = try intern(mod, .{ .enum_tag = .{
|
||||
.ty = ty.ip_index,
|
||||
.int = tag_int,
|
||||
} });
|
||||
return i.toValue();
|
||||
}
|
||||
|
||||
/// Creates an enum tag value based on the field index according to source code
|
||||
/// declaration order.
|
||||
pub fn enumValueFieldIndex(mod: *Module, ty: Type, field_index: u32) Allocator.Error!Value {
|
||||
const ip = &mod.intern_pool;
|
||||
const gpa = mod.gpa;
|
||||
const enum_type = ip.indexToKey(ty.ip_index).enum_type;
|
||||
|
||||
if (enum_type.values.len == 0) {
|
||||
// Auto-numbered fields.
|
||||
return (try ip.get(gpa, .{ .enum_tag = .{
|
||||
.ty = ty.ip_index,
|
||||
.int = try ip.get(gpa, .{ .int = .{
|
||||
.ty = enum_type.tag_ty,
|
||||
.storage = .{ .u64 = field_index },
|
||||
} }),
|
||||
} })).toValue();
|
||||
}
|
||||
|
||||
return (try ip.get(gpa, .{ .enum_tag = .{
|
||||
.ty = ty.ip_index,
|
||||
.int = enum_type.values[field_index],
|
||||
} })).toValue();
|
||||
}
|
||||
|
||||
pub fn intValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value {
|
||||
if (std.debug.runtime_safety) {
|
||||
const tag = ty.zigTypeTag(mod);
|
||||
@@ -6967,8 +7004,8 @@ pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type {
|
||||
/// `max`. Asserts that neither value is undef.
|
||||
/// TODO: if #3806 is implemented, this becomes trivial
|
||||
pub fn intFittingRange(mod: *Module, min: Value, max: Value) !Type {
|
||||
assert(!min.isUndef());
|
||||
assert(!max.isUndef());
|
||||
assert(!min.isUndef(mod));
|
||||
assert(!max.isUndef(mod));
|
||||
|
||||
if (std.debug.runtime_safety) {
|
||||
assert(Value.order(min, max, mod).compare(.lte));
|
||||
@@ -6990,7 +7027,7 @@ pub fn intFittingRange(mod: *Module, min: Value, max: Value) !Type {
|
||||
/// twos-complement integer; otherwise in an unsigned integer.
|
||||
/// Asserts that `val` is not undef. If `val` is negative, asserts that `sign` is true.
|
||||
pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
|
||||
assert(!val.isUndef());
|
||||
assert(!val.isUndef(mod));
|
||||
|
||||
const key = mod.intern_pool.indexToKey(val.ip_index);
|
||||
switch (key.int.storage) {
|
||||
@@ -7193,3 +7230,7 @@ pub fn fieldSrcLoc(mod: *Module, owner_decl_index: Decl.Index, query: FieldSrcQu
|
||||
return owner_decl.srcLoc(mod);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toEnum(mod: *Module, comptime E: type, val: Value) E {
|
||||
return mod.intern_pool.toEnum(E, val.ip_index);
|
||||
}
|
||||
|
||||
487
src/Sema.zig
487
src/Sema.zig
File diff suppressed because it is too large
Load Diff
@@ -197,9 +197,6 @@ pub fn print(
|
||||
},
|
||||
.empty_array => return writer.writeAll(".{}"),
|
||||
.enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
|
||||
.enum_field_index => {
|
||||
return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data, mod)});
|
||||
},
|
||||
.bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
|
||||
.str_lit => {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
@@ -255,7 +252,7 @@ pub fn print(
|
||||
const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) {
|
||||
error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic
|
||||
};
|
||||
if (elem_val.isUndef()) break :str;
|
||||
if (elem_val.isUndef(mod)) break :str;
|
||||
buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str;
|
||||
}
|
||||
|
||||
@@ -358,6 +355,20 @@ pub fn print(
|
||||
.int => |int| switch (int.storage) {
|
||||
inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}),
|
||||
},
|
||||
.enum_tag => |enum_tag| {
|
||||
try writer.writeAll("@intToEnum(");
|
||||
try print(.{
|
||||
.ty = Type.type,
|
||||
.val = enum_tag.ty.toValue(),
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(", ");
|
||||
try print(.{
|
||||
.ty = mod.intern_pool.typeOf(enum_tag.int).toType(),
|
||||
.val = enum_tag.int.toValue(),
|
||||
}, writer, level - 1, mod);
|
||||
try writer.writeAll(")");
|
||||
return;
|
||||
},
|
||||
.float => |float| switch (float.storage) {
|
||||
inline else => |x| return writer.print("{}", .{x}),
|
||||
},
|
||||
@@ -414,7 +425,7 @@ fn printAggregate(
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
const elem = try val.fieldValue(ty, mod, i);
|
||||
if (elem.isUndef()) break :str;
|
||||
if (elem.isUndef(mod)) break :str;
|
||||
buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str;
|
||||
}
|
||||
|
||||
|
||||
@@ -2052,6 +2052,7 @@ pub const Inst = struct {
|
||||
/// and `[]Ref`.
|
||||
pub const Ref = enum(u32) {
|
||||
u1_type = @enumToInt(InternPool.Index.u1_type),
|
||||
u5_type = @enumToInt(InternPool.Index.u5_type),
|
||||
u8_type = @enumToInt(InternPool.Index.u8_type),
|
||||
i8_type = @enumToInt(InternPool.Index.i8_type),
|
||||
u16_type = @enumToInt(InternPool.Index.u16_type),
|
||||
@@ -2120,6 +2121,8 @@ pub const Inst = struct {
|
||||
zero_u8 = @enumToInt(InternPool.Index.zero_u8),
|
||||
one = @enumToInt(InternPool.Index.one),
|
||||
one_usize = @enumToInt(InternPool.Index.one_usize),
|
||||
one_u5 = @enumToInt(InternPool.Index.one_u5),
|
||||
four_u5 = @enumToInt(InternPool.Index.four_u5),
|
||||
negative_one = @enumToInt(InternPool.Index.negative_one),
|
||||
calling_convention_c = @enumToInt(InternPool.Index.calling_convention_c),
|
||||
calling_convention_inline = @enumToInt(InternPool.Index.calling_convention_inline),
|
||||
|
||||
@@ -11,6 +11,7 @@ const log = std.log.scoped(.codegen);
|
||||
|
||||
const codegen = @import("../../codegen.zig");
|
||||
const Module = @import("../../Module.zig");
|
||||
const InternPool = @import("../../InternPool.zig");
|
||||
const Decl = Module.Decl;
|
||||
const Type = @import("../../type.zig").Type;
|
||||
const Value = @import("../../value.zig").Value;
|
||||
@@ -3044,11 +3045,12 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo(
|
||||
}
|
||||
|
||||
fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
||||
const mod = func.bin_file.base.options.module.?;
|
||||
var val = arg_val;
|
||||
if (val.castTag(.runtime_value)) |rt| {
|
||||
val = rt.data;
|
||||
}
|
||||
if (val.isUndefDeep()) return func.emitUndefined(ty);
|
||||
if (val.isUndefDeep(mod)) return func.emitUndefined(ty);
|
||||
if (val.castTag(.decl_ref)) |decl_ref| {
|
||||
const decl_index = decl_ref.data;
|
||||
return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0);
|
||||
@@ -3057,7 +3059,6 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
||||
const decl_index = decl_ref_mut.data.decl_index;
|
||||
return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0);
|
||||
}
|
||||
const mod = func.bin_file.base.options.module.?;
|
||||
switch (ty.zigTypeTag(mod)) {
|
||||
.Void => return WValue{ .none = {} },
|
||||
.Int => {
|
||||
@@ -3100,18 +3101,9 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
||||
},
|
||||
},
|
||||
.Enum => {
|
||||
if (val.castTag(.enum_field_index)) |field_index| {
|
||||
const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
|
||||
if (enum_type.values.len != 0) {
|
||||
const tag_val = enum_type.values[field_index.data];
|
||||
return func.lowerConstant(tag_val.toValue(), enum_type.tag_ty.toType());
|
||||
} else {
|
||||
return WValue{ .imm32 = field_index.data };
|
||||
}
|
||||
} else {
|
||||
const int_tag_ty = try ty.intTagType(mod);
|
||||
return func.lowerConstant(val, int_tag_ty);
|
||||
}
|
||||
const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag;
|
||||
const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);
|
||||
return func.lowerConstant(enum_tag.int.toValue(), int_tag_ty.toType());
|
||||
},
|
||||
.ErrorSet => switch (val.tag()) {
|
||||
.@"error" => {
|
||||
@@ -3223,37 +3215,42 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue {
|
||||
/// Returns a `Value` as a signed 32 bit value.
|
||||
/// It's illegal to provide a value with a type that cannot be represented
|
||||
/// as an integer value.
|
||||
fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) !i32 {
|
||||
fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 {
|
||||
const mod = func.bin_file.base.options.module.?;
|
||||
|
||||
switch (val.ip_index) {
|
||||
.none => {},
|
||||
.bool_true => return 1,
|
||||
.bool_false => return 0,
|
||||
else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
.enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int),
|
||||
.int => |int| intStorageAsI32(int.storage),
|
||||
.ptr => |ptr| intIndexAsI32(&mod.intern_pool, ptr.addr.int),
|
||||
else => unreachable,
|
||||
},
|
||||
}
|
||||
|
||||
switch (ty.zigTypeTag(mod)) {
|
||||
.Enum => {
|
||||
if (val.castTag(.enum_field_index)) |field_index| {
|
||||
const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
|
||||
if (enum_type.values.len != 0) {
|
||||
const tag_val = enum_type.values[field_index.data];
|
||||
return func.valueAsI32(tag_val.toValue(), enum_type.tag_ty.toType());
|
||||
} else {
|
||||
return @bitCast(i32, field_index.data);
|
||||
}
|
||||
} else {
|
||||
const int_tag_ty = try ty.intTagType(mod);
|
||||
return func.valueAsI32(val, int_tag_ty);
|
||||
}
|
||||
},
|
||||
.Int => switch (ty.intInfo(mod).signedness) {
|
||||
.signed => return @truncate(i32, val.toSignedInt(mod)),
|
||||
.unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(mod))),
|
||||
},
|
||||
.ErrorSet => {
|
||||
const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
|
||||
return @bitCast(i32, kv.value);
|
||||
},
|
||||
.Bool => return @intCast(i32, val.toSignedInt(mod)),
|
||||
.Pointer => return @intCast(i32, val.toSignedInt(mod)),
|
||||
else => unreachable, // Programmer called this function for an illegal type
|
||||
}
|
||||
}
|
||||
|
||||
fn intIndexAsI32(ip: *const InternPool, int: InternPool.Index) i32 {
|
||||
return intStorageAsI32(ip.indexToKey(int).int.storage);
|
||||
}
|
||||
|
||||
fn intStorageAsI32(storage: InternPool.Key.Int.Storage) i32 {
|
||||
return switch (storage) {
|
||||
.i64 => |x| @intCast(i32, x),
|
||||
.u64 => |x| @bitCast(i32, @intCast(u32, x)),
|
||||
.big_int => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
const mod = func.bin_file.base.options.module.?;
|
||||
const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
|
||||
@@ -3772,7 +3769,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
for (items, 0..) |ref, i| {
|
||||
const item_val = (try func.air.value(ref, mod)).?;
|
||||
const int_val = try func.valueAsI32(item_val, target_ty);
|
||||
const int_val = func.valueAsI32(item_val, target_ty);
|
||||
if (lowest_maybe == null or int_val < lowest_maybe.?) {
|
||||
lowest_maybe = int_val;
|
||||
}
|
||||
@@ -5071,12 +5068,8 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||
|
||||
const tag_int = blk: {
|
||||
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
|
||||
const enum_field_index = tag_ty.enumFieldIndex(field_name).?;
|
||||
var tag_val_payload: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, enum_field_index),
|
||||
};
|
||||
const tag_val = Value.initPayload(&tag_val_payload.base);
|
||||
const enum_field_index = tag_ty.enumFieldIndex(field_name, mod).?;
|
||||
const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
|
||||
break :blk try func.lowerConstant(tag_val, tag_ty);
|
||||
};
|
||||
if (layout.payload_size == 0) {
|
||||
@@ -6815,7 +6808,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
|
||||
|
||||
// TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse.
|
||||
// generate an if-else chain for each tag value as well as constant.
|
||||
for (enum_ty.enumFields(mod), 0..) |tag_name_ip, field_index| {
|
||||
for (enum_ty.enumFields(mod), 0..) |tag_name_ip, field_index_usize| {
|
||||
const field_index = @intCast(u32, field_index_usize);
|
||||
const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
|
||||
// for each tag name, create an unnamed const,
|
||||
// and then get a pointer to its value.
|
||||
@@ -6857,11 +6851,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
|
||||
try writer.writeByte(std.wasm.opcode(.local_get));
|
||||
try leb.writeULEB128(writer, @as(u32, 1));
|
||||
|
||||
var tag_val_payload: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, field_index),
|
||||
};
|
||||
const tag_value = try func.lowerConstant(Value.initPayload(&tag_val_payload.base), enum_ty);
|
||||
const tag_val = try mod.enumValueFieldIndex(enum_ty, field_index);
|
||||
const tag_value = try func.lowerConstant(tag_val, enum_ty);
|
||||
|
||||
switch (tag_value) {
|
||||
.imm32 => |value| {
|
||||
|
||||
@@ -2029,13 +2029,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
|
||||
exitlude_jump_relocs,
|
||||
enum_ty.enumFields(mod),
|
||||
0..,
|
||||
) |*exitlude_jump_reloc, tag_name_ip, index| {
|
||||
) |*exitlude_jump_reloc, tag_name_ip, index_usize| {
|
||||
const index = @intCast(u32, index_usize);
|
||||
const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
|
||||
var tag_pl = Value.Payload.U32{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, index),
|
||||
};
|
||||
const tag_val = Value.initPayload(&tag_pl.base);
|
||||
const tag_val = try mod.enumValueFieldIndex(enum_ty, index);
|
||||
const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val });
|
||||
try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv);
|
||||
const skip_reloc = try self.asmJccReloc(undefined, .ne);
|
||||
@@ -11415,8 +11412,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const field_name = union_obj.fields.keys()[extra.field_index];
|
||||
const tag_ty = union_obj.tag_ty;
|
||||
const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
|
||||
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 = try mod.enumValueFieldIndex(tag_ty, field_index);
|
||||
const tag_int_val = try tag_val.enumToInt(tag_ty, mod);
|
||||
const tag_int = tag_int_val.toUnsignedInt(mod);
|
||||
const tag_off = if (layout.tag_align < layout.payload_align)
|
||||
|
||||
@@ -196,7 +196,7 @@ pub fn generateSymbol(
|
||||
typed_value.val.fmtValue(typed_value.ty, mod),
|
||||
});
|
||||
|
||||
if (typed_value.val.isUndefDeep()) {
|
||||
if (typed_value.val.isUndefDeep(mod)) {
|
||||
const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow;
|
||||
try code.appendNTimes(0xaa, abi_size);
|
||||
return Result.ok;
|
||||
@@ -1168,7 +1168,7 @@ pub fn genTypedValue(
|
||||
typed_value.val.fmtValue(typed_value.ty, mod),
|
||||
});
|
||||
|
||||
if (typed_value.val.isUndef())
|
||||
if (typed_value.val.isUndef(mod))
|
||||
return GenResult.mcv(.undef);
|
||||
|
||||
const target = bin_file.options.target;
|
||||
@@ -1229,24 +1229,12 @@ pub fn genTypedValue(
|
||||
}
|
||||
},
|
||||
.Enum => {
|
||||
if (typed_value.val.castTag(.enum_field_index)) |field_index| {
|
||||
const enum_type = mod.intern_pool.indexToKey(typed_value.ty.ip_index).enum_type;
|
||||
if (enum_type.values.len != 0) {
|
||||
const tag_val = enum_type.values[field_index.data];
|
||||
return genTypedValue(bin_file, src_loc, .{
|
||||
.ty = enum_type.tag_ty.toType(),
|
||||
.val = tag_val.toValue(),
|
||||
}, owner_decl_index);
|
||||
} else {
|
||||
return GenResult.mcv(.{ .immediate = field_index.data });
|
||||
}
|
||||
} else {
|
||||
const int_tag_ty = try typed_value.ty.intTagType(mod);
|
||||
return genTypedValue(bin_file, src_loc, .{
|
||||
.ty = int_tag_ty,
|
||||
.val = typed_value.val,
|
||||
}, owner_decl_index);
|
||||
}
|
||||
const enum_tag = mod.intern_pool.indexToKey(typed_value.val.ip_index).enum_tag;
|
||||
const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);
|
||||
return genTypedValue(bin_file, src_loc, .{
|
||||
.ty = int_tag_ty.toType(),
|
||||
.val = enum_tag.int.toValue(),
|
||||
}, owner_decl_index);
|
||||
},
|
||||
.ErrorSet => {
|
||||
switch (typed_value.val.tag()) {
|
||||
|
||||
@@ -748,7 +748,7 @@ pub const DeclGen = struct {
|
||||
.ReleaseFast, .ReleaseSmall => false,
|
||||
};
|
||||
|
||||
if (val.isUndefDeep()) {
|
||||
if (val.isUndefDeep(mod)) {
|
||||
switch (ty.zigTypeTag(mod)) {
|
||||
.Bool => {
|
||||
if (safety_on) {
|
||||
@@ -1183,7 +1183,7 @@ pub const DeclGen = struct {
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
const elem_val = try val.elemValue(mod, index);
|
||||
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
try literal.writeChar(elem_val_u8);
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
@@ -1197,7 +1197,7 @@ pub const DeclGen = struct {
|
||||
while (index < ai.len) : (index += 1) {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
const elem_val = try val.elemValue(mod, index);
|
||||
const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod));
|
||||
try writer.print("'\\x{x}'", .{elem_val_u8});
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
@@ -1284,23 +1284,16 @@ pub const DeclGen = struct {
|
||||
try dg.renderValue(writer, error_ty, error_val, initializer_type);
|
||||
try writer.writeAll(" }");
|
||||
},
|
||||
.Enum => {
|
||||
switch (val.tag()) {
|
||||
.enum_field_index => {
|
||||
const field_index = val.castTag(.enum_field_index).?.data;
|
||||
const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
|
||||
if (enum_type.values.len != 0) {
|
||||
const tag_val = enum_type.values[field_index];
|
||||
return dg.renderValue(writer, enum_type.tag_ty.toType(), tag_val.toValue(), location);
|
||||
} else {
|
||||
return writer.print("{d}", .{field_index});
|
||||
}
|
||||
},
|
||||
else => {
|
||||
const int_tag_ty = try ty.intTagType(mod);
|
||||
return dg.renderValue(writer, int_tag_ty, val, location);
|
||||
},
|
||||
}
|
||||
.Enum => switch (val.ip_index) {
|
||||
.none => {
|
||||
const int_tag_ty = try ty.intTagType(mod);
|
||||
return dg.renderValue(writer, int_tag_ty, val, location);
|
||||
},
|
||||
else => {
|
||||
const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag;
|
||||
const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);
|
||||
return dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location);
|
||||
},
|
||||
},
|
||||
.Fn => switch (val.tag()) {
|
||||
.function => {
|
||||
@@ -2524,13 +2517,10 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
|
||||
try w.writeByte('(');
|
||||
try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);
|
||||
try w.writeAll(") {\n switch (tag) {\n");
|
||||
for (enum_ty.enumFields(mod), 0..) |name_ip, index| {
|
||||
for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| {
|
||||
const index = @intCast(u32, index_usize);
|
||||
const name = mod.intern_pool.stringToSlice(name_ip);
|
||||
var tag_pl: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, index),
|
||||
};
|
||||
const tag_val = Value.initPayload(&tag_pl.base);
|
||||
const tag_val = try mod.enumValueFieldIndex(enum_ty, index);
|
||||
|
||||
const int_val = try tag_val.enumToInt(enum_ty, mod);
|
||||
|
||||
@@ -3609,7 +3599,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
|
||||
const ptr_val = try f.resolveInst(bin_op.lhs);
|
||||
const src_ty = f.typeOf(bin_op.rhs);
|
||||
|
||||
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |v| v.isUndefDeep() else false;
|
||||
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |v| v.isUndefDeep(mod) else false;
|
||||
|
||||
if (val_is_undef) {
|
||||
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
|
||||
@@ -4267,7 +4257,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
const mod = f.object.dg.module;
|
||||
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
|
||||
const name = f.air.nullTerminatedString(pl_op.payload);
|
||||
const operand_is_undef = if (try f.air.value(pl_op.operand, mod)) |v| v.isUndefDeep() else false;
|
||||
const operand_is_undef = if (try f.air.value(pl_op.operand, mod)) |v| v.isUndefDeep(mod) else false;
|
||||
if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand);
|
||||
|
||||
try reap(f, inst, &.{pl_op.operand});
|
||||
@@ -6290,7 +6280,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
|
||||
const value = try f.resolveInst(bin_op.rhs);
|
||||
const elem_ty = f.typeOf(bin_op.rhs);
|
||||
const elem_abi_size = elem_ty.abiSize(mod);
|
||||
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep() else false;
|
||||
const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false;
|
||||
const writer = f.object.writer();
|
||||
|
||||
if (val_is_undef) {
|
||||
@@ -6907,11 +6897,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
if (layout.tag_size != 0) {
|
||||
const field_index = tag_ty.enumFieldIndex(field_name, mod).?;
|
||||
|
||||
var tag_pl: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, field_index),
|
||||
};
|
||||
const tag_val = Value.initPayload(&tag_pl.base);
|
||||
const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
|
||||
|
||||
const int_val = try tag_val.enumToInt(tag_ty, mod);
|
||||
|
||||
@@ -7438,7 +7424,7 @@ fn formatIntLiteral(
|
||||
defer allocator.free(undef_limbs);
|
||||
|
||||
var int_buf: Value.BigIntSpace = undefined;
|
||||
const int = if (data.val.isUndefDeep()) blk: {
|
||||
const int = if (data.val.isUndefDeep(mod)) blk: {
|
||||
undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits));
|
||||
@memset(undef_limbs, undefPattern(BigIntLimb));
|
||||
|
||||
|
||||
@@ -3233,16 +3233,16 @@ pub const DeclGen = struct {
|
||||
}
|
||||
|
||||
fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value {
|
||||
const mod = dg.module;
|
||||
const target = mod.getTarget();
|
||||
var tv = arg_tv;
|
||||
if (tv.val.castTag(.runtime_value)) |rt| {
|
||||
tv.val = rt.data;
|
||||
}
|
||||
if (tv.val.isUndef()) {
|
||||
if (tv.val.isUndef(mod)) {
|
||||
const llvm_type = try dg.lowerType(tv.ty);
|
||||
return llvm_type.getUndef();
|
||||
}
|
||||
const mod = dg.module;
|
||||
const target = mod.getTarget();
|
||||
switch (tv.ty.zigTypeTag(mod)) {
|
||||
.Bool => {
|
||||
const llvm_type = try dg.lowerType(tv.ty);
|
||||
@@ -8204,7 +8204,7 @@ pub const FuncGen = struct {
|
||||
const ptr_ty = self.typeOf(bin_op.lhs);
|
||||
const operand_ty = ptr_ty.childType(mod);
|
||||
|
||||
const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep() else false;
|
||||
const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false;
|
||||
if (val_is_undef) {
|
||||
// Even if safety is disabled, we still emit a memset to undefined since it conveys
|
||||
// extra information to LLVM. However, safety makes the difference between using
|
||||
@@ -8496,7 +8496,7 @@ pub const FuncGen = struct {
|
||||
const is_volatile = ptr_ty.isVolatilePtr(mod);
|
||||
|
||||
if (try self.air.value(bin_op.rhs, mod)) |elem_val| {
|
||||
if (elem_val.isUndefDeep()) {
|
||||
if (elem_val.isUndefDeep(mod)) {
|
||||
// Even if safety is disabled, we still emit a memset to undefined since it conveys
|
||||
// extra information to LLVM. However, safety makes the difference between using
|
||||
// 0xaa or actual undefined for the fill byte.
|
||||
@@ -8890,15 +8890,12 @@ pub const FuncGen = struct {
|
||||
const tag_int_value = fn_val.getParam(0);
|
||||
const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, enum_type.names.len));
|
||||
|
||||
for (enum_type.names, 0..) |_, field_index| {
|
||||
for (enum_type.names, 0..) |_, field_index_usize| {
|
||||
const field_index = @intCast(u32, field_index_usize);
|
||||
const this_tag_int_value = int: {
|
||||
var tag_val_payload: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, field_index),
|
||||
};
|
||||
break :int try self.dg.lowerValue(.{
|
||||
.ty = enum_ty,
|
||||
.val = Value.initPayload(&tag_val_payload.base),
|
||||
.val = try mod.enumValueFieldIndex(enum_ty, field_index),
|
||||
});
|
||||
};
|
||||
switch_instr.addCase(this_tag_int_value, named_block);
|
||||
@@ -8973,7 +8970,8 @@ pub const FuncGen = struct {
|
||||
usize_llvm_ty.constNull(), usize_llvm_ty.constNull(),
|
||||
};
|
||||
|
||||
for (enum_type.names, 0..) |name_ip, field_index| {
|
||||
for (enum_type.names, 0..) |name_ip, field_index_usize| {
|
||||
const field_index = @intCast(u32, field_index_usize);
|
||||
const name = mod.intern_pool.stringToSlice(name_ip);
|
||||
const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False);
|
||||
const str_init_llvm_ty = str_init.typeOf();
|
||||
@@ -8997,16 +8995,10 @@ pub const FuncGen = struct {
|
||||
slice_global.setAlignment(slice_alignment);
|
||||
|
||||
const return_block = self.context.appendBasicBlock(fn_val, "Name");
|
||||
const this_tag_int_value = int: {
|
||||
var tag_val_payload: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, field_index),
|
||||
};
|
||||
break :int try self.dg.lowerValue(.{
|
||||
.ty = enum_ty,
|
||||
.val = Value.initPayload(&tag_val_payload.base),
|
||||
});
|
||||
};
|
||||
const this_tag_int_value = try self.dg.lowerValue(.{
|
||||
.ty = enum_ty,
|
||||
.val = try mod.enumValueFieldIndex(enum_ty, field_index),
|
||||
});
|
||||
switch_instr.addCase(this_tag_int_value, return_block);
|
||||
|
||||
self.builder.positionBuilderAtEnd(return_block);
|
||||
@@ -9094,7 +9086,7 @@ pub const FuncGen = struct {
|
||||
|
||||
for (values, 0..) |*val, i| {
|
||||
const elem = try mask.elemValue(mod, i);
|
||||
if (elem.isUndef()) {
|
||||
if (elem.isUndef(mod)) {
|
||||
val.* = llvm_i32.getUndef();
|
||||
} else {
|
||||
const int = elem.toSignedInt(mod);
|
||||
@@ -9419,11 +9411,7 @@ pub const FuncGen = struct {
|
||||
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
|
||||
const union_field_name = union_obj.fields.keys()[extra.field_index];
|
||||
const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?;
|
||||
var tag_val_payload: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, enum_field_index),
|
||||
};
|
||||
const tag_val = Value.initPayload(&tag_val_payload.base);
|
||||
const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
|
||||
const tag_int_val = try tag_val.enumToInt(tag_ty, mod);
|
||||
break :blk tag_int_val.toUnsignedInt(mod);
|
||||
};
|
||||
|
||||
@@ -614,7 +614,7 @@ pub const DeclGen = struct {
|
||||
const dg = self.dg;
|
||||
const mod = dg.module;
|
||||
|
||||
if (val.isUndef()) {
|
||||
if (val.isUndef(mod)) {
|
||||
const size = ty.abiSize(mod);
|
||||
return try self.addUndef(size);
|
||||
}
|
||||
@@ -882,7 +882,7 @@ pub const DeclGen = struct {
|
||||
// const target = self.getTarget();
|
||||
|
||||
// TODO: Fix the resulting global linking for these paths.
|
||||
// if (val.isUndef()) {
|
||||
// if (val.isUndef(mod)) {
|
||||
// // Special case: the entire value is undefined. In this case, we can just
|
||||
// // generate an OpVariable with no initializer.
|
||||
// return try section.emit(self.spv.gpa, .OpVariable, .{
|
||||
@@ -978,7 +978,7 @@ pub const DeclGen = struct {
|
||||
|
||||
log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
|
||||
|
||||
if (val.isUndef()) {
|
||||
if (val.isUndef(mod)) {
|
||||
return self.spv.constUndef(result_ty_ref);
|
||||
}
|
||||
|
||||
@@ -2091,7 +2091,7 @@ pub const DeclGen = struct {
|
||||
var i: usize = 0;
|
||||
while (i < mask_len) : (i += 1) {
|
||||
const elem = try mask.elemValue(self.module, i);
|
||||
if (elem.isUndef()) {
|
||||
if (elem.isUndef(mod)) {
|
||||
self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF);
|
||||
} else {
|
||||
const int = elem.toSignedInt(mod);
|
||||
|
||||
@@ -1304,7 +1304,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 {
|
||||
const zig_ty = ty.zigTypeTag(mod);
|
||||
const val = decl.val;
|
||||
const index: u16 = blk: {
|
||||
if (val.isUndefDeep()) {
|
||||
if (val.isUndefDeep(mod)) {
|
||||
// TODO in release-fast and release-small, we should put undef in .bss
|
||||
break :blk self.data_section_index.?;
|
||||
}
|
||||
|
||||
@@ -2456,7 +2456,7 @@ fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 {
|
||||
const zig_ty = ty.zigTypeTag(mod);
|
||||
const val = decl.val;
|
||||
const shdr_index: u16 = blk: {
|
||||
if (val.isUndefDeep()) {
|
||||
if (val.isUndefDeep(mod)) {
|
||||
// TODO in release-fast and release-small, we should put undef in .bss
|
||||
break :blk self.data_section_index.?;
|
||||
}
|
||||
|
||||
@@ -2270,7 +2270,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 {
|
||||
const single_threaded = self.base.options.single_threaded;
|
||||
const sect_id: u8 = blk: {
|
||||
// TODO finish and audit this function
|
||||
if (val.isUndefDeep()) {
|
||||
if (val.isUndefDeep(mod)) {
|
||||
if (mode == .ReleaseFast or mode == .ReleaseSmall) {
|
||||
@panic("TODO __DATA,__bss");
|
||||
} else {
|
||||
|
||||
@@ -3374,7 +3374,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
} else if (decl.getVariable()) |variable| {
|
||||
if (!variable.is_mutable) {
|
||||
try wasm.parseAtom(atom_index, .{ .data = .read_only });
|
||||
} else if (variable.init.isUndefDeep()) {
|
||||
} else if (variable.init.isUndefDeep(mod)) {
|
||||
// for safe build modes, we store the atom in the data segment,
|
||||
// whereas for unsafe build modes we store it in bss.
|
||||
const is_initialized = wasm.base.options.optimize_mode == .Debug or
|
||||
|
||||
59
src/type.zig
59
src/type.zig
@@ -126,6 +126,7 @@ pub const Type = struct {
|
||||
},
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.extern_func => unreachable,
|
||||
.int => unreachable,
|
||||
@@ -1350,6 +1351,7 @@ pub const Type = struct {
|
||||
},
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -1600,6 +1602,7 @@ pub const Type = struct {
|
||||
.enum_type => |enum_type| enum_type.tag_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -1713,6 +1716,7 @@ pub const Type = struct {
|
||||
},
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -2104,6 +2108,7 @@ pub const Type = struct {
|
||||
.enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) },
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -2499,6 +2504,7 @@ pub const Type = struct {
|
||||
.enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) },
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -2736,6 +2742,7 @@ pub const Type = struct {
|
||||
.enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema),
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -3492,6 +3499,7 @@ pub const Type = struct {
|
||||
.opaque_type => unreachable,
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -3826,19 +3834,30 @@ pub const Type = struct {
|
||||
.opaque_type => return null,
|
||||
.enum_type => |enum_type| switch (enum_type.tag_mode) {
|
||||
.nonexhaustive => {
|
||||
if (enum_type.tag_ty != .comptime_int_type and
|
||||
!enum_type.tag_ty.toType().hasRuntimeBits(mod))
|
||||
{
|
||||
return Value.enum_field_0;
|
||||
} else {
|
||||
return null;
|
||||
if (enum_type.tag_ty == .comptime_int_type) return null;
|
||||
|
||||
if (try enum_type.tag_ty.toType().onePossibleValue(mod)) |int_opv| {
|
||||
const only = try mod.intern(.{ .enum_tag = .{
|
||||
.ty = ty.ip_index,
|
||||
.int = int_opv.ip_index,
|
||||
} });
|
||||
return only.toValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
.auto, .explicit => switch (enum_type.names.len) {
|
||||
0 => return Value.@"unreachable",
|
||||
1 => {
|
||||
if (enum_type.values.len == 0) {
|
||||
return Value.enum_field_0; // auto-numbered
|
||||
const only = try mod.intern(.{ .enum_tag = .{
|
||||
.ty = ty.ip_index,
|
||||
.int = try mod.intern(.{ .int = .{
|
||||
.ty = enum_type.tag_ty,
|
||||
.storage = .{ .u64 = 0 },
|
||||
} }),
|
||||
} });
|
||||
return only.toValue();
|
||||
} else {
|
||||
return enum_type.values[0].toValue();
|
||||
}
|
||||
@@ -3848,6 +3867,7 @@ pub const Type = struct {
|
||||
},
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -4006,6 +4026,7 @@ pub const Type = struct {
|
||||
.enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod),
|
||||
|
||||
// values, not types
|
||||
.undef => unreachable,
|
||||
.un => unreachable,
|
||||
.simple_value => unreachable,
|
||||
.extern_func => unreachable,
|
||||
@@ -4224,36 +4245,22 @@ pub const Type = struct {
|
||||
return ip.stringToSlice(field_name);
|
||||
}
|
||||
|
||||
pub fn enumFieldIndex(ty: Type, field_name: []const u8, mod: *Module) ?usize {
|
||||
pub fn enumFieldIndex(ty: Type, field_name: []const u8, mod: *Module) ?u32 {
|
||||
const ip = &mod.intern_pool;
|
||||
const enum_type = ip.indexToKey(ty.ip_index).enum_type;
|
||||
// If the string is not interned, then the field certainly is not present.
|
||||
const field_name_interned = ip.getString(field_name).unwrap() orelse return null;
|
||||
return enum_type.nameIndex(ip.*, field_name_interned);
|
||||
return enum_type.nameIndex(ip, field_name_interned);
|
||||
}
|
||||
|
||||
/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
|
||||
/// an integer which represents the enum value. Returns the field index in
|
||||
/// declaration order, or `null` if `enum_tag` does not match any field.
|
||||
pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
|
||||
if (enum_tag.castTag(.enum_field_index)) |payload| {
|
||||
return @as(usize, payload.data);
|
||||
}
|
||||
pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
|
||||
const ip = &mod.intern_pool;
|
||||
const enum_type = ip.indexToKey(ty.ip_index).enum_type;
|
||||
const tag_ty = enum_type.tag_ty.toType();
|
||||
if (enum_type.values.len == 0) {
|
||||
if (enum_tag.compareAllWithZero(.lt, mod)) return null;
|
||||
const end_val = mod.intValue(tag_ty, enum_type.names.len) catch |err| switch (err) {
|
||||
// TODO: eliminate this failure condition
|
||||
error.OutOfMemory => @panic("OOM"),
|
||||
};
|
||||
if (enum_tag.compareScalar(.gte, end_val, tag_ty, mod)) return null;
|
||||
return @intCast(usize, enum_tag.toUnsignedInt(mod));
|
||||
} else {
|
||||
assert(ip.typeOf(enum_tag.ip_index) == enum_type.tag_ty);
|
||||
return enum_type.tagValueIndex(ip.*, enum_tag.ip_index);
|
||||
}
|
||||
assert(ip.typeOf(enum_tag.ip_index) == enum_type.tag_ty);
|
||||
return enum_type.tagValueIndex(ip, enum_tag.ip_index);
|
||||
}
|
||||
|
||||
pub fn structFields(ty: Type, mod: *Module) Module.Struct.Fields {
|
||||
|
||||
260
src/value.zig
260
src/value.zig
@@ -73,8 +73,6 @@ pub const Value = struct {
|
||||
/// Pointer and length as sub `Value` objects.
|
||||
slice,
|
||||
enum_literal,
|
||||
/// A specific enum tag, indicated by the field index (declaration order).
|
||||
enum_field_index,
|
||||
@"error",
|
||||
/// When the type is error union:
|
||||
/// * If the tag is `.@"error"`, the error union is an error.
|
||||
@@ -143,8 +141,6 @@ pub const Value = struct {
|
||||
.str_lit => Payload.StrLit,
|
||||
.slice => Payload.Slice,
|
||||
|
||||
.enum_field_index => Payload.U32,
|
||||
|
||||
.ty,
|
||||
.lazy_align,
|
||||
.lazy_size,
|
||||
@@ -397,7 +393,6 @@ pub const Value = struct {
|
||||
.legacy = .{ .ptr_otherwise = &new_payload.base },
|
||||
};
|
||||
},
|
||||
.enum_field_index => return self.copyPayloadShallow(arena, Payload.U32),
|
||||
.@"error" => return self.copyPayloadShallow(arena, Payload.Error),
|
||||
|
||||
.aggregate => {
|
||||
@@ -515,7 +510,6 @@ pub const Value = struct {
|
||||
},
|
||||
.empty_array => return out_stream.writeAll(".{}"),
|
||||
.enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
|
||||
.enum_field_index => return out_stream.print("(enum field {d})", .{val.castTag(.enum_field_index).?.data}),
|
||||
.bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
|
||||
.str_lit => {
|
||||
const str_lit = val.castTag(.str_lit).?.data;
|
||||
@@ -618,87 +612,58 @@ pub const Value = struct {
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the type is an enum type.
|
||||
pub fn toEnum(val: Value, comptime E: type) E {
|
||||
switch (val.ip_index) {
|
||||
.calling_convention_c => {
|
||||
if (E == std.builtin.CallingConvention) {
|
||||
return .C;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
.calling_convention_inline => {
|
||||
if (E == std.builtin.CallingConvention) {
|
||||
return .Inline;
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
.none => switch (val.tag()) {
|
||||
.enum_field_index => {
|
||||
const field_index = val.castTag(.enum_field_index).?.data;
|
||||
return @intToEnum(E, field_index);
|
||||
},
|
||||
.the_only_possible_value => {
|
||||
const fields = std.meta.fields(E);
|
||||
assert(fields.len == 1);
|
||||
return @intToEnum(E, fields[0].value);
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enumToInt(val: Value, ty: Type, mod: *Module) Allocator.Error!Value {
|
||||
const field_index = switch (val.tag()) {
|
||||
.enum_field_index => val.castTag(.enum_field_index).?.data,
|
||||
.the_only_possible_value => blk: {
|
||||
assert(ty.enumFieldCount(mod) == 1);
|
||||
break :blk 0;
|
||||
const ip = &mod.intern_pool;
|
||||
switch (val.ip_index) {
|
||||
.none => {
|
||||
const field_index = switch (val.tag()) {
|
||||
.the_only_possible_value => blk: {
|
||||
assert(ty.enumFieldCount(mod) == 1);
|
||||
break :blk 0;
|
||||
},
|
||||
.enum_literal => i: {
|
||||
const name = val.castTag(.enum_literal).?.data;
|
||||
break :i ty.enumFieldIndex(name, mod).?;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const enum_type = ip.indexToKey(ty.ip_index).enum_type;
|
||||
if (enum_type.values.len != 0) {
|
||||
return enum_type.values[field_index].toValue();
|
||||
} else {
|
||||
// Field index and integer values are the same.
|
||||
return mod.intValue(enum_type.tag_ty.toType(), field_index);
|
||||
}
|
||||
},
|
||||
.enum_literal => i: {
|
||||
const name = val.castTag(.enum_literal).?.data;
|
||||
break :i ty.enumFieldIndex(name, mod).?;
|
||||
else => {
|
||||
const enum_type = ip.indexToKey(ip.typeOf(val.ip_index)).enum_type;
|
||||
const int = try ip.getCoerced(mod.gpa, val.ip_index, enum_type.tag_ty);
|
||||
return int.toValue();
|
||||
},
|
||||
// Assume it is already an integer and return it directly.
|
||||
else => return val,
|
||||
};
|
||||
|
||||
const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
|
||||
if (enum_type.values.len != 0) {
|
||||
return enum_type.values[field_index].toValue();
|
||||
} else {
|
||||
// Field index and integer values are the same.
|
||||
return mod.intValue(enum_type.tag_ty.toType(), field_index);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 {
|
||||
if (ty.zigTypeTag(mod) == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(mod), mod);
|
||||
_ = ty; // TODO: remove this parameter now that we use InternPool
|
||||
|
||||
const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type;
|
||||
if (val.castTag(.enum_literal)) |payload| {
|
||||
return payload.data;
|
||||
}
|
||||
|
||||
const field_index = switch (val.tag()) {
|
||||
.enum_field_index => val.castTag(.enum_field_index).?.data,
|
||||
.the_only_possible_value => blk: {
|
||||
assert(ty.enumFieldCount(mod) == 1);
|
||||
break :blk 0;
|
||||
},
|
||||
.enum_literal => return val.castTag(.enum_literal).?.data,
|
||||
else => field_index: {
|
||||
if (enum_type.values.len == 0) {
|
||||
// auto-numbered enum
|
||||
break :field_index @intCast(u32, val.toUnsignedInt(mod));
|
||||
}
|
||||
const field_index = enum_type.tagValueIndex(mod.intern_pool, val.ip_index).?;
|
||||
break :field_index @intCast(u32, field_index);
|
||||
},
|
||||
const ip = &mod.intern_pool;
|
||||
|
||||
const enum_tag = switch (ip.indexToKey(val.ip_index)) {
|
||||
.un => |un| ip.indexToKey(un.tag).enum_tag,
|
||||
.enum_tag => |x| x,
|
||||
else => unreachable,
|
||||
};
|
||||
const enum_type = ip.indexToKey(enum_tag.ty).enum_type;
|
||||
const field_index = field_index: {
|
||||
const field_index = enum_type.tagValueIndex(ip, val.ip_index).?;
|
||||
break :field_index @intCast(u32, field_index);
|
||||
};
|
||||
|
||||
const field_name = enum_type.names[field_index];
|
||||
return mod.intern_pool.stringToSlice(field_name);
|
||||
return ip.stringToSlice(field_name);
|
||||
}
|
||||
|
||||
/// Asserts the value is an integer.
|
||||
@@ -722,10 +687,6 @@ pub const Value = struct {
|
||||
.the_only_possible_value, // i0, u0
|
||||
=> BigIntMutable.init(&space.limbs, 0).toConst(),
|
||||
|
||||
.enum_field_index => {
|
||||
const index = val.castTag(.enum_field_index).?.data;
|
||||
return BigIntMutable.init(&space.limbs, index).toConst();
|
||||
},
|
||||
.runtime_value => {
|
||||
const sub_val = val.castTag(.runtime_value).?.data;
|
||||
return sub_val.toBigIntAdvanced(space, mod, opt_sema);
|
||||
@@ -759,6 +720,7 @@ pub const Value = struct {
|
||||
},
|
||||
else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
.int => |int| int.storage.toBigInt(space),
|
||||
.enum_tag => |enum_tag| mod.intern_pool.indexToKey(enum_tag.int).int.storage.toBigInt(space),
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
@@ -886,7 +848,7 @@ pub const Value = struct {
|
||||
}!void {
|
||||
const target = mod.getTarget();
|
||||
const endian = target.cpu.arch.endian();
|
||||
if (val.isUndef()) {
|
||||
if (val.isUndef(mod)) {
|
||||
const size = @intCast(usize, ty.abiSize(mod));
|
||||
@memset(buffer[0..size], 0xaa);
|
||||
return;
|
||||
@@ -1007,7 +969,7 @@ pub const Value = struct {
|
||||
) error{ ReinterpretDeclRef, OutOfMemory }!void {
|
||||
const target = mod.getTarget();
|
||||
const endian = target.cpu.arch.endian();
|
||||
if (val.isUndef()) {
|
||||
if (val.isUndef(mod)) {
|
||||
const bit_size = @intCast(usize, ty.bitSize(mod));
|
||||
std.mem.writeVarPackedInt(buffer, bit_offset, bit_size, @as(u1, 0), endian);
|
||||
return;
|
||||
@@ -1087,7 +1049,7 @@ pub const Value = struct {
|
||||
.Auto => unreachable, // Sema is supposed to have emitted a compile error already
|
||||
.Extern => unreachable, // Handled in non-packed writeToMemory
|
||||
.Packed => {
|
||||
const field_index = ty.unionTagFieldIndex(val.unionTag(), mod);
|
||||
const field_index = ty.unionTagFieldIndex(val.unionTag(mod), mod);
|
||||
const field_type = ty.unionFields(mod).values()[field_index.?].ty;
|
||||
const field_val = try val.fieldValue(field_type, mod, field_index.?);
|
||||
|
||||
@@ -1432,7 +1394,7 @@ pub const Value = struct {
|
||||
}
|
||||
|
||||
pub fn popCount(val: Value, ty: Type, mod: *Module) u64 {
|
||||
assert(!val.isUndef());
|
||||
assert(!val.isUndef(mod));
|
||||
switch (val.ip_index) {
|
||||
.bool_false => return 0,
|
||||
.bool_true => return 1,
|
||||
@@ -1450,7 +1412,7 @@ pub const Value = struct {
|
||||
}
|
||||
|
||||
pub fn bitReverse(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value {
|
||||
assert(!val.isUndef());
|
||||
assert(!val.isUndef(mod));
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
@@ -1468,7 +1430,7 @@ pub const Value = struct {
|
||||
}
|
||||
|
||||
pub fn byteSwap(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value {
|
||||
assert(!val.isUndef());
|
||||
assert(!val.isUndef(mod));
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
@@ -1578,7 +1540,6 @@ pub const Value = struct {
|
||||
.variable,
|
||||
=> .gt,
|
||||
|
||||
.enum_field_index => return std.math.order(lhs.castTag(.enum_field_index).?.data, 0),
|
||||
.runtime_value => {
|
||||
// This is needed to correctly handle hashing the value.
|
||||
// Checks in Sema should prevent direct comparisons from reaching here.
|
||||
@@ -1633,6 +1594,10 @@ pub const Value = struct {
|
||||
.big_int => |big_int| big_int.orderAgainstScalar(0),
|
||||
inline .u64, .i64 => |x| std.math.order(x, 0),
|
||||
},
|
||||
.enum_tag => |enum_tag| switch (mod.intern_pool.indexToKey(enum_tag.int).int.storage) {
|
||||
.big_int => |big_int| big_int.orderAgainstScalar(0),
|
||||
inline .u64, .i64 => |x| std.math.order(x, 0),
|
||||
},
|
||||
.float => |float| switch (float.storage) {
|
||||
inline else => |x| std.math.order(x, 0),
|
||||
},
|
||||
@@ -1861,11 +1826,6 @@ pub const Value = struct {
|
||||
const b_name = b.castTag(.enum_literal).?.data;
|
||||
return std.mem.eql(u8, a_name, b_name);
|
||||
},
|
||||
.enum_field_index => {
|
||||
const a_field_index = a.castTag(.enum_field_index).?.data;
|
||||
const b_field_index = b.castTag(.enum_field_index).?.data;
|
||||
return a_field_index == b_field_index;
|
||||
},
|
||||
.opt_payload => {
|
||||
const a_payload = a.castTag(.opt_payload).?.data;
|
||||
const b_payload = b.castTag(.opt_payload).?.data;
|
||||
@@ -2064,13 +2024,9 @@ pub const Value = struct {
|
||||
}
|
||||
const field_name = tuple.names[0];
|
||||
const union_obj = mod.typeToUnion(ty).?;
|
||||
const field_index = union_obj.fields.getIndex(field_name) orelse return false;
|
||||
const field_index = @intCast(u32, union_obj.fields.getIndex(field_name) orelse return false);
|
||||
const tag_and_val = b.castTag(.@"union").?.data;
|
||||
var field_tag_buf: Value.Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = @intCast(u32, field_index),
|
||||
};
|
||||
const field_tag = Value.initPayload(&field_tag_buf.base);
|
||||
const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, field_index);
|
||||
const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod);
|
||||
if (!tag_matches) return false;
|
||||
return eqlAdvanced(tag_and_val.val, union_obj.tag_ty, tuple.values[0], tuple.types[0], mod, opt_sema);
|
||||
@@ -2132,7 +2088,7 @@ pub const Value = struct {
|
||||
}
|
||||
const zig_ty_tag = ty.zigTypeTag(mod);
|
||||
std.hash.autoHash(hasher, zig_ty_tag);
|
||||
if (val.isUndef()) return;
|
||||
if (val.isUndef(mod)) return;
|
||||
// The value is runtime-known and shouldn't affect the hash.
|
||||
if (val.isRuntimeValue()) return;
|
||||
|
||||
@@ -2277,7 +2233,7 @@ pub const Value = struct {
|
||||
/// This function is used by hash maps and so treats floating-point NaNs as equal
|
||||
/// to each other, and not equal to other floating-point values.
|
||||
pub fn hashUncoerced(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void {
|
||||
if (val.isUndef()) return;
|
||||
if (val.isUndef(mod)) return;
|
||||
// The value is runtime-known and shouldn't affect the hash.
|
||||
if (val.isRuntimeValue()) return;
|
||||
|
||||
@@ -2726,16 +2682,12 @@ pub const Value = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unionTag(val: Value) Value {
|
||||
switch (val.ip_index) {
|
||||
.undef => return val,
|
||||
.none => switch (val.tag()) {
|
||||
.enum_field_index => return val,
|
||||
.@"union" => return val.castTag(.@"union").?.data.tag,
|
||||
else => unreachable,
|
||||
},
|
||||
pub fn unionTag(val: Value, mod: *Module) Value {
|
||||
return switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
.undef, .enum_tag => val,
|
||||
.un => |un| un.tag.toValue(),
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a pointer to the element value at the index.
|
||||
@@ -2769,27 +2721,30 @@ pub const Value = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn isUndef(val: Value) bool {
|
||||
return val.ip_index == .undef;
|
||||
pub fn isUndef(val: Value, mod: *Module) bool {
|
||||
if (val.ip_index == .none) return false;
|
||||
return switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
.undef => true,
|
||||
.simple_value => |v| v == .undefined,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// TODO: check for cases such as array that is not marked undef but all the element
|
||||
/// values are marked undef, or struct that is not marked undef but all fields are marked
|
||||
/// undef, etc.
|
||||
pub fn isUndefDeep(val: Value) bool {
|
||||
return val.isUndef();
|
||||
pub fn isUndefDeep(val: Value, mod: *Module) bool {
|
||||
return val.isUndef(mod);
|
||||
}
|
||||
|
||||
/// Returns true if any value contained in `self` is undefined.
|
||||
/// TODO: check for cases such as array that is not marked undef but all the element
|
||||
/// values are marked undef, or struct that is not marked undef but all fields are marked
|
||||
/// undef, etc.
|
||||
pub fn anyUndef(self: Value, mod: *Module) !bool {
|
||||
switch (self.ip_index) {
|
||||
pub fn anyUndef(val: Value, mod: *Module) !bool {
|
||||
if (val.ip_index == .none) return false;
|
||||
switch (val.ip_index) {
|
||||
.undef => return true,
|
||||
.none => switch (self.tag()) {
|
||||
.none => switch (val.tag()) {
|
||||
.slice => {
|
||||
const payload = self.castTag(.slice).?;
|
||||
const payload = val.castTag(.slice).?;
|
||||
const len = payload.data.len.toUnsignedInt(mod);
|
||||
|
||||
for (0..len) |i| {
|
||||
@@ -2799,14 +2754,21 @@ pub const Value = struct {
|
||||
},
|
||||
|
||||
.aggregate => {
|
||||
const payload = self.castTag(.aggregate).?;
|
||||
for (payload.data) |val| {
|
||||
if (try val.anyUndef(mod)) return true;
|
||||
const payload = val.castTag(.aggregate).?;
|
||||
for (payload.data) |field| {
|
||||
if (try field.anyUndef(mod)) return true;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
|
||||
.undef => return true,
|
||||
.simple_value => |v| if (v == .undefined) return true,
|
||||
.aggregate => |aggregate| for (aggregate.fields) |field| {
|
||||
if (try anyUndef(field.toValue(), mod)) return true;
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -2819,11 +2781,7 @@ pub const Value = struct {
|
||||
.undef => unreachable,
|
||||
.unreachable_value => unreachable,
|
||||
|
||||
.null_value,
|
||||
.zero,
|
||||
.zero_usize,
|
||||
.zero_u8,
|
||||
=> true,
|
||||
.null_value => true,
|
||||
|
||||
.none => switch (val.tag()) {
|
||||
.opt_payload => false,
|
||||
@@ -2843,6 +2801,7 @@ pub const Value = struct {
|
||||
.big_int => |big_int| big_int.eqZero(),
|
||||
inline .u64, .i64 => |x| x == 0,
|
||||
},
|
||||
.opt => |opt| opt.val == .none,
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
@@ -3024,8 +2983,8 @@ pub const Value = struct {
|
||||
arena: Allocator,
|
||||
mod: *Module,
|
||||
) !Value {
|
||||
assert(!lhs.isUndef());
|
||||
assert(!rhs.isUndef());
|
||||
assert(!lhs.isUndef(mod));
|
||||
assert(!rhs.isUndef(mod));
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
@@ -3071,8 +3030,8 @@ pub const Value = struct {
|
||||
arena: Allocator,
|
||||
mod: *Module,
|
||||
) !Value {
|
||||
assert(!lhs.isUndef());
|
||||
assert(!rhs.isUndef());
|
||||
assert(!lhs.isUndef(mod));
|
||||
assert(!rhs.isUndef(mod));
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
@@ -3178,7 +3137,7 @@ pub const Value = struct {
|
||||
arena: Allocator,
|
||||
mod: *Module,
|
||||
) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
|
||||
if (ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||
return intMul(lhs, rhs, ty, arena, mod);
|
||||
@@ -3220,8 +3179,8 @@ pub const Value = struct {
|
||||
arena: Allocator,
|
||||
mod: *Module,
|
||||
) !Value {
|
||||
assert(!lhs.isUndef());
|
||||
assert(!rhs.isUndef());
|
||||
assert(!lhs.isUndef(mod));
|
||||
assert(!rhs.isUndef(mod));
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
@@ -3249,7 +3208,7 @@ pub const Value = struct {
|
||||
|
||||
/// Supports both floats and ints; handles undefined.
|
||||
pub fn numberMax(lhs: Value, rhs: Value, mod: *Module) Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return undef;
|
||||
if (lhs.isNan(mod)) return rhs;
|
||||
if (rhs.isNan(mod)) return lhs;
|
||||
|
||||
@@ -3261,7 +3220,7 @@ pub const Value = struct {
|
||||
|
||||
/// Supports both floats and ints; handles undefined.
|
||||
pub fn numberMin(lhs: Value, rhs: Value, mod: *Module) Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return undef;
|
||||
if (lhs.isNan(mod)) return rhs;
|
||||
if (rhs.isNan(mod)) return lhs;
|
||||
|
||||
@@ -3286,7 +3245,7 @@ pub const Value = struct {
|
||||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
if (val.isUndef()) return Value.undef;
|
||||
if (val.isUndef(mod)) return Value.undef;
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
@@ -3324,7 +3283,7 @@ pub const Value = struct {
|
||||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
@@ -3358,7 +3317,7 @@ pub const Value = struct {
|
||||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
|
||||
const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod);
|
||||
const all_ones = if (ty.isSignedInt(mod)) try mod.intValue(ty, -1) else try ty.maxIntScalar(mod, ty);
|
||||
@@ -3381,7 +3340,7 @@ pub const Value = struct {
|
||||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseOrScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
@@ -3415,7 +3374,7 @@ pub const Value = struct {
|
||||
|
||||
/// operands must be integers; handles undefined.
|
||||
pub fn bitwiseXorScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
@@ -4697,11 +4656,6 @@ pub const Value = struct {
|
||||
pub const Payload = struct {
|
||||
tag: Tag,
|
||||
|
||||
pub const U32 = struct {
|
||||
base: Payload,
|
||||
data: u32,
|
||||
};
|
||||
|
||||
pub const Function = struct {
|
||||
base: Payload,
|
||||
data: *Module.Fn,
|
||||
@@ -4885,16 +4839,6 @@ pub const Value = struct {
|
||||
pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type, .legacy = undefined };
|
||||
pub const empty_struct: Value = .{ .ip_index = .empty_struct, .legacy = undefined };
|
||||
|
||||
pub const enum_field_0: Value = .{
|
||||
.ip_index = .none,
|
||||
.legacy = .{ .ptr_otherwise = &enum_field_0_payload.base },
|
||||
};
|
||||
|
||||
var enum_field_0_payload: Payload.U32 = .{
|
||||
.base = .{ .tag = .enum_field_index },
|
||||
.data = 0,
|
||||
};
|
||||
|
||||
pub fn makeBool(x: bool) Value {
|
||||
return if (x) Value.true else Value.false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user