mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
behavior: get more test cases passing with llvm
This commit is contained in:
committed by
Andrew Kelley
parent
c8b0d4d149
commit
2d5bc01469
+254
-155
@@ -621,8 +621,7 @@ pub const Key = union(enum) {
|
||||
|
||||
pub fn hashWithHasher(key: Key, hasher: *std.hash.Wyhash, ip: *const InternPool) void {
|
||||
const KeyTag = @typeInfo(Key).Union.tag_type.?;
|
||||
const key_tag: KeyTag = key;
|
||||
std.hash.autoHash(hasher, key_tag);
|
||||
std.hash.autoHash(hasher, @as(KeyTag, key));
|
||||
switch (key) {
|
||||
inline .int_type,
|
||||
.ptr_type,
|
||||
@@ -710,39 +709,58 @@ pub const Key = union(enum) {
|
||||
|
||||
.aggregate => |aggregate| {
|
||||
std.hash.autoHash(hasher, aggregate.ty);
|
||||
switch (ip.indexToKey(aggregate.ty)) {
|
||||
.array_type => |array_type| if (array_type.child == .u8_type) {
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| for (bytes) |byte| std.hash.autoHash(hasher, byte),
|
||||
.elems => |elems| {
|
||||
var buffer: Key.Int.Storage.BigIntSpace = undefined;
|
||||
for (elems) |elem| std.hash.autoHash(
|
||||
const len = ip.aggregateTypeLen(aggregate.ty);
|
||||
const child = switch (ip.indexToKey(aggregate.ty)) {
|
||||
.array_type => |array_type| array_type.child,
|
||||
.vector_type => |vector_type| vector_type.child,
|
||||
.anon_struct_type, .struct_type => .none,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
if (child == .u8_type) {
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| for (bytes[0..@intCast(usize, len)]) |byte| {
|
||||
std.hash.autoHash(hasher, KeyTag.int);
|
||||
std.hash.autoHash(hasher, byte);
|
||||
},
|
||||
.elems => |elems| for (elems[0..@intCast(usize, len)]) |elem| {
|
||||
const elem_key = ip.indexToKey(elem);
|
||||
std.hash.autoHash(hasher, @as(KeyTag, elem_key));
|
||||
switch (elem_key) {
|
||||
.undef => {},
|
||||
.int => |int| std.hash.autoHash(
|
||||
hasher,
|
||||
ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch
|
||||
unreachable,
|
||||
);
|
||||
},
|
||||
.repeated_elem => |elem| {
|
||||
const len = ip.aggregateTypeLen(aggregate.ty);
|
||||
var buffer: Key.Int.Storage.BigIntSpace = undefined;
|
||||
const byte = ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch
|
||||
unreachable;
|
||||
var i: u64 = 0;
|
||||
while (i < len) : (i += 1) std.hash.autoHash(hasher, byte);
|
||||
},
|
||||
}
|
||||
return;
|
||||
},
|
||||
else => {},
|
||||
@intCast(u8, int.storage.u64),
|
||||
),
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.repeated_elem => |elem| {
|
||||
const elem_key = ip.indexToKey(elem);
|
||||
var remaining = len;
|
||||
while (remaining > 0) : (remaining -= 1) {
|
||||
std.hash.autoHash(hasher, @as(KeyTag, elem_key));
|
||||
switch (elem_key) {
|
||||
.undef => {},
|
||||
.int => |int| std.hash.autoHash(
|
||||
hasher,
|
||||
@intCast(u8, int.storage.u64),
|
||||
),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aggregate.storage) {
|
||||
.bytes => unreachable,
|
||||
.elems => |elems| for (elems) |elem| std.hash.autoHash(hasher, elem),
|
||||
.elems => |elems| for (elems[0..@intCast(usize, len)]) |elem|
|
||||
std.hash.autoHash(hasher, elem),
|
||||
.repeated_elem => |elem| {
|
||||
const len = ip.aggregateTypeLen(aggregate.ty);
|
||||
var i: u64 = 0;
|
||||
while (i < len) : (i += 1) std.hash.autoHash(hasher, elem);
|
||||
var remaining = len;
|
||||
while (remaining > 0) : (remaining -= 1) std.hash.autoHash(hasher, elem);
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -960,9 +978,10 @@ pub const Key = union(enum) {
|
||||
const b_info = b.aggregate;
|
||||
if (a_info.ty != b_info.ty) return false;
|
||||
|
||||
const len = ip.aggregateTypeLen(a_info.ty);
|
||||
const StorageTag = @typeInfo(Key.Aggregate.Storage).Union.tag_type.?;
|
||||
if (@as(StorageTag, a_info.storage) != @as(StorageTag, b_info.storage)) {
|
||||
for (0..@intCast(usize, ip.aggregateTypeLen(a_info.ty))) |elem_index| {
|
||||
for (0..@intCast(usize, len)) |elem_index| {
|
||||
const a_elem = switch (a_info.storage) {
|
||||
.bytes => |bytes| ip.getIfExists(.{ .int = .{
|
||||
.ty = .u8_type,
|
||||
@@ -987,11 +1006,19 @@ pub const Key = union(enum) {
|
||||
switch (a_info.storage) {
|
||||
.bytes => |a_bytes| {
|
||||
const b_bytes = b_info.storage.bytes;
|
||||
return std.mem.eql(u8, a_bytes, b_bytes);
|
||||
return std.mem.eql(
|
||||
u8,
|
||||
a_bytes[0..@intCast(usize, len)],
|
||||
b_bytes[0..@intCast(usize, len)],
|
||||
);
|
||||
},
|
||||
.elems => |a_elems| {
|
||||
const b_elems = b_info.storage.elems;
|
||||
return std.mem.eql(Index, a_elems, b_elems);
|
||||
return std.mem.eql(
|
||||
Index,
|
||||
a_elems[0..@intCast(usize, len)],
|
||||
b_elems[0..@intCast(usize, len)],
|
||||
);
|
||||
},
|
||||
.repeated_elem => |a_elem| {
|
||||
const b_elem = b_info.storage.repeated_elem;
|
||||
@@ -2691,7 +2718,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
|
||||
},
|
||||
.bytes => {
|
||||
const extra = ip.extraData(Bytes, data);
|
||||
const len = @intCast(u32, ip.aggregateTypeLen(extra.ty));
|
||||
const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(extra.ty));
|
||||
return .{ .aggregate = .{
|
||||
.ty = extra.ty,
|
||||
.storage = .{ .bytes = ip.string_bytes.items[@enumToInt(extra.bytes)..][0..len] },
|
||||
@@ -2699,7 +2726,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
|
||||
},
|
||||
.aggregate => {
|
||||
const extra = ip.extraDataTrail(Aggregate, data);
|
||||
const len = @intCast(u32, ip.aggregateTypeLen(extra.data.ty));
|
||||
const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(extra.data.ty));
|
||||
const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]);
|
||||
return .{ .aggregate = .{
|
||||
.ty = extra.data.ty,
|
||||
@@ -3145,7 +3172,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
}),
|
||||
}),
|
||||
.int => |int| {
|
||||
assert(int != .none);
|
||||
assert(ip.typeOf(int) == .usize_type);
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .ptr_int,
|
||||
.data = try ip.addExtra(gpa, PtrAddr{
|
||||
@@ -3452,7 +3479,11 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
|
||||
.enum_tag => |enum_tag| {
|
||||
assert(ip.isEnumType(enum_tag.ty));
|
||||
assert(ip.indexToKey(enum_tag.int) == .int);
|
||||
switch (ip.indexToKey(enum_tag.ty)) {
|
||||
.simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))),
|
||||
.enum_type => |enum_type| assert(ip.typeOf(enum_tag.int) == enum_type.tag_ty),
|
||||
else => unreachable,
|
||||
}
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .enum_tag,
|
||||
.data = try ip.addExtra(gpa, enum_tag),
|
||||
@@ -3501,21 +3532,43 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
|
||||
.aggregate => |aggregate| {
|
||||
const ty_key = ip.indexToKey(aggregate.ty);
|
||||
const aggregate_len = ip.aggregateTypeLen(aggregate.ty);
|
||||
const len = ip.aggregateTypeLen(aggregate.ty);
|
||||
const child = switch (ty_key) {
|
||||
.array_type => |array_type| array_type.child,
|
||||
.vector_type => |vector_type| vector_type.child,
|
||||
.anon_struct_type, .struct_type => .none,
|
||||
else => unreachable,
|
||||
};
|
||||
const sentinel = switch (ty_key) {
|
||||
.array_type => |array_type| array_type.sentinel,
|
||||
.vector_type, .anon_struct_type, .struct_type => .none,
|
||||
else => unreachable,
|
||||
};
|
||||
const len_including_sentinel = len + @boolToInt(sentinel != .none);
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| {
|
||||
assert(ty_key.array_type.child == .u8_type);
|
||||
assert(bytes.len == aggregate_len);
|
||||
assert(child == .u8_type);
|
||||
if (bytes.len != len) {
|
||||
assert(bytes.len == len_including_sentinel);
|
||||
assert(bytes[len] == ip.indexToKey(sentinel).int.storage.u64);
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
.elems => |elems| {
|
||||
assert(elems.len == aggregate_len);
|
||||
if (elems.len != len) {
|
||||
assert(elems.len == len_including_sentinel);
|
||||
assert(elems[len] == sentinel);
|
||||
unreachable;
|
||||
}
|
||||
},
|
||||
.repeated_elem => |elem| {
|
||||
assert(sentinel == .none or elem == sentinel);
|
||||
},
|
||||
.repeated_elem => {},
|
||||
}
|
||||
switch (ty_key) {
|
||||
inline .array_type, .vector_type => |seq_type| {
|
||||
.array_type, .vector_type => {
|
||||
for (aggregate.storage.values()) |elem| {
|
||||
assert(ip.typeOf(elem) == seq_type.child);
|
||||
assert(ip.typeOf(elem) == child);
|
||||
}
|
||||
},
|
||||
.struct_type => |struct_type| {
|
||||
@@ -3534,7 +3587,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
if (aggregate_len == 0) {
|
||||
if (len == 0) {
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .only_possible_value,
|
||||
.data = @enumToInt(aggregate.ty),
|
||||
@@ -3543,41 +3596,43 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
}
|
||||
|
||||
switch (ty_key) {
|
||||
.anon_struct_type => |anon_struct_type| {
|
||||
if (switch (aggregate.storage) {
|
||||
.anon_struct_type => |anon_struct_type| opv: {
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| for (anon_struct_type.values, bytes) |value, byte| {
|
||||
if (value != ip.getIfExists(.{ .int = .{
|
||||
.ty = .u8_type,
|
||||
.storage = .{ .u64 = byte },
|
||||
} })) break false;
|
||||
} else true,
|
||||
.elems => |elems| std.mem.eql(Index, anon_struct_type.values, elems),
|
||||
} })) break :opv;
|
||||
},
|
||||
.elems => |elems| if (!std.mem.eql(
|
||||
Index,
|
||||
anon_struct_type.values,
|
||||
elems,
|
||||
)) break :opv,
|
||||
.repeated_elem => |elem| for (anon_struct_type.values) |value| {
|
||||
if (value != elem) break false;
|
||||
} else true,
|
||||
}) {
|
||||
// This encoding works thanks to the fact that, as we just verified,
|
||||
// the type itself contains a slice of values that can be provided
|
||||
// in the aggregate fields.
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .only_possible_value,
|
||||
.data = @enumToInt(aggregate.ty),
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
if (value != elem) break :opv;
|
||||
},
|
||||
}
|
||||
// This encoding works thanks to the fact that, as we just verified,
|
||||
// the type itself contains a slice of values that can be provided
|
||||
// in the aggregate fields.
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .only_possible_value,
|
||||
.data = @enumToInt(aggregate.ty),
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (switch (aggregate.storage) {
|
||||
.bytes => |bytes| for (bytes[1..]) |byte| {
|
||||
if (byte != bytes[0]) break false;
|
||||
} else true,
|
||||
.elems => |elems| for (elems[1..]) |elem| {
|
||||
if (elem != elems[0]) break false;
|
||||
} else true,
|
||||
.repeated_elem => true,
|
||||
}) {
|
||||
repeated: {
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| for (bytes[1..@intCast(usize, len)]) |byte|
|
||||
if (byte != bytes[0]) break :repeated,
|
||||
.elems => |elems| for (elems[1..@intCast(usize, len)]) |elem|
|
||||
if (elem != elems[0]) break :repeated,
|
||||
.repeated_elem => {},
|
||||
}
|
||||
const elem = switch (aggregate.storage) {
|
||||
.bytes => |bytes| elem: {
|
||||
_ = ip.map.pop();
|
||||
@@ -3607,42 +3662,48 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
}
|
||||
|
||||
switch (ty_key) {
|
||||
.array_type => |array_type| if (array_type.child == .u8_type) {
|
||||
const len_including_sentinel = aggregate_len + @boolToInt(array_type.sentinel != .none);
|
||||
try ip.string_bytes.ensureUnusedCapacity(gpa, len_including_sentinel + 1);
|
||||
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len);
|
||||
var buffer: Key.Int.Storage.BigIntSpace = undefined;
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes),
|
||||
.elems => |elems| for (elems) |elem| ip.string_bytes.appendAssumeCapacity(
|
||||
ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch unreachable,
|
||||
if (child == .u8_type) bytes: {
|
||||
const string_bytes_index = ip.string_bytes.items.len;
|
||||
try ip.string_bytes.ensureUnusedCapacity(gpa, len_including_sentinel + 1);
|
||||
try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len);
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes),
|
||||
.elems => |elems| for (elems) |elem| switch (ip.indexToKey(elem)) {
|
||||
.undef => {
|
||||
ip.string_bytes.shrinkRetainingCapacity(string_bytes_index);
|
||||
break :bytes;
|
||||
},
|
||||
.int => |int| ip.string_bytes.appendAssumeCapacity(
|
||||
@intCast(u8, int.storage.u64),
|
||||
),
|
||||
.repeated_elem => |elem| @memset(
|
||||
ip.string_bytes.addManyAsSliceAssumeCapacity(aggregate_len),
|
||||
ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch unreachable,
|
||||
else => unreachable,
|
||||
},
|
||||
.repeated_elem => |elem| switch (ip.indexToKey(elem)) {
|
||||
.undef => break :bytes,
|
||||
.int => |int| @memset(
|
||||
ip.string_bytes.addManyAsSliceAssumeCapacity(len),
|
||||
@intCast(u8, int.storage.u64),
|
||||
),
|
||||
}
|
||||
if (array_type.sentinel != .none) ip.string_bytes.appendAssumeCapacity(
|
||||
ip.indexToKey(array_type.sentinel).int.storage.toBigInt(&buffer).to(u8) catch
|
||||
unreachable,
|
||||
);
|
||||
const bytes = try ip.getOrPutTrailingString(gpa, len_including_sentinel);
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .bytes,
|
||||
.data = ip.addExtraAssumeCapacity(Bytes{
|
||||
.ty = aggregate.ty,
|
||||
.bytes = bytes.toString(),
|
||||
}),
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
},
|
||||
else => {},
|
||||
else => unreachable,
|
||||
},
|
||||
}
|
||||
if (sentinel != .none) ip.string_bytes.appendAssumeCapacity(
|
||||
@intCast(u8, ip.indexToKey(sentinel).int.storage.u64),
|
||||
);
|
||||
const bytes = try ip.getOrPutTrailingString(gpa, len_including_sentinel);
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .bytes,
|
||||
.data = ip.addExtraAssumeCapacity(Bytes{
|
||||
.ty = aggregate.ty,
|
||||
.bytes = bytes.toString(),
|
||||
}),
|
||||
});
|
||||
return @intToEnum(Index, ip.items.len - 1);
|
||||
}
|
||||
|
||||
try ip.extra.ensureUnusedCapacity(
|
||||
gpa,
|
||||
@typeInfo(Aggregate).Struct.fields.len + aggregate_len,
|
||||
@typeInfo(Aggregate).Struct.fields.len + len_including_sentinel,
|
||||
);
|
||||
ip.items.appendAssumeCapacity(.{
|
||||
.tag = .aggregate,
|
||||
@@ -3651,6 +3712,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
||||
}),
|
||||
});
|
||||
ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, aggregate.storage.elems));
|
||||
if (sentinel != .none) ip.extra.appendAssumeCapacity(@enumToInt(sentinel));
|
||||
},
|
||||
|
||||
.un => |un| {
|
||||
@@ -4183,10 +4245,12 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
|
||||
/// Given an existing value, returns the same value but with the supplied type.
|
||||
/// Only some combinations are allowed:
|
||||
/// * identity coercion
|
||||
/// * undef => any
|
||||
/// * int <=> int
|
||||
/// * int <=> enum
|
||||
/// * enum_literal => enum
|
||||
/// * ptr <=> ptr
|
||||
/// * int => ptr
|
||||
/// * null_value => opt
|
||||
/// * payload => opt
|
||||
/// * error set <=> error set
|
||||
@@ -4194,68 +4258,93 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
|
||||
/// * error set => error union
|
||||
/// * payload => error union
|
||||
/// * fn <=> fn
|
||||
/// * array <=> array
|
||||
/// * array <=> vector
|
||||
/// * vector <=> vector
|
||||
pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
|
||||
const old_ty = ip.typeOf(val);
|
||||
if (old_ty == new_ty) return val;
|
||||
switch (ip.indexToKey(val)) {
|
||||
.extern_func => |extern_func| if (ip.isFunctionType(new_ty))
|
||||
return ip.get(gpa, .{ .extern_func = .{
|
||||
switch (val) {
|
||||
.undef => return ip.get(gpa, .{ .undef = new_ty }),
|
||||
.null_value => if (ip.isOptionalType(new_ty))
|
||||
return ip.get(gpa, .{ .opt = .{
|
||||
.ty = new_ty,
|
||||
.decl = extern_func.decl,
|
||||
.lib_name = extern_func.lib_name,
|
||||
.val = .none,
|
||||
} }),
|
||||
.func => |func| if (ip.isFunctionType(new_ty))
|
||||
return ip.get(gpa, .{ .func = .{
|
||||
.ty = new_ty,
|
||||
.index = func.index,
|
||||
} }),
|
||||
.int => |int| if (ip.isIntegerType(new_ty))
|
||||
return getCoercedInts(ip, gpa, int, new_ty)
|
||||
else if (ip.isEnumType(new_ty))
|
||||
return ip.get(gpa, .{ .enum_tag = .{
|
||||
.ty = new_ty,
|
||||
.int = val,
|
||||
} }),
|
||||
.enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
|
||||
return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
|
||||
.enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
|
||||
.enum_type => |enum_type| {
|
||||
const index = enum_type.nameIndex(ip, enum_literal).?;
|
||||
else => switch (ip.indexToKey(val)) {
|
||||
.undef => return ip.get(gpa, .{ .undef = new_ty }),
|
||||
.extern_func => |extern_func| if (ip.isFunctionType(new_ty))
|
||||
return ip.get(gpa, .{ .extern_func = .{
|
||||
.ty = new_ty,
|
||||
.decl = extern_func.decl,
|
||||
.lib_name = extern_func.lib_name,
|
||||
} }),
|
||||
.func => |func| if (ip.isFunctionType(new_ty))
|
||||
return ip.get(gpa, .{ .func = .{
|
||||
.ty = new_ty,
|
||||
.index = func.index,
|
||||
} }),
|
||||
.int => |int| if (ip.isIntegerType(new_ty))
|
||||
return getCoercedInts(ip, gpa, int, new_ty)
|
||||
else if (ip.isEnumType(new_ty))
|
||||
return ip.get(gpa, .{ .enum_tag = .{
|
||||
.ty = new_ty,
|
||||
.int = if (enum_type.values.len != 0)
|
||||
enum_type.values[index]
|
||||
else
|
||||
try ip.get(gpa, .{ .int = .{
|
||||
.ty = enum_type.tag_ty,
|
||||
.storage = .{ .u64 = index },
|
||||
} }),
|
||||
} });
|
||||
.int = val,
|
||||
} })
|
||||
else if (ip.isPointerType(new_ty))
|
||||
return ip.get(gpa, .{ .ptr = .{
|
||||
.ty = new_ty,
|
||||
.addr = .{ .int = val },
|
||||
} }),
|
||||
.enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
|
||||
return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
|
||||
.enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
|
||||
.enum_type => |enum_type| {
|
||||
const index = enum_type.nameIndex(ip, enum_literal).?;
|
||||
return ip.get(gpa, .{ .enum_tag = .{
|
||||
.ty = new_ty,
|
||||
.int = if (enum_type.values.len != 0)
|
||||
enum_type.values[index]
|
||||
else
|
||||
try ip.get(gpa, .{ .int = .{
|
||||
.ty = enum_type.tag_ty,
|
||||
.storage = .{ .u64 = index },
|
||||
} }),
|
||||
} });
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.ptr => |ptr| if (ip.isPointerType(new_ty))
|
||||
return ip.get(gpa, .{ .ptr = .{
|
||||
.ty = new_ty,
|
||||
.addr = ptr.addr,
|
||||
.len = ptr.len,
|
||||
} }),
|
||||
.err => |err| if (ip.isErrorSetType(new_ty))
|
||||
return ip.get(gpa, .{ .err = .{
|
||||
.ty = new_ty,
|
||||
.name = err.name,
|
||||
} })
|
||||
else if (ip.isErrorUnionType(new_ty))
|
||||
return ip.get(gpa, .{ .error_union = .{
|
||||
.ty = new_ty,
|
||||
.val = .{ .err_name = err.name },
|
||||
} }),
|
||||
.error_union => |error_union| if (ip.isErrorUnionType(new_ty))
|
||||
return ip.get(gpa, .{ .error_union = .{
|
||||
.ty = new_ty,
|
||||
.val = error_union.val,
|
||||
} }),
|
||||
.aggregate => |aggregate| return ip.get(gpa, .{ .aggregate = .{
|
||||
.ty = new_ty,
|
||||
.storage = switch (aggregate.storage) {
|
||||
.bytes => |bytes| .{ .bytes = bytes[0..@intCast(usize, ip.aggregateTypeLen(new_ty))] },
|
||||
.elems => |elems| .{ .elems = elems[0..@intCast(usize, ip.aggregateTypeLen(new_ty))] },
|
||||
.repeated_elem => |elem| .{ .repeated_elem = elem },
|
||||
},
|
||||
} }),
|
||||
else => {},
|
||||
},
|
||||
.ptr => |ptr| if (ip.isPointerType(new_ty))
|
||||
return ip.get(gpa, .{ .ptr = .{
|
||||
.ty = new_ty,
|
||||
.addr = ptr.addr,
|
||||
.len = ptr.len,
|
||||
} }),
|
||||
.err => |err| if (ip.isErrorSetType(new_ty))
|
||||
return ip.get(gpa, .{ .err = .{
|
||||
.ty = new_ty,
|
||||
.name = err.name,
|
||||
} })
|
||||
else if (ip.isErrorUnionType(new_ty))
|
||||
return ip.get(gpa, .{ .error_union = .{
|
||||
.ty = new_ty,
|
||||
.val = .{ .err_name = err.name },
|
||||
} }),
|
||||
.error_union => |error_union| if (ip.isErrorUnionType(new_ty))
|
||||
return ip.get(gpa, .{ .error_union = .{
|
||||
.ty = new_ty,
|
||||
.val = error_union.val,
|
||||
} }),
|
||||
else => {},
|
||||
}
|
||||
switch (ip.indexToKey(new_ty)) {
|
||||
.opt_type => |child_type| switch (val) {
|
||||
@@ -4527,7 +4616,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||
|
||||
.type_function => b: {
|
||||
const info = ip.extraData(TypeFunction, data);
|
||||
break :b @sizeOf(TypeFunction) + (@sizeOf(u32) * info.params_len);
|
||||
break :b @sizeOf(TypeFunction) + (@sizeOf(Index) * info.params_len);
|
||||
},
|
||||
|
||||
.undef => 0,
|
||||
@@ -4570,14 +4659,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
|
||||
|
||||
.bytes => b: {
|
||||
const info = ip.extraData(Bytes, data);
|
||||
const len = @intCast(u32, ip.aggregateTypeLen(info.ty));
|
||||
const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(info.ty));
|
||||
break :b @sizeOf(Bytes) + len +
|
||||
@boolToInt(ip.string_bytes.items[@enumToInt(info.bytes) + len - 1] != 0);
|
||||
},
|
||||
.aggregate => b: {
|
||||
const info = ip.extraData(Aggregate, data);
|
||||
const fields_len = @intCast(u32, ip.aggregateTypeLen(info.ty));
|
||||
break :b @sizeOf(Aggregate) + (@sizeOf(u32) * fields_len);
|
||||
const fields_len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(info.ty));
|
||||
break :b @sizeOf(Aggregate) + (@sizeOf(Index) * fields_len);
|
||||
},
|
||||
.repeated => @sizeOf(Repeated),
|
||||
|
||||
@@ -4889,6 +4978,16 @@ pub fn aggregateTypeLen(ip: InternPool, ty: Index) u64 {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn aggregateTypeLenIncludingSentinel(ip: InternPool, ty: Index) u64 {
|
||||
return switch (ip.indexToKey(ty)) {
|
||||
.struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(),
|
||||
.anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
|
||||
.array_type => |array_type| array_type.len + @boolToInt(array_type.sentinel != .none),
|
||||
.vector_type => |vector_type| vector_type.len,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isNoReturn(ip: InternPool, ty: Index) bool {
|
||||
return switch (ty) {
|
||||
.noreturn_type => true,
|
||||
|
||||
+36
-49
@@ -99,6 +99,7 @@ monomorphed_funcs: MonomorphedFuncsSet = .{},
|
||||
/// The set of all comptime function calls that have been cached so that future calls
|
||||
/// with the same parameters will get the same return value.
|
||||
memoized_calls: MemoizedCallSet = .{},
|
||||
memoized_call_args: MemoizedCall.Args = .{},
|
||||
/// Contains the values from `@setAlignStack`. A sparse table is used here
|
||||
/// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while
|
||||
/// functions are many.
|
||||
@@ -230,46 +231,30 @@ pub const MemoizedCallSet = std.HashMapUnmanaged(
|
||||
);
|
||||
|
||||
pub const MemoizedCall = struct {
|
||||
module: *Module,
|
||||
args: *const Args,
|
||||
|
||||
pub const Args = std.ArrayListUnmanaged(InternPool.Index);
|
||||
|
||||
pub const Key = struct {
|
||||
func: Fn.Index,
|
||||
args: []TypedValue,
|
||||
};
|
||||
args_index: u32,
|
||||
args_count: u32,
|
||||
|
||||
pub const Result = struct {
|
||||
val: Value,
|
||||
arena: std.heap.ArenaAllocator.State,
|
||||
};
|
||||
|
||||
pub fn eql(ctx: @This(), a: Key, b: Key) bool {
|
||||
if (a.func != b.func) return false;
|
||||
|
||||
assert(a.args.len == b.args.len);
|
||||
for (a.args, 0..) |a_arg, arg_i| {
|
||||
const b_arg = b.args[arg_i];
|
||||
if (!a_arg.eql(b_arg, ctx.module)) {
|
||||
return false;
|
||||
}
|
||||
pub fn args(key: Key, ctx: MemoizedCall) []InternPool.Index {
|
||||
return ctx.args.items[key.args_index..][0..key.args_count];
|
||||
}
|
||||
};
|
||||
|
||||
return true;
|
||||
pub const Result = InternPool.Index;
|
||||
|
||||
pub fn eql(ctx: MemoizedCall, a: Key, b: Key) bool {
|
||||
return a.func == b.func and mem.eql(InternPool.Index, a.args(ctx), b.args(ctx));
|
||||
}
|
||||
|
||||
/// Must match `Sema.GenericCallAdapter.hash`.
|
||||
pub fn hash(ctx: @This(), key: Key) u64 {
|
||||
pub fn hash(ctx: MemoizedCall, key: Key) u64 {
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
|
||||
// The generic function Decl is guaranteed to be the first dependency
|
||||
// of each of its instantiations.
|
||||
std.hash.autoHash(&hasher, key.func);
|
||||
|
||||
// This logic must be kept in sync with the logic in `analyzeCall` that
|
||||
// computes the hash.
|
||||
for (key.args) |arg| {
|
||||
arg.hash(&hasher, ctx.module);
|
||||
}
|
||||
|
||||
std.hash.autoHashStrat(&hasher, key.args(ctx), .Deep);
|
||||
return hasher.final();
|
||||
}
|
||||
};
|
||||
@@ -883,6 +868,10 @@ pub const Decl = struct {
|
||||
return decl.ty.abiAlignment(mod);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intern(decl: *Decl, mod: *Module) Allocator.Error!void {
|
||||
decl.val = (try decl.val.intern(decl.ty, mod)).toValue();
|
||||
}
|
||||
};
|
||||
|
||||
/// This state is attached to every Decl when Module emit_h is non-null.
|
||||
@@ -3325,15 +3314,8 @@ pub fn deinit(mod: *Module) void {
|
||||
mod.test_functions.deinit(gpa);
|
||||
mod.align_stack_fns.deinit(gpa);
|
||||
mod.monomorphed_funcs.deinit(gpa);
|
||||
|
||||
{
|
||||
var it = mod.memoized_calls.iterator();
|
||||
while (it.next()) |entry| {
|
||||
gpa.free(entry.key_ptr.args);
|
||||
entry.value_ptr.arena.promote(gpa).deinit();
|
||||
}
|
||||
mod.memoized_calls.deinit(gpa);
|
||||
}
|
||||
mod.memoized_call_args.deinit(gpa);
|
||||
mod.memoized_calls.deinit(gpa);
|
||||
|
||||
mod.decls_free_list.deinit(gpa);
|
||||
mod.allocated_decls.deinit(gpa);
|
||||
@@ -5894,6 +5876,7 @@ pub fn initNewAnonDecl(
|
||||
typed_value: TypedValue,
|
||||
name: [:0]u8,
|
||||
) !void {
|
||||
assert(typed_value.ty.toIntern() == mod.intern_pool.typeOf(typed_value.val.toIntern()));
|
||||
errdefer mod.gpa.free(name);
|
||||
|
||||
const new_decl = mod.declPtr(new_decl_index);
|
||||
@@ -6645,7 +6628,7 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void {
|
||||
if (decl.alive) return;
|
||||
decl.alive = true;
|
||||
|
||||
decl.val = (try decl.val.intern(decl.ty, mod)).toValue();
|
||||
try decl.intern(mod);
|
||||
|
||||
// This is the first time we are marking this Decl alive. We must
|
||||
// therefore recurse into its value and mark any Decl it references
|
||||
@@ -6749,15 +6732,19 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type
|
||||
}
|
||||
}
|
||||
|
||||
// Canonicalize host_size. If it matches the bit size of the pointee type,
|
||||
// we change it to 0 here. If this causes an assertion trip, the pointee type
|
||||
// needs to be resolved before calling this ptr() function.
|
||||
if (info.host_size != 0) {
|
||||
const elem_bit_size = info.elem_type.toType().bitSize(mod);
|
||||
assert(info.bit_offset + elem_bit_size <= info.host_size * 8);
|
||||
if (info.host_size * 8 == elem_bit_size) {
|
||||
canon_info.host_size = 0;
|
||||
}
|
||||
switch (info.vector_index) {
|
||||
// Canonicalize host_size. If it matches the bit size of the pointee type,
|
||||
// we change it to 0 here. If this causes an assertion trip, the pointee type
|
||||
// needs to be resolved before calling this ptr() function.
|
||||
.none => if (info.host_size != 0) {
|
||||
const elem_bit_size = info.elem_type.toType().bitSize(mod);
|
||||
assert(info.bit_offset + elem_bit_size <= info.host_size * 8);
|
||||
if (info.host_size * 8 == elem_bit_size) {
|
||||
canon_info.host_size = 0;
|
||||
}
|
||||
},
|
||||
.runtime => {},
|
||||
_ => assert(@enumToInt(info.vector_index) < info.host_size),
|
||||
}
|
||||
|
||||
return (try intern(mod, .{ .ptr_type = canon_info })).toType();
|
||||
|
||||
+33
-25
@@ -1,18 +1,18 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Order = std.math.Order;
|
||||
|
||||
const RangeSet = @This();
|
||||
const InternPool = @import("InternPool.zig");
|
||||
const Module = @import("Module.zig");
|
||||
const RangeSet = @This();
|
||||
const SwitchProngSrc = @import("Module.zig").SwitchProngSrc;
|
||||
const Type = @import("type.zig").Type;
|
||||
const Value = @import("value.zig").Value;
|
||||
|
||||
ranges: std.ArrayList(Range),
|
||||
module: *Module,
|
||||
|
||||
pub const Range = struct {
|
||||
first: Value,
|
||||
last: Value,
|
||||
first: InternPool.Index,
|
||||
last: InternPool.Index,
|
||||
src: SwitchProngSrc,
|
||||
};
|
||||
|
||||
@@ -29,18 +29,27 @@ pub fn deinit(self: *RangeSet) void {
|
||||
|
||||
pub fn add(
|
||||
self: *RangeSet,
|
||||
first: Value,
|
||||
last: Value,
|
||||
ty: Type,
|
||||
first: InternPool.Index,
|
||||
last: InternPool.Index,
|
||||
src: SwitchProngSrc,
|
||||
) !?SwitchProngSrc {
|
||||
const mod = self.module;
|
||||
const ip = &mod.intern_pool;
|
||||
|
||||
const ty = ip.typeOf(first);
|
||||
assert(ty == ip.typeOf(last));
|
||||
|
||||
for (self.ranges.items) |range| {
|
||||
if (last.compareScalar(.gte, range.first, ty, self.module) and
|
||||
first.compareScalar(.lte, range.last, ty, self.module))
|
||||
assert(ty == ip.typeOf(range.first));
|
||||
assert(ty == ip.typeOf(range.last));
|
||||
|
||||
if (last.toValue().compareScalar(.gte, range.first.toValue(), ty.toType(), mod) and
|
||||
first.toValue().compareScalar(.lte, range.last.toValue(), ty.toType(), mod))
|
||||
{
|
||||
return range.src; // They overlap.
|
||||
}
|
||||
}
|
||||
|
||||
try self.ranges.append(.{
|
||||
.first = first,
|
||||
.last = last,
|
||||
@@ -49,30 +58,29 @@ pub fn add(
|
||||
return null;
|
||||
}
|
||||
|
||||
const LessThanContext = struct { ty: Type, module: *Module };
|
||||
|
||||
/// Assumes a and b do not overlap
|
||||
fn lessThan(ctx: LessThanContext, a: Range, b: Range) bool {
|
||||
return a.first.compareScalar(.lt, b.first, ctx.ty, ctx.module);
|
||||
fn lessThan(mod: *Module, a: Range, b: Range) bool {
|
||||
const ty = mod.intern_pool.typeOf(a.first).toType();
|
||||
return a.first.toValue().compareScalar(.lt, b.first.toValue(), ty, mod);
|
||||
}
|
||||
|
||||
pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool {
|
||||
pub fn spans(self: *RangeSet, first: InternPool.Index, last: InternPool.Index) !bool {
|
||||
const mod = self.module;
|
||||
const ip = &mod.intern_pool;
|
||||
assert(ip.typeOf(first) == ip.typeOf(last));
|
||||
|
||||
if (self.ranges.items.len == 0)
|
||||
return false;
|
||||
|
||||
const mod = self.module;
|
||||
std.mem.sort(Range, self.ranges.items, LessThanContext{
|
||||
.ty = ty,
|
||||
.module = mod,
|
||||
}, lessThan);
|
||||
std.mem.sort(Range, self.ranges.items, mod, lessThan);
|
||||
|
||||
if (!self.ranges.items[0].first.eql(first, ty, mod) or
|
||||
!self.ranges.items[self.ranges.items.len - 1].last.eql(last, ty, mod))
|
||||
if (self.ranges.items[0].first != first or
|
||||
self.ranges.items[self.ranges.items.len - 1].last != last)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var space: Value.BigIntSpace = undefined;
|
||||
var space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
|
||||
|
||||
var counter = try std.math.big.int.Managed.init(self.ranges.allocator);
|
||||
defer counter.deinit();
|
||||
@@ -83,10 +91,10 @@ pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool {
|
||||
const prev = self.ranges.items[i];
|
||||
|
||||
// prev.last + 1 == cur.first
|
||||
try counter.copy(prev.last.toBigInt(&space, mod));
|
||||
try counter.copy(prev.last.toValue().toBigInt(&space, mod));
|
||||
try counter.addScalar(&counter, 1);
|
||||
|
||||
const cur_start_int = cur.first.toBigInt(&space, mod);
|
||||
const cur_start_int = cur.first.toValue().toBigInt(&space, mod);
|
||||
if (!cur_start_int.eq(counter.toConst())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+335
-340
@@ -1609,7 +1609,7 @@ fn analyzeBodyInner(
|
||||
if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
|
||||
return err;
|
||||
};
|
||||
const inline_body = if (cond.val.toBool(mod)) then_body else else_body;
|
||||
const inline_body = if (cond.val.toBool()) then_body else else_body;
|
||||
|
||||
try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
|
||||
const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
|
||||
@@ -1630,7 +1630,7 @@ fn analyzeBodyInner(
|
||||
if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
|
||||
return err;
|
||||
};
|
||||
const inline_body = if (cond.val.toBool(mod)) then_body else else_body;
|
||||
const inline_body = if (cond.val.toBool()) then_body else else_body;
|
||||
|
||||
try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
|
||||
const old_runtime_index = block.runtime_index;
|
||||
@@ -1663,7 +1663,7 @@ fn analyzeBodyInner(
|
||||
if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
|
||||
return err;
|
||||
};
|
||||
if (is_non_err_val.toBool(mod)) {
|
||||
if (is_non_err_val.toBool()) {
|
||||
break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
|
||||
}
|
||||
const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
|
||||
@@ -1689,7 +1689,7 @@ fn analyzeBodyInner(
|
||||
if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
|
||||
return err;
|
||||
};
|
||||
if (is_non_err_val.toBool(mod)) {
|
||||
if (is_non_err_val.toBool()) {
|
||||
break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
|
||||
}
|
||||
const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
|
||||
@@ -1778,12 +1778,11 @@ fn resolveConstBool(
|
||||
zir_ref: Zir.Inst.Ref,
|
||||
reason: []const u8,
|
||||
) !bool {
|
||||
const mod = sema.mod;
|
||||
const air_inst = try sema.resolveInst(zir_ref);
|
||||
const wanted_type = Type.bool;
|
||||
const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
|
||||
const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
|
||||
return val.toBool(mod);
|
||||
return val.toBool();
|
||||
}
|
||||
|
||||
pub fn resolveConstString(
|
||||
@@ -2488,7 +2487,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
|
||||
defer anon_decl.deinit();
|
||||
const decl_index = try anon_decl.finish(
|
||||
pointee_ty,
|
||||
Value.undef,
|
||||
(try mod.intern(.{ .undef = pointee_ty.toIntern() })).toValue(),
|
||||
alignment.toByteUnits(0),
|
||||
);
|
||||
sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.decl_index = decl_index;
|
||||
@@ -2611,7 +2610,7 @@ fn coerceResultPtr(
|
||||
.@"addrspace" = addr_space,
|
||||
});
|
||||
if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
|
||||
new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val);
|
||||
new_ptr = try sema.addConstant(ptr_operand_ty, try mod.getCoerced(ptr_val, ptr_operand_ty));
|
||||
} else {
|
||||
new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
|
||||
}
|
||||
@@ -3613,7 +3612,7 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai
|
||||
|
||||
// Detect if a comptime value simply needs to have its type changed.
|
||||
if (try sema.resolveMaybeUndefVal(alloc)) |val| {
|
||||
return sema.addConstant(const_ptr_ty, val);
|
||||
return sema.addConstant(const_ptr_ty, try mod.getCoerced(val, const_ptr_ty));
|
||||
}
|
||||
|
||||
return block.addBitCast(const_ptr_ty, alloc);
|
||||
@@ -3735,6 +3734,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
|
||||
try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
|
||||
|
||||
const decl = mod.declPtr(decl_index);
|
||||
if (iac.is_const) try decl.intern(mod);
|
||||
const final_elem_ty = decl.ty;
|
||||
const final_ptr_ty = try mod.ptrType(.{
|
||||
.elem_type = final_elem_ty.toIntern(),
|
||||
@@ -3774,7 +3774,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
|
||||
// Detect if the value is comptime-known. In such case, the
|
||||
// last 3 AIR instructions of the block will look like this:
|
||||
//
|
||||
// %a = interned
|
||||
// %a = inferred_alloc
|
||||
// %b = bitcast(%a)
|
||||
// %c = store(%b, %d)
|
||||
//
|
||||
@@ -3814,22 +3814,22 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
|
||||
}
|
||||
};
|
||||
|
||||
const const_inst = while (true) {
|
||||
while (true) {
|
||||
if (search_index == 0) break :ct;
|
||||
search_index -= 1;
|
||||
|
||||
const candidate = block.instructions.items[search_index];
|
||||
if (candidate == ptr_inst) break;
|
||||
switch (air_tags[candidate]) {
|
||||
.dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
|
||||
.interned => break candidate,
|
||||
else => break :ct,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const store_op = air_datas[store_inst].bin_op;
|
||||
const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct;
|
||||
if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct;
|
||||
if (air_datas[bitcast_inst].ty_op.operand != Air.indexToRef(const_inst)) break :ct;
|
||||
if (air_datas[bitcast_inst].ty_op.operand != ptr) break :ct;
|
||||
|
||||
const new_decl_index = d: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
@@ -3850,7 +3850,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
|
||||
sema.air_instructions.set(ptr_inst, .{
|
||||
.tag = .interned,
|
||||
.data = .{ .interned = try mod.intern(.{ .ptr = .{
|
||||
.ty = final_elem_ty.toIntern(),
|
||||
.ty = final_ptr_ty.toIntern(),
|
||||
.addr = .{ .decl = new_decl_index },
|
||||
} }) },
|
||||
});
|
||||
@@ -4707,15 +4707,23 @@ fn zirValidateArrayInit(
|
||||
return;
|
||||
}
|
||||
|
||||
// If the array has one possible value, the value is always comptime-known.
|
||||
if (try sema.typeHasOnePossibleValue(array_ty)) |array_opv| {
|
||||
const array_init = try sema.addConstant(array_ty, array_opv);
|
||||
try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
|
||||
return;
|
||||
}
|
||||
|
||||
var array_is_comptime = true;
|
||||
var first_block_index = block.instructions.items.len;
|
||||
var make_runtime = false;
|
||||
|
||||
// Collect the comptime element values in case the array literal ends up
|
||||
// being comptime-known.
|
||||
const array_len_s = try sema.usizeCast(block, init_src, array_ty.arrayLenIncludingSentinel(mod));
|
||||
const element_vals = try sema.arena.alloc(InternPool.Index, array_len_s);
|
||||
const opt_opv = try sema.typeHasOnePossibleValue(array_ty);
|
||||
const element_vals = try sema.arena.alloc(
|
||||
InternPool.Index,
|
||||
try sema.usizeCast(block, init_src, array_len),
|
||||
);
|
||||
const air_tags = sema.air_instructions.items(.tag);
|
||||
const air_datas = sema.air_instructions.items(.data);
|
||||
|
||||
@@ -4727,12 +4735,6 @@ fn zirValidateArrayInit(
|
||||
element_vals[i] = opv.toIntern();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Array has one possible value, so value is always comptime-known
|
||||
if (opt_opv) |opv| {
|
||||
element_vals[i] = opv.toIntern();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
|
||||
@@ -4814,11 +4816,6 @@ fn zirValidateArrayInit(
|
||||
|
||||
// Our task is to delete all the `elem_ptr` and `store` instructions, and insert
|
||||
// instead a single `store` to the array_ptr with a comptime struct value.
|
||||
// Also to populate the sentinel value, if any.
|
||||
if (array_ty.sentinel(mod)) |sentinel_val| {
|
||||
element_vals[instrs.len] = sentinel_val.toIntern();
|
||||
}
|
||||
|
||||
block.instructions.shrinkRetainingCapacity(first_block_index);
|
||||
|
||||
var array_val = try mod.intern(.{ .aggregate = .{
|
||||
@@ -6259,7 +6256,7 @@ fn popErrorReturnTrace(
|
||||
if (operand != .none) {
|
||||
is_non_error_inst = try sema.analyzeIsNonErr(block, src, operand);
|
||||
if (try sema.resolveDefinedValue(block, src, is_non_error_inst)) |cond_val|
|
||||
is_non_error = cond_val.toBool(mod);
|
||||
is_non_error = cond_val.toBool();
|
||||
} else is_non_error = true; // no operand means pop unconditionally
|
||||
|
||||
if (is_non_error == true) {
|
||||
@@ -6873,14 +6870,15 @@ fn analyzeCall(
|
||||
|
||||
// If it's a comptime function call, we need to memoize it as long as no external
|
||||
// comptime memory is mutated.
|
||||
var memoized_call_key: Module.MemoizedCall.Key = undefined;
|
||||
var memoized_call_key = Module.MemoizedCall.Key{
|
||||
.func = module_fn_index,
|
||||
.args_index = @intCast(u32, mod.memoized_call_args.items.len),
|
||||
.args_count = @intCast(u32, func_ty_info.param_types.len),
|
||||
};
|
||||
var delete_memoized_call_key = false;
|
||||
defer if (delete_memoized_call_key) gpa.free(memoized_call_key.args);
|
||||
defer if (delete_memoized_call_key) mod.memoized_call_args.shrinkRetainingCapacity(memoized_call_key.args_index);
|
||||
if (is_comptime_call) {
|
||||
memoized_call_key = .{
|
||||
.func = module_fn_index,
|
||||
.args = try gpa.alloc(TypedValue, func_ty_info.param_types.len),
|
||||
};
|
||||
try mod.memoized_call_args.ensureUnusedCapacity(gpa, memoized_call_key.args_count);
|
||||
delete_memoized_call_key = true;
|
||||
}
|
||||
|
||||
@@ -6916,8 +6914,7 @@ fn analyzeCall(
|
||||
uncasted_args,
|
||||
is_comptime_call,
|
||||
&should_memoize,
|
||||
memoized_call_key,
|
||||
func_ty_info.param_types,
|
||||
mod.typeToFunc(func_ty).?.param_types,
|
||||
func,
|
||||
&has_comptime_args,
|
||||
) catch |err| switch (err) {
|
||||
@@ -6934,8 +6931,7 @@ fn analyzeCall(
|
||||
uncasted_args,
|
||||
is_comptime_call,
|
||||
&should_memoize,
|
||||
memoized_call_key,
|
||||
func_ty_info.param_types,
|
||||
mod.typeToFunc(func_ty).?.param_types,
|
||||
func,
|
||||
&has_comptime_args,
|
||||
);
|
||||
@@ -6988,9 +6984,19 @@ fn analyzeCall(
|
||||
// bug generating invalid LLVM IR.
|
||||
const res2: Air.Inst.Ref = res2: {
|
||||
if (should_memoize and is_comptime_call) {
|
||||
if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| {
|
||||
break :res2 try sema.addConstant(fn_ret_ty, result.val);
|
||||
const gop = try mod.memoized_calls.getOrPutContext(
|
||||
gpa,
|
||||
memoized_call_key,
|
||||
.{ .args = &mod.memoized_call_args },
|
||||
);
|
||||
if (gop.found_existing) {
|
||||
// We need to use the original memoized error set instead of fn_ret_ty.
|
||||
const result = gop.value_ptr.*;
|
||||
assert(result != .none); // recursive memoization?
|
||||
break :res2 try sema.addConstant(mod.intern_pool.typeOf(result).toType(), result.toValue());
|
||||
}
|
||||
gop.value_ptr.* = .none;
|
||||
delete_memoized_call_key = false;
|
||||
}
|
||||
|
||||
const new_func_resolved_ty = try mod.funcType(new_fn_info);
|
||||
@@ -7049,26 +7055,10 @@ fn analyzeCall(
|
||||
|
||||
if (should_memoize and is_comptime_call) {
|
||||
const result_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, result, "");
|
||||
|
||||
// TODO: check whether any external comptime memory was mutated by the
|
||||
// comptime function call. If so, then do not memoize the call here.
|
||||
// TODO: re-evaluate whether memoized_calls needs its own arena. I think
|
||||
// it should be fine to use the Decl arena for the function.
|
||||
{
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
errdefer arena_allocator.deinit();
|
||||
const arena = arena_allocator.allocator();
|
||||
|
||||
for (memoized_call_key.args) |*arg| {
|
||||
arg.* = try arg.*.copy(arena);
|
||||
}
|
||||
|
||||
try mod.memoized_calls.putContext(gpa, memoized_call_key, .{
|
||||
.val = try result_val.copy(arena),
|
||||
.arena = arena_allocator.state,
|
||||
}, .{ .module = mod });
|
||||
delete_memoized_call_key = false;
|
||||
}
|
||||
mod.memoized_calls.getPtrContext(
|
||||
memoized_call_key,
|
||||
.{ .args = &mod.memoized_call_args },
|
||||
).?.* = try result_val.intern(fn_ret_ty, mod);
|
||||
}
|
||||
|
||||
break :res2 result;
|
||||
@@ -7214,11 +7204,11 @@ fn analyzeInlineCallArg(
|
||||
uncasted_args: []const Air.Inst.Ref,
|
||||
is_comptime_call: bool,
|
||||
should_memoize: *bool,
|
||||
memoized_call_key: Module.MemoizedCall.Key,
|
||||
raw_param_types: []const InternPool.Index,
|
||||
func_inst: Air.Inst.Ref,
|
||||
has_comptime_args: *bool,
|
||||
) !void {
|
||||
const mod = sema.mod;
|
||||
const zir_tags = sema.code.instructions.items(.tag);
|
||||
switch (zir_tags[inst]) {
|
||||
.param_comptime, .param_anytype_comptime => has_comptime_args.* = true,
|
||||
@@ -7276,11 +7266,8 @@ fn analyzeInlineCallArg(
|
||||
try sema.resolveLazyValue(arg_val);
|
||||
},
|
||||
}
|
||||
should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(sema.mod);
|
||||
memoized_call_key.args[arg_i.*] = .{
|
||||
.ty = param_ty.toType(),
|
||||
.val = arg_val,
|
||||
};
|
||||
should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(mod);
|
||||
mod.memoized_call_args.appendAssumeCapacity(try arg_val.intern(param_ty.toType(), mod));
|
||||
} else {
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
|
||||
}
|
||||
@@ -7315,11 +7302,8 @@ fn analyzeInlineCallArg(
|
||||
try sema.resolveLazyValue(arg_val);
|
||||
},
|
||||
}
|
||||
should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(sema.mod);
|
||||
memoized_call_key.args[arg_i.*] = .{
|
||||
.ty = sema.typeOf(uncasted_arg),
|
||||
.val = arg_val,
|
||||
};
|
||||
should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(mod);
|
||||
mod.memoized_call_args.appendAssumeCapacity(try arg_val.intern(sema.typeOf(uncasted_arg), mod));
|
||||
} else {
|
||||
if (zir_tags[inst] == .param_anytype_comptime) {
|
||||
_ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
|
||||
@@ -8279,7 +8263,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
const int_tag_ty = try enum_tag_ty.intTagType(mod);
|
||||
|
||||
if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| {
|
||||
return sema.addConstant(int_tag_ty, opv);
|
||||
return sema.addConstant(int_tag_ty, try mod.getCoerced(opv, int_tag_ty));
|
||||
}
|
||||
|
||||
if (try sema.resolveMaybeUndefVal(enum_tag)) |enum_tag_val| {
|
||||
@@ -8310,7 +8294,10 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
if (dest_ty.isNonexhaustiveEnum(mod)) {
|
||||
const int_tag_ty = try dest_ty.intTagType(mod);
|
||||
if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
|
||||
return sema.addConstant(dest_ty, int_val);
|
||||
return sema.addConstant(dest_ty, (try mod.intern(.{ .enum_tag = .{
|
||||
.ty = dest_ty.toIntern(),
|
||||
.int = int_val.toIntern(),
|
||||
} })).toValue());
|
||||
}
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(
|
||||
@@ -8657,8 +8644,10 @@ fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air
|
||||
const result_ty = operand_ty.errorUnionSet(mod);
|
||||
|
||||
if (try sema.resolveDefinedValue(block, src, operand)) |val| {
|
||||
assert(val.getError(mod) != null);
|
||||
return sema.addConstant(result_ty, val);
|
||||
return sema.addConstant(result_ty, (try mod.intern(.{ .err = .{
|
||||
.ty = result_ty.toIntern(),
|
||||
.name = mod.intern_pool.indexToKey(val.toIntern()).error_union.val.err_name,
|
||||
} })).toValue());
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src, null);
|
||||
@@ -10737,7 +10726,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
block,
|
||||
&range_set,
|
||||
item_ref,
|
||||
operand_ty,
|
||||
src_node_offset,
|
||||
.{ .scalar = scalar_i },
|
||||
);
|
||||
@@ -10760,7 +10748,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
block,
|
||||
&range_set,
|
||||
item_ref,
|
||||
operand_ty,
|
||||
src_node_offset,
|
||||
.{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
|
||||
);
|
||||
@@ -10778,7 +10765,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
&range_set,
|
||||
item_first,
|
||||
item_last,
|
||||
operand_ty,
|
||||
src_node_offset,
|
||||
.{ .range = .{ .prong = multi_i, .item = range_i } },
|
||||
);
|
||||
@@ -10792,7 +10778,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
if (operand_ty.zigTypeTag(mod) == .Int) {
|
||||
const min_int = try operand_ty.minInt(mod, operand_ty);
|
||||
const max_int = try operand_ty.maxInt(mod, operand_ty);
|
||||
if (try range_set.spans(min_int, max_int, operand_ty)) {
|
||||
if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) {
|
||||
if (special_prong == .@"else") {
|
||||
return sema.fail(
|
||||
block,
|
||||
@@ -10894,11 +10880,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
);
|
||||
}
|
||||
|
||||
var seen_values = ValueSrcMap.initContext(gpa, .{
|
||||
.ty = operand_ty,
|
||||
.mod = mod,
|
||||
});
|
||||
defer seen_values.deinit();
|
||||
var seen_values = ValueSrcMap{};
|
||||
defer seen_values.deinit(gpa);
|
||||
|
||||
var extra_index: usize = special.end;
|
||||
{
|
||||
@@ -11664,10 +11647,10 @@ const RangeSetUnhandledIterator = struct {
|
||||
it.cur = try it.sema.intAddScalar(it.cur, try it.sema.mod.intValue(it.ty, 1), it.ty);
|
||||
}
|
||||
it.first = false;
|
||||
if (it.cur.compareScalar(.lt, it.ranges[it.range_i].first, it.ty, it.sema.mod)) {
|
||||
if (it.cur.compareScalar(.lt, it.ranges[it.range_i].first.toValue(), it.ty, it.sema.mod)) {
|
||||
return it.cur;
|
||||
}
|
||||
it.cur = it.ranges[it.range_i].last;
|
||||
it.cur = it.ranges[it.range_i].last.toValue();
|
||||
}
|
||||
if (!it.first) {
|
||||
it.cur = try it.sema.intAddScalar(it.cur, try it.sema.mod.intValue(it.ty, 1), it.ty);
|
||||
@@ -11687,16 +11670,15 @@ fn resolveSwitchItemVal(
|
||||
switch_node_offset: i32,
|
||||
switch_prong_src: Module.SwitchProngSrc,
|
||||
range_expand: Module.SwitchProngSrc.RangeExpand,
|
||||
) CompileError!TypedValue {
|
||||
) CompileError!InternPool.Index {
|
||||
const mod = sema.mod;
|
||||
const item = try sema.resolveInst(item_ref);
|
||||
const item_ty = sema.typeOf(item);
|
||||
// Constructing a LazySrcLoc is costly because we only have the switch AST node.
|
||||
// Only if we know for sure we need to report a compile error do we resolve the
|
||||
// full source locations.
|
||||
if (sema.resolveConstValue(block, .unneeded, item, "")) |val| {
|
||||
try sema.resolveLazyValue(val);
|
||||
return TypedValue{ .ty = item_ty, .val = val };
|
||||
return val.toIntern();
|
||||
} else |err| switch (err) {
|
||||
error.NeededSourceLocation => {
|
||||
const src = switch_prong_src.resolve(mod, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand);
|
||||
@@ -11713,18 +11695,17 @@ fn validateSwitchRange(
|
||||
range_set: *RangeSet,
|
||||
first_ref: Zir.Inst.Ref,
|
||||
last_ref: Zir.Inst.Ref,
|
||||
operand_ty: Type,
|
||||
src_node_offset: i32,
|
||||
switch_prong_src: Module.SwitchProngSrc,
|
||||
) CompileError!void {
|
||||
const mod = sema.mod;
|
||||
const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
|
||||
const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
|
||||
if (first_val.compareScalar(.gt, last_val, operand_ty, mod)) {
|
||||
const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
|
||||
const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
|
||||
if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) {
|
||||
const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first);
|
||||
return sema.fail(block, src, "range start value is greater than the end value", .{});
|
||||
}
|
||||
const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src);
|
||||
const maybe_prev_src = try range_set.add(first, last, switch_prong_src);
|
||||
return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
|
||||
}
|
||||
|
||||
@@ -11733,12 +11714,11 @@ fn validateSwitchItem(
|
||||
block: *Block,
|
||||
range_set: *RangeSet,
|
||||
item_ref: Zir.Inst.Ref,
|
||||
operand_ty: Type,
|
||||
src_node_offset: i32,
|
||||
switch_prong_src: Module.SwitchProngSrc,
|
||||
) CompileError!void {
|
||||
const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
|
||||
const maybe_prev_src = try range_set.add(item_val, item_val, operand_ty, switch_prong_src);
|
||||
const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
|
||||
const maybe_prev_src = try range_set.add(item, item, switch_prong_src);
|
||||
return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
|
||||
}
|
||||
|
||||
@@ -11751,9 +11731,11 @@ fn validateSwitchItemEnum(
|
||||
src_node_offset: i32,
|
||||
switch_prong_src: Module.SwitchProngSrc,
|
||||
) CompileError!void {
|
||||
const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
|
||||
const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse {
|
||||
const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src);
|
||||
const ip = &sema.mod.intern_pool;
|
||||
const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
|
||||
const int = ip.indexToKey(item).enum_tag.int;
|
||||
const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse {
|
||||
const maybe_prev_src = try range_set.add(int, int, switch_prong_src);
|
||||
return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
|
||||
};
|
||||
const maybe_prev_src = seen_fields[field_index];
|
||||
@@ -11770,9 +11752,9 @@ fn validateSwitchItemError(
|
||||
switch_prong_src: Module.SwitchProngSrc,
|
||||
) CompileError!void {
|
||||
const ip = &sema.mod.intern_pool;
|
||||
const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
|
||||
const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
|
||||
// TODO: Do i need to typecheck here?
|
||||
const error_name = ip.stringToSlice(ip.indexToKey(item_tv.val.toIntern()).err.name);
|
||||
const error_name = ip.stringToSlice(ip.indexToKey(item).err.name);
|
||||
const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
|
||||
prev.value
|
||||
else
|
||||
@@ -11822,8 +11804,8 @@ fn validateSwitchItemBool(
|
||||
switch_prong_src: Module.SwitchProngSrc,
|
||||
) CompileError!void {
|
||||
const mod = sema.mod;
|
||||
const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
|
||||
if (item_val.toBool(mod)) {
|
||||
const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
|
||||
if (item.toValue().toBool()) {
|
||||
true_count.* += 1;
|
||||
} else {
|
||||
false_count.* += 1;
|
||||
@@ -11835,7 +11817,7 @@ fn validateSwitchItemBool(
|
||||
}
|
||||
}
|
||||
|
||||
const ValueSrcMap = std.HashMap(Value, Module.SwitchProngSrc, Value.HashContext, std.hash_map.default_max_load_percentage);
|
||||
const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc);
|
||||
|
||||
fn validateSwitchItemSparse(
|
||||
sema: *Sema,
|
||||
@@ -11845,8 +11827,8 @@ fn validateSwitchItemSparse(
|
||||
src_node_offset: i32,
|
||||
switch_prong_src: Module.SwitchProngSrc,
|
||||
) CompileError!void {
|
||||
const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
|
||||
const kv = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
|
||||
const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
|
||||
const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return;
|
||||
return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
|
||||
}
|
||||
|
||||
@@ -13047,8 +13029,6 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
|
||||
|
||||
if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {
|
||||
const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null);
|
||||
|
||||
const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))
|
||||
(try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
|
||||
else
|
||||
@@ -13065,7 +13045,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
} });
|
||||
}
|
||||
|
||||
const element_vals = try sema.arena.alloc(InternPool.Index, final_len_including_sent);
|
||||
const element_vals = try sema.arena.alloc(InternPool.Index, result_len);
|
||||
var elem_i: usize = 0;
|
||||
while (elem_i < result_len) {
|
||||
var lhs_i: usize = 0;
|
||||
@@ -13075,9 +13055,6 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
elem_i += 1;
|
||||
}
|
||||
}
|
||||
if (lhs_info.sentinel) |sent_val| {
|
||||
element_vals[result_len] = sent_val.toIntern();
|
||||
}
|
||||
break :v try mod.intern(.{ .aggregate = .{
|
||||
.ty = result_ty.toIntern(),
|
||||
.storage = .{ .elems = element_vals },
|
||||
@@ -14896,13 +14873,18 @@ fn analyzeArithmetic(
|
||||
.ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
|
||||
else => unreachable,
|
||||
};
|
||||
const scalar_one = switch (scalar_tag) {
|
||||
.ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
|
||||
.ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
|
||||
else => unreachable,
|
||||
};
|
||||
if (maybe_lhs_val) |lhs_val| {
|
||||
if (!lhs_val.isUndef(mod)) {
|
||||
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
|
||||
const zero_val = try sema.splat(resolved_type, scalar_zero);
|
||||
return sema.addConstant(resolved_type, zero_val);
|
||||
}
|
||||
if (try sema.compareAll(lhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) {
|
||||
if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
|
||||
return casted_rhs;
|
||||
}
|
||||
}
|
||||
@@ -14916,7 +14898,7 @@ fn analyzeArithmetic(
|
||||
const zero_val = try sema.splat(resolved_type, scalar_zero);
|
||||
return sema.addConstant(resolved_type, zero_val);
|
||||
}
|
||||
if (try sema.compareAll(rhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) {
|
||||
if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
|
||||
return casted_lhs;
|
||||
}
|
||||
if (maybe_lhs_val) |lhs_val| {
|
||||
@@ -15524,7 +15506,7 @@ fn cmpSelf(
|
||||
} else {
|
||||
if (resolved_type.zigTypeTag(mod) == .Bool) {
|
||||
// We can lower bool eq/neq more efficiently.
|
||||
return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(mod), rhs_src);
|
||||
return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src);
|
||||
}
|
||||
break :src rhs_src;
|
||||
}
|
||||
@@ -15534,7 +15516,7 @@ fn cmpSelf(
|
||||
if (resolved_type.zigTypeTag(mod) == .Bool) {
|
||||
if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
|
||||
if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
|
||||
return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(mod), lhs_src);
|
||||
return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src);
|
||||
}
|
||||
}
|
||||
break :src lhs_src;
|
||||
@@ -15840,6 +15822,7 @@ fn zirBuiltinSrc(
|
||||
break :blk try mod.intern(.{ .ptr = .{
|
||||
.ty = .slice_const_u8_sentinel_0_type,
|
||||
.addr = .{ .decl = new_decl },
|
||||
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
|
||||
} });
|
||||
};
|
||||
|
||||
@@ -15864,6 +15847,7 @@ fn zirBuiltinSrc(
|
||||
break :blk try mod.intern(.{ .ptr = .{
|
||||
.ty = .slice_const_u8_sentinel_0_type,
|
||||
.addr = .{ .decl = new_decl },
|
||||
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
|
||||
} });
|
||||
};
|
||||
|
||||
@@ -16314,6 +16298,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
break :v try mod.intern(.{ .ptr = .{
|
||||
.ty = slice_errors_ty.toIntern(),
|
||||
.addr = .{ .decl = new_decl },
|
||||
.len = (try mod.intValue(Type.usize, vals.len)).toIntern(),
|
||||
} });
|
||||
} else .none;
|
||||
const errors_val = try mod.intern(.{ .opt = .{
|
||||
@@ -16438,6 +16423,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
.is_const = true,
|
||||
})).toIntern(),
|
||||
.addr = .{ .decl = new_decl },
|
||||
.len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),
|
||||
} });
|
||||
};
|
||||
|
||||
@@ -17141,7 +17127,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
if (try sema.resolveMaybeUndefVal(operand)) |val| {
|
||||
return if (val.isUndef(mod))
|
||||
sema.addConstUndef(Type.bool)
|
||||
else if (val.toBool(mod))
|
||||
else if (val.toBool())
|
||||
Air.Inst.Ref.bool_false
|
||||
else
|
||||
Air.Inst.Ref.bool_true;
|
||||
@@ -17169,9 +17155,9 @@ fn zirBoolBr(
|
||||
const gpa = sema.gpa;
|
||||
|
||||
if (try sema.resolveDefinedValue(parent_block, lhs_src, lhs)) |lhs_val| {
|
||||
if (is_bool_or and lhs_val.toBool(mod)) {
|
||||
if (is_bool_or and lhs_val.toBool()) {
|
||||
return Air.Inst.Ref.bool_true;
|
||||
} else if (!is_bool_or and !lhs_val.toBool(mod)) {
|
||||
} else if (!is_bool_or and !lhs_val.toBool()) {
|
||||
return Air.Inst.Ref.bool_false;
|
||||
}
|
||||
// comptime-known left-hand side. No need for a block here; the result
|
||||
@@ -17215,9 +17201,9 @@ fn zirBoolBr(
|
||||
const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
|
||||
if (!sema.typeOf(rhs_result).isNoReturn(mod)) {
|
||||
if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| {
|
||||
if (is_bool_or and rhs_val.toBool(mod)) {
|
||||
if (is_bool_or and rhs_val.toBool()) {
|
||||
return Air.Inst.Ref.bool_true;
|
||||
} else if (!is_bool_or and !rhs_val.toBool(mod)) {
|
||||
} else if (!is_bool_or and !rhs_val.toBool()) {
|
||||
return Air.Inst.Ref.bool_false;
|
||||
}
|
||||
}
|
||||
@@ -17371,7 +17357,7 @@ fn zirCondbr(
|
||||
const cond = try sema.coerce(parent_block, Type.bool, uncasted_cond, cond_src);
|
||||
|
||||
if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| {
|
||||
const body = if (cond_val.toBool(mod)) then_body else else_body;
|
||||
const body = if (cond_val.toBool()) then_body else else_body;
|
||||
|
||||
try sema.maybeErrorUnwrapCondbr(parent_block, body, extra.data.condition, cond_src);
|
||||
// We use `analyzeBodyInner` since we want to propagate any possible
|
||||
@@ -17444,7 +17430,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
|
||||
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
|
||||
if (is_non_err != .none) {
|
||||
const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
|
||||
if (is_non_err_val.toBool(mod)) {
|
||||
if (is_non_err_val.toBool()) {
|
||||
return sema.analyzeErrUnionPayload(parent_block, src, err_union_ty, err_union, operand_src, false);
|
||||
}
|
||||
// We can analyze the body directly in the parent block because we know there are
|
||||
@@ -17491,7 +17477,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
|
||||
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
|
||||
if (is_non_err != .none) {
|
||||
const is_non_err_val = (try sema.resolveDefinedValue(parent_block, operand_src, is_non_err)).?;
|
||||
if (is_non_err_val.toBool(mod)) {
|
||||
if (is_non_err_val.toBool()) {
|
||||
return sema.analyzeErrUnionPayloadPtr(parent_block, src, operand, false, false);
|
||||
}
|
||||
// We can analyze the body directly in the parent block because we know there are
|
||||
@@ -18858,7 +18844,7 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
const operand = try sema.resolveInst(inst_data.operand);
|
||||
if (try sema.resolveMaybeUndefVal(operand)) |val| {
|
||||
if (val.isUndef(mod)) return sema.addConstUndef(Type.u1);
|
||||
if (val.toBool(mod)) return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 1));
|
||||
if (val.toBool()) return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 1));
|
||||
return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0));
|
||||
}
|
||||
return block.addUnOp(.bool_to_int, operand);
|
||||
@@ -19171,12 +19157,12 @@ fn zirReify(
|
||||
|
||||
const ty = try mod.ptrType(.{
|
||||
.size = ptr_size,
|
||||
.is_const = is_const_val.toBool(mod),
|
||||
.is_volatile = is_volatile_val.toBool(mod),
|
||||
.is_const = is_const_val.toBool(),
|
||||
.is_volatile = is_volatile_val.toBool(),
|
||||
.alignment = abi_align,
|
||||
.address_space = mod.toEnum(std.builtin.AddressSpace, address_space_val),
|
||||
.elem_type = elem_ty.toIntern(),
|
||||
.is_allowzero = is_allowzero_val.toBool(mod),
|
||||
.is_allowzero = is_allowzero_val.toBool(),
|
||||
.sentinel = actual_sentinel,
|
||||
});
|
||||
return sema.addType(ty);
|
||||
@@ -19267,7 +19253,7 @@ fn zirReify(
|
||||
return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
|
||||
}
|
||||
|
||||
return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool(mod));
|
||||
return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
|
||||
},
|
||||
.Enum => {
|
||||
const fields = ip.typeOf(union_val.val).toType().structFields(mod);
|
||||
@@ -19305,7 +19291,7 @@ fn zirReify(
|
||||
.namespace = .none,
|
||||
.fields_len = fields_len,
|
||||
.has_values = true,
|
||||
.tag_mode = if (!is_exhaustive_val.toBool(mod))
|
||||
.tag_mode = if (!is_exhaustive_val.toBool())
|
||||
.nonexhaustive
|
||||
else
|
||||
.explicit,
|
||||
@@ -19619,12 +19605,12 @@ fn zirReify(
|
||||
const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("return_type").?);
|
||||
const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("params").?);
|
||||
|
||||
const is_generic = is_generic_val.toBool(mod);
|
||||
const is_generic = is_generic_val.toBool();
|
||||
if (is_generic) {
|
||||
return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{});
|
||||
}
|
||||
|
||||
const is_var_args = is_var_args_val.toBool(mod);
|
||||
const is_var_args = is_var_args_val.toBool();
|
||||
const cc = mod.toEnum(std.builtin.CallingConvention, calling_convention_val);
|
||||
if (is_var_args and cc != .C) {
|
||||
return sema.fail(block, src, "varargs functions must have C calling convention", .{});
|
||||
@@ -19653,9 +19639,9 @@ fn zirReify(
|
||||
const arg_val = arg.castTag(.aggregate).?.data;
|
||||
// TODO use reflection instead of magic numbers here
|
||||
// is_generic: bool,
|
||||
const arg_is_generic = arg_val[0].toBool(mod);
|
||||
const arg_is_generic = arg_val[0].toBool();
|
||||
// is_noalias: bool,
|
||||
const arg_is_noalias = arg_val[1].toBool(mod);
|
||||
const arg_is_noalias = arg_val[1].toBool();
|
||||
// type: ?type,
|
||||
const param_type_opt_val = arg_val[2];
|
||||
|
||||
@@ -19783,9 +19769,9 @@ fn reifyStruct(
|
||||
|
||||
if (layout == .Packed) {
|
||||
if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
|
||||
if (is_comptime_val.toBool(mod)) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
|
||||
if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
|
||||
}
|
||||
if (layout == .Extern and is_comptime_val.toBool(mod)) {
|
||||
if (layout == .Extern and is_comptime_val.toBool()) {
|
||||
return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
|
||||
}
|
||||
|
||||
@@ -19827,7 +19813,7 @@ fn reifyStruct(
|
||||
opt_val;
|
||||
break :blk try payload_val.copy(new_decl_arena_allocator);
|
||||
} else Value.@"unreachable";
|
||||
if (is_comptime_val.toBool(mod) and default_val.toIntern() == .unreachable_value) {
|
||||
if (is_comptime_val.toBool() and default_val.toIntern() == .unreachable_value) {
|
||||
return sema.fail(block, src, "comptime field without default initialization value", .{});
|
||||
}
|
||||
|
||||
@@ -19836,7 +19822,7 @@ fn reifyStruct(
|
||||
.ty = field_ty,
|
||||
.abi_align = abi_align,
|
||||
.default_val = default_val,
|
||||
.is_comptime = is_comptime_val.toBool(mod),
|
||||
.is_comptime = is_comptime_val.toBool(),
|
||||
.offset = undefined,
|
||||
};
|
||||
|
||||
@@ -20400,13 +20386,17 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) {
|
||||
return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
|
||||
}
|
||||
if (dest_ty.zigTypeTag(mod) == .Optional and sema.typeOf(ptr).zigTypeTag(mod) != .Optional) {
|
||||
return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{
|
||||
.ty = dest_ty.toIntern(),
|
||||
.val = operand_val.toIntern(),
|
||||
} })).toValue());
|
||||
}
|
||||
return sema.addConstant(aligned_dest_ty, try mod.getCoerced(operand_val, aligned_dest_ty));
|
||||
return sema.addConstant(aligned_dest_ty, try mod.getCoerced(switch (mod.intern_pool.indexToKey(operand_val.toIntern())) {
|
||||
.undef, .ptr => operand_val,
|
||||
.opt => |opt| switch (opt.val) {
|
||||
.none => if (dest_ty.ptrAllowsZero(mod))
|
||||
Value.zero_usize
|
||||
else
|
||||
return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}),
|
||||
else => opt.val.toValue(),
|
||||
},
|
||||
else => unreachable,
|
||||
}, aligned_dest_ty));
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src, null);
|
||||
@@ -20534,10 +20524,10 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
if (try sema.resolveMaybeUndefValIntable(operand)) |val| {
|
||||
if (val.isUndef(mod)) return sema.addConstUndef(dest_ty);
|
||||
if (!is_vector) {
|
||||
return sema.addConstant(
|
||||
dest_ty,
|
||||
return sema.addConstant(dest_ty, try mod.getCoerced(
|
||||
try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, mod),
|
||||
);
|
||||
dest_ty,
|
||||
));
|
||||
}
|
||||
const elems = try sema.arena.alloc(InternPool.Index, operand_ty.vectorLen(mod));
|
||||
for (elems, 0..) |*elem, i| {
|
||||
@@ -21410,7 +21400,10 @@ fn zirCmpxchg(
|
||||
|
||||
// special case zero bit types
|
||||
if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) {
|
||||
return sema.addConstant(result_ty, Value.null);
|
||||
return sema.addConstant(result_ty, (try mod.intern(.{ .opt = .{
|
||||
.ty = result_ty.toIntern(),
|
||||
.val = .none,
|
||||
} })).toValue());
|
||||
}
|
||||
|
||||
const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
|
||||
@@ -21633,8 +21626,7 @@ fn analyzeShuffle(
|
||||
.{ b_len, b_src, b_ty },
|
||||
};
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < mask_len) : (i += 1) {
|
||||
for (0..@intCast(usize, mask_len)) |i| {
|
||||
const elem = try mask.elemValue(sema.mod, i);
|
||||
if (elem.isUndef(mod)) continue;
|
||||
const int = elem.toSignedInt(mod);
|
||||
@@ -21670,7 +21662,7 @@ fn analyzeShuffle(
|
||||
if (try sema.resolveMaybeUndefVal(a)) |a_val| {
|
||||
if (try sema.resolveMaybeUndefVal(b)) |b_val| {
|
||||
const values = try sema.arena.alloc(InternPool.Index, mask_len);
|
||||
for (values) |*value| {
|
||||
for (values, 0..) |*value, i| {
|
||||
const mask_elem_val = try mask.elemValue(sema.mod, i);
|
||||
if (mask_elem_val.isUndef(mod)) {
|
||||
value.* = try mod.intern(.{ .undef = elem_ty.toIntern() });
|
||||
@@ -21698,11 +21690,10 @@ fn analyzeShuffle(
|
||||
const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len));
|
||||
|
||||
const expand_mask_values = try sema.arena.alloc(InternPool.Index, max_len);
|
||||
i = 0;
|
||||
while (i < min_len) : (i += 1) {
|
||||
for (@intCast(usize, 0)..@intCast(usize, min_len)) |i| {
|
||||
expand_mask_values[i] = (try mod.intValue(Type.comptime_int, i)).toIntern();
|
||||
}
|
||||
while (i < max_len) : (i += 1) {
|
||||
for (@intCast(usize, min_len)..@intCast(usize, max_len)) |i| {
|
||||
expand_mask_values[i] = (try mod.intValue(Type.comptime_int, -1)).toIntern();
|
||||
}
|
||||
const expand_mask = try mod.intern(.{ .aggregate = .{
|
||||
@@ -21783,7 +21774,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
|
||||
const elems = try sema.gpa.alloc(InternPool.Index, vec_len);
|
||||
for (elems, 0..) |*elem, i| {
|
||||
const pred_elem_val = try pred_val.elemValue(mod, i);
|
||||
const should_choose_a = pred_elem_val.toBool(mod);
|
||||
const should_choose_a = pred_elem_val.toBool();
|
||||
elem.* = try (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).intern(elem_ty, mod);
|
||||
}
|
||||
|
||||
@@ -22853,15 +22844,15 @@ fn zirVarExtended(
|
||||
else
|
||||
uncasted_init;
|
||||
|
||||
break :blk (try sema.resolveMaybeUndefVal(init)) orelse
|
||||
return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known");
|
||||
} else Value.@"unreachable";
|
||||
break :blk ((try sema.resolveMaybeUndefVal(init)) orelse
|
||||
return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known")).toIntern();
|
||||
} else .none;
|
||||
|
||||
try sema.validateVarType(block, ty_src, var_ty, small.is_extern);
|
||||
|
||||
return sema.addConstant(var_ty, (try mod.intern(.{ .variable = .{
|
||||
.ty = var_ty.toIntern(),
|
||||
.init = init_val.toIntern(),
|
||||
.init = init_val,
|
||||
.decl = sema.owner_decl_index,
|
||||
.lib_name = if (lib_name) |lname| (try mod.intern_pool.getOrPutString(
|
||||
sema.gpa,
|
||||
@@ -23284,7 +23275,7 @@ fn resolveExternOptions(
|
||||
.name = name,
|
||||
.library_name = library_name,
|
||||
.linkage = linkage,
|
||||
.is_thread_local = is_thread_local_val.toBool(mod),
|
||||
.is_thread_local = is_thread_local_val.toBool(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26190,7 +26181,7 @@ fn coerceExtra(
|
||||
.addr = .{ .int = (if (dest_info.@"align" != 0)
|
||||
try mod.intValue(Type.usize, dest_info.@"align")
|
||||
else
|
||||
try dest_info.pointee_type.lazyAbiAlignment(mod)).toIntern() },
|
||||
try mod.getCoerced(try dest_info.pointee_type.lazyAbiAlignment(mod), Type.usize)).toIntern() },
|
||||
.len = (try mod.intValue(Type.usize, 0)).toIntern(),
|
||||
} })).toValue());
|
||||
}
|
||||
@@ -27785,7 +27776,7 @@ fn beginComptimePtrMutation(
|
||||
const payload = try arena.create(Value.Payload.SubValue);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .eu_payload },
|
||||
.data = Value.undef,
|
||||
.data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(),
|
||||
};
|
||||
|
||||
val_ptr.* = Value.initPayload(&payload.base);
|
||||
@@ -27824,7 +27815,7 @@ fn beginComptimePtrMutation(
|
||||
const payload = try arena.create(Value.Payload.SubValue);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .opt_payload },
|
||||
.data = Value.undef,
|
||||
.data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(),
|
||||
};
|
||||
|
||||
val_ptr.* = Value.initPayload(&payload.base);
|
||||
@@ -27898,30 +27889,6 @@ fn beginComptimePtrMutation(
|
||||
}
|
||||
|
||||
switch (val_ptr.ip_index) {
|
||||
.undef => {
|
||||
// An array has been initialized to undefined at comptime and now we
|
||||
// are for the first time setting an element. We must change the representation
|
||||
// of the array from `undef` to `array`.
|
||||
const arena = parent.beginArena(sema.mod);
|
||||
defer parent.finishArena(sema.mod);
|
||||
|
||||
const array_len_including_sentinel =
|
||||
try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
|
||||
const elems = try arena.alloc(Value, array_len_including_sentinel);
|
||||
@memset(elems, Value.undef);
|
||||
|
||||
val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
|
||||
|
||||
return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
elem_ty,
|
||||
&elems[elem_ptr.index],
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
);
|
||||
},
|
||||
.none => switch (val_ptr.tag()) {
|
||||
.bytes => {
|
||||
// An array is memory-optimized to store a slice of bytes, but we are about
|
||||
@@ -27999,7 +27966,33 @@ fn beginComptimePtrMutation(
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) {
|
||||
.undef => {
|
||||
// An array has been initialized to undefined at comptime and now we
|
||||
// are for the first time setting an element. We must change the representation
|
||||
// of the array from `undef` to `array`.
|
||||
const arena = parent.beginArena(sema.mod);
|
||||
defer parent.finishArena(sema.mod);
|
||||
|
||||
const array_len_including_sentinel =
|
||||
try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
|
||||
const elems = try arena.alloc(Value, array_len_including_sentinel);
|
||||
@memset(elems, (try mod.intern(.{ .undef = elem_ty.toIntern() })).toValue());
|
||||
|
||||
val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
|
||||
|
||||
return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
elem_ty,
|
||||
&elems[elem_ptr.index],
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
);
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
}
|
||||
},
|
||||
else => {
|
||||
@@ -28052,83 +28045,6 @@ fn beginComptimePtrMutation(
|
||||
var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.base.toValue(), base_child_ty);
|
||||
switch (parent.pointee) {
|
||||
.direct => |val_ptr| switch (val_ptr.ip_index) {
|
||||
.undef => {
|
||||
// A struct or union has been initialized to undefined at comptime and now we
|
||||
// are for the first time setting a field. We must change the representation
|
||||
// of the struct/union from `undef` to `struct`/`union`.
|
||||
const arena = parent.beginArena(sema.mod);
|
||||
defer parent.finishArena(sema.mod);
|
||||
|
||||
switch (parent.ty.zigTypeTag(mod)) {
|
||||
.Struct => {
|
||||
const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod));
|
||||
@memset(fields, Value.undef);
|
||||
|
||||
val_ptr.* = try Value.Tag.aggregate.create(arena, fields);
|
||||
|
||||
return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
parent.ty.structFieldType(field_index, mod),
|
||||
&fields[field_index],
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
);
|
||||
},
|
||||
.Union => {
|
||||
const payload = try arena.create(Value.Payload.Union);
|
||||
const tag_ty = parent.ty.unionTagTypeHypothetical(mod);
|
||||
payload.* = .{ .data = .{
|
||||
.tag = try mod.enumValueFieldIndex(tag_ty, field_index),
|
||||
.val = Value.undef,
|
||||
} };
|
||||
|
||||
val_ptr.* = Value.initPayload(&payload.base);
|
||||
|
||||
return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
parent.ty.structFieldType(field_index, mod),
|
||||
&payload.data.val,
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
);
|
||||
},
|
||||
.Pointer => {
|
||||
assert(parent.ty.isSlice(mod));
|
||||
val_ptr.* = try Value.Tag.slice.create(arena, .{
|
||||
.ptr = Value.undef,
|
||||
.len = Value.undef,
|
||||
});
|
||||
|
||||
switch (field_index) {
|
||||
Value.slice_ptr_index => return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
parent.ty.slicePtrFieldType(mod),
|
||||
&val_ptr.castTag(.slice).?.data.ptr,
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
),
|
||||
Value.slice_len_index => return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
Type.usize,
|
||||
&val_ptr.castTag(.slice).?.data.len,
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
),
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.empty_struct => {
|
||||
const duped = try sema.arena.create(Value);
|
||||
duped.* = val_ptr.*;
|
||||
@@ -28210,10 +28126,92 @@ fn beginComptimePtrMutation(
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) {
|
||||
.undef => {
|
||||
// A struct or union has been initialized to undefined at comptime and now we
|
||||
// are for the first time setting a field. We must change the representation
|
||||
// of the struct/union from `undef` to `struct`/`union`.
|
||||
const arena = parent.beginArena(sema.mod);
|
||||
defer parent.finishArena(sema.mod);
|
||||
|
||||
switch (parent.ty.zigTypeTag(mod)) {
|
||||
.Struct => {
|
||||
const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod));
|
||||
for (fields, 0..) |*field, i| field.* = (try mod.intern(.{
|
||||
.undef = parent.ty.structFieldType(i, mod).toIntern(),
|
||||
})).toValue();
|
||||
|
||||
val_ptr.* = try Value.Tag.aggregate.create(arena, fields);
|
||||
|
||||
return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
parent.ty.structFieldType(field_index, mod),
|
||||
&fields[field_index],
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
);
|
||||
},
|
||||
.Union => {
|
||||
const payload = try arena.create(Value.Payload.Union);
|
||||
const tag_ty = parent.ty.unionTagTypeHypothetical(mod);
|
||||
const payload_ty = parent.ty.structFieldType(field_index, mod);
|
||||
payload.* = .{ .data = .{
|
||||
.tag = try mod.enumValueFieldIndex(tag_ty, field_index),
|
||||
.val = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(),
|
||||
} };
|
||||
|
||||
val_ptr.* = Value.initPayload(&payload.base);
|
||||
|
||||
return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
payload_ty,
|
||||
&payload.data.val,
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
);
|
||||
},
|
||||
.Pointer => {
|
||||
assert(parent.ty.isSlice(mod));
|
||||
const ptr_ty = parent.ty.slicePtrFieldType(mod);
|
||||
val_ptr.* = try Value.Tag.slice.create(arena, .{
|
||||
.ptr = (try mod.intern(.{ .undef = ptr_ty.toIntern() })).toValue(),
|
||||
.len = (try mod.intern(.{ .undef = .usize_type })).toValue(),
|
||||
});
|
||||
|
||||
switch (field_index) {
|
||||
Value.slice_ptr_index => return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
ptr_ty,
|
||||
&val_ptr.castTag(.slice).?.data.ptr,
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
),
|
||||
Value.slice_len_index => return beginComptimePtrMutationInner(
|
||||
sema,
|
||||
block,
|
||||
src,
|
||||
Type.usize,
|
||||
&val_ptr.castTag(.slice).?.data.len,
|
||||
ptr_elem_ty,
|
||||
parent.mut_decl,
|
||||
),
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
},
|
||||
.reinterpret => |reinterpret| {
|
||||
const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
|
||||
@@ -28370,18 +28368,22 @@ fn beginComptimePtrLoad(
|
||||
(try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or
|
||||
(try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok;
|
||||
if (coerce_in_mem_ok) {
|
||||
const payload_val = switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
|
||||
.error_union => |error_union| switch (error_union.val) {
|
||||
.err_name => |err_name| return sema.fail(block, src, "attempt to unwrap error: {s}", .{mod.intern_pool.stringToSlice(err_name)}),
|
||||
.payload => |payload| payload,
|
||||
},
|
||||
.opt => |opt| switch (opt.val) {
|
||||
.none => return sema.fail(block, src, "attempt to use null value", .{}),
|
||||
else => opt.val,
|
||||
},
|
||||
else => unreachable,
|
||||
const payload_val = switch (tv.val.ip_index) {
|
||||
.none => tv.val.cast(Value.Payload.SubValue).?.data,
|
||||
.null_value => return sema.fail(block, src, "attempt to use null value", .{}),
|
||||
else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
|
||||
.error_union => |error_union| switch (error_union.val) {
|
||||
.err_name => |err_name| return sema.fail(block, src, "attempt to unwrap error: {s}", .{mod.intern_pool.stringToSlice(err_name)}),
|
||||
.payload => |payload| payload,
|
||||
},
|
||||
.opt => |opt| switch (opt.val) {
|
||||
.none => return sema.fail(block, src, "attempt to use null value", .{}),
|
||||
else => opt.val,
|
||||
},
|
||||
else => unreachable,
|
||||
}.toValue(),
|
||||
};
|
||||
tv.* = TypedValue{ .ty = payload_ty, .val = payload_val.toValue() };
|
||||
tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
|
||||
break :blk deref;
|
||||
}
|
||||
}
|
||||
@@ -28960,7 +28962,7 @@ fn coerceArrayLike(
|
||||
if (in_memory_result == .ok) {
|
||||
if (try sema.resolveMaybeUndefVal(inst)) |inst_val| {
|
||||
// These types share the same comptime value representation.
|
||||
return sema.addConstant(dest_ty, inst_val);
|
||||
return sema.addConstant(dest_ty, try mod.getCoerced(inst_val, dest_ty));
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, inst_src, null);
|
||||
return block.addBitCast(dest_ty, inst);
|
||||
@@ -29024,7 +29026,7 @@ fn coerceTupleToArray(
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
|
||||
const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLenIncludingSentinel(mod));
|
||||
const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_len);
|
||||
const element_vals = try sema.arena.alloc(InternPool.Index, dest_elems);
|
||||
const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems);
|
||||
const dest_elem_ty = dest_ty.childType(mod);
|
||||
@@ -29430,7 +29432,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: boo
|
||||
const ptr_ty = try mod.ptrType(.{
|
||||
.elem_type = decl_tv.ty.toIntern(),
|
||||
.alignment = InternPool.Alignment.fromByteUnits(decl.@"align"),
|
||||
.is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else false,
|
||||
.is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true,
|
||||
.address_space = decl.@"addrspace",
|
||||
});
|
||||
if (analyze_fn_body) {
|
||||
@@ -29513,7 +29515,7 @@ fn analyzeLoad(
|
||||
|
||||
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
|
||||
if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
|
||||
return sema.addConstant(elem_ty, elem_val);
|
||||
return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32610,8 +32612,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
|
||||
var int_tag_ty: Type = undefined;
|
||||
var enum_field_names: []InternPool.NullTerminatedString = &.{};
|
||||
var enum_field_vals: []InternPool.Index = &.{};
|
||||
var enum_field_vals_map: std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false) = .{};
|
||||
var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};
|
||||
var explicit_tags_seen: []bool = &.{};
|
||||
var explicit_enum_info: ?InternPool.Key.EnumType = null;
|
||||
if (tag_type_ref != .none) {
|
||||
@@ -32638,9 +32639,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
|
||||
try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len);
|
||||
}
|
||||
enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
|
||||
enum_field_vals = try sema.arena.alloc(InternPool.Index, fields_len);
|
||||
} else {
|
||||
// The provided type is the enum tag type.
|
||||
union_obj.tag_ty = provided_ty;
|
||||
@@ -32712,8 +32713,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
break :blk try sema.resolveInst(tag_ref);
|
||||
} else .none;
|
||||
|
||||
if (enum_field_vals.len != 0) {
|
||||
const copied_val = if (tag_ref != .none) blk: {
|
||||
if (enum_field_vals.capacity() > 0) {
|
||||
const enum_tag_val = if (tag_ref != .none) blk: {
|
||||
const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {
|
||||
error.NeededSourceLocation => {
|
||||
const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
|
||||
@@ -32737,16 +32738,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
|
||||
break :blk val;
|
||||
};
|
||||
enum_field_vals[field_i] = copied_val.toIntern();
|
||||
const gop = enum_field_vals_map.getOrPutAssumeCapacityContext(copied_val, .{
|
||||
.ty = int_tag_ty,
|
||||
.mod = mod,
|
||||
});
|
||||
const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern());
|
||||
if (gop.found_existing) {
|
||||
const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
|
||||
const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy;
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, mod)});
|
||||
const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{});
|
||||
break :msg msg;
|
||||
@@ -32907,8 +32904,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
} else if (enum_field_vals.len != 0) {
|
||||
union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals, union_obj);
|
||||
} else if (enum_field_vals.count() > 0) {
|
||||
union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_obj);
|
||||
} else {
|
||||
union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_obj);
|
||||
}
|
||||
@@ -33180,8 +33177,12 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
.struct_type => |struct_type| {
|
||||
const resolved_ty = try sema.resolveTypeFields(ty);
|
||||
if (mod.structPtrUnwrap(struct_type.index)) |s| {
|
||||
for (s.fields.values(), 0..) |field, i| {
|
||||
if (field.is_comptime) continue;
|
||||
const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count());
|
||||
for (field_vals, s.fields.values(), 0..) |*field_val, field, i| {
|
||||
if (field.is_comptime) {
|
||||
field_val.* = try field.default_val.intern(field.ty, mod);
|
||||
continue;
|
||||
}
|
||||
if (field.ty.eql(resolved_ty, sema.mod)) {
|
||||
const msg = try Module.ErrorMsg.create(
|
||||
sema.gpa,
|
||||
@@ -33192,24 +33193,25 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{});
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
if ((try sema.typeHasOnePossibleValue(field.ty)) == null) {
|
||||
return null;
|
||||
}
|
||||
if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| {
|
||||
field_val.* = try field_opv.intern(field.ty, mod);
|
||||
} else return null;
|
||||
}
|
||||
}
|
||||
// In this case the struct has no runtime-known fields and
|
||||
// therefore has one possible value.
|
||||
|
||||
// TODO: this is incorrect for structs with comptime fields, I think
|
||||
// we should use a temporary allocator to construct an aggregate that
|
||||
// is populated with the comptime values and then intern that value here.
|
||||
// This TODO is repeated in the redundant implementation of
|
||||
// one-possible-value in type.zig.
|
||||
const empty = try mod.intern(.{ .aggregate = .{
|
||||
// In this case the struct has no runtime-known fields and
|
||||
// therefore has one possible value.
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = field_vals },
|
||||
} })).toValue();
|
||||
}
|
||||
|
||||
// In this case the struct has no fields at all and
|
||||
// therefore has one possible value.
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = &.{} },
|
||||
} });
|
||||
return empty.toValue();
|
||||
} })).toValue();
|
||||
},
|
||||
|
||||
.anon_struct_type => |tuple| {
|
||||
@@ -33268,20 +33270,13 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
},
|
||||
.auto, .explicit => switch (enum_type.names.len) {
|
||||
0 => return Value.@"unreachable",
|
||||
1 => {
|
||||
if (enum_type.values.len == 0) {
|
||||
const only = try mod.intern(.{ .enum_tag = .{
|
||||
.ty = ty.toIntern(),
|
||||
.int = try mod.intern(.{ .int = .{
|
||||
.ty = enum_type.tag_ty,
|
||||
.storage = .{ .u64 = 0 },
|
||||
} }),
|
||||
} });
|
||||
return only.toValue();
|
||||
} else {
|
||||
return enum_type.values[0].toValue();
|
||||
}
|
||||
},
|
||||
1 => return try mod.getCoerced((if (enum_type.values.len == 0)
|
||||
try mod.intern(.{ .int = .{
|
||||
.ty = enum_type.tag_ty,
|
||||
.storage = .{ .u64 = 0 },
|
||||
} })
|
||||
else
|
||||
enum_type.values[0]).toValue(), ty),
|
||||
else => return null,
|
||||
},
|
||||
},
|
||||
@@ -33427,7 +33422,7 @@ fn analyzeComptimeAlloc(
|
||||
// There will be stores before the first load, but they may be to sub-elements or
|
||||
// sub-fields. So we need to initialize with undef to allow the mechanism to expand
|
||||
// into fields/elements and have those overridden with stored values.
|
||||
Value.undef,
|
||||
(try sema.mod.intern(.{ .undef = var_type.toIntern() })).toValue(),
|
||||
alignment,
|
||||
);
|
||||
const decl = sema.mod.declPtr(decl_index);
|
||||
@@ -34028,16 +34023,16 @@ fn intSubWithOverflow(
|
||||
const lhs_elem = try lhs.elemValue(sema.mod, i);
|
||||
const rhs_elem = try rhs.elemValue(sema.mod, i);
|
||||
const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty);
|
||||
of.* = try of_math_result.overflow_bit.intern(Type.bool, mod);
|
||||
of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
|
||||
scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
|
||||
}
|
||||
return Value.OverflowArithmeticResult{
|
||||
.overflow_bit = (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
|
||||
.storage = .{ .elems = overflowed_data },
|
||||
} })).toValue(),
|
||||
.wrapped_result = (try mod.intern(.{ .aggregate = .{
|
||||
.ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = result_data },
|
||||
} })).toValue(),
|
||||
};
|
||||
@@ -34066,7 +34061,7 @@ fn intSubWithOverflowScalar(
|
||||
const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
|
||||
const wrapped_result = try mod.intValue_big(ty, result_bigint.toConst());
|
||||
return Value.OverflowArithmeticResult{
|
||||
.overflow_bit = Value.boolToInt(overflowed),
|
||||
.overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
|
||||
.wrapped_result = wrapped_result,
|
||||
};
|
||||
}
|
||||
@@ -34273,16 +34268,16 @@ fn intAddWithOverflow(
|
||||
const lhs_elem = try lhs.elemValue(sema.mod, i);
|
||||
const rhs_elem = try rhs.elemValue(sema.mod, i);
|
||||
const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty);
|
||||
of.* = try of_math_result.overflow_bit.intern(Type.bool, mod);
|
||||
of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
|
||||
scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
|
||||
}
|
||||
return Value.OverflowArithmeticResult{
|
||||
.overflow_bit = (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
|
||||
.storage = .{ .elems = overflowed_data },
|
||||
} })).toValue(),
|
||||
.wrapped_result = (try mod.intern(.{ .aggregate = .{
|
||||
.ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = result_data },
|
||||
} })).toValue(),
|
||||
};
|
||||
@@ -34311,7 +34306,7 @@ fn intAddWithOverflowScalar(
|
||||
const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
|
||||
const result = try mod.intValue_big(ty, result_bigint.toConst());
|
||||
return Value.OverflowArithmeticResult{
|
||||
.overflow_bit = Value.boolToInt(overflowed),
|
||||
.overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
|
||||
.wrapped_result = result,
|
||||
};
|
||||
}
|
||||
@@ -34384,7 +34379,7 @@ fn compareVector(
|
||||
scalar.* = try Value.makeBool(res_bool).intern(Type.bool, mod);
|
||||
}
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = (try mod.vectorType(.{ .len = ty.vectorLen(mod), .child = .u1_type })).toIntern(),
|
||||
.ty = (try mod.vectorType(.{ .len = ty.vectorLen(mod), .child = .bool_type })).toIntern(),
|
||||
.storage = .{ .elems = result_data },
|
||||
} })).toValue();
|
||||
}
|
||||
|
||||
+1
-1
@@ -957,7 +957,7 @@ pub fn genTypedValue(
|
||||
}
|
||||
},
|
||||
.Bool => {
|
||||
return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool(mod)) });
|
||||
return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) });
|
||||
},
|
||||
.Optional => {
|
||||
if (typed_value.ty.isPtrLikeOptional(mod)) {
|
||||
|
||||
+19
-15
@@ -2003,7 +2003,7 @@ pub const Object = struct {
|
||||
mod.intern_pool.stringToSlice(tuple.names[i])
|
||||
else
|
||||
try std.fmt.allocPrintZ(gpa, "{d}", .{i});
|
||||
defer gpa.free(field_name);
|
||||
defer if (tuple.names.len == 0) gpa.free(field_name);
|
||||
|
||||
try di_fields.append(gpa, dib.createMemberType(
|
||||
fwd_decl.toScope(),
|
||||
@@ -2461,13 +2461,13 @@ pub const DeclGen = struct {
|
||||
if (decl.@"linksection") |section| global.setSection(section);
|
||||
assert(decl.has_tv);
|
||||
const init_val = if (decl.val.getVariable(mod)) |variable| init_val: {
|
||||
break :init_val variable.init.toValue();
|
||||
break :init_val variable.init;
|
||||
} else init_val: {
|
||||
global.setGlobalConstant(.True);
|
||||
break :init_val decl.val;
|
||||
break :init_val decl.val.toIntern();
|
||||
};
|
||||
if (init_val.toIntern() != .unreachable_value) {
|
||||
const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val });
|
||||
if (init_val != .none) {
|
||||
const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() });
|
||||
if (global.globalGetValueType() == llvm_init.typeOf()) {
|
||||
global.setInitializer(llvm_init);
|
||||
} else {
|
||||
@@ -2748,7 +2748,7 @@ pub const DeclGen = struct {
|
||||
if (std.debug.runtime_safety and false) check: {
|
||||
if (t.zigTypeTag(mod) == .Opaque) break :check;
|
||||
if (!t.hasRuntimeBits(mod)) break :check;
|
||||
if (!llvm_ty.isSized().toBool(mod)) break :check;
|
||||
if (!llvm_ty.isSized().toBool()) break :check;
|
||||
|
||||
const zig_size = t.abiSize(mod);
|
||||
const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty);
|
||||
@@ -3239,7 +3239,7 @@ pub const DeclGen = struct {
|
||||
=> unreachable, // non-runtime values
|
||||
.false, .true => {
|
||||
const llvm_type = try dg.lowerType(tv.ty);
|
||||
return if (tv.val.toBool(mod)) llvm_type.constAllOnes() else llvm_type.constNull();
|
||||
return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
|
||||
},
|
||||
},
|
||||
.variable,
|
||||
@@ -3522,15 +3522,19 @@ pub const DeclGen = struct {
|
||||
const elem_ty = vector_type.child.toType();
|
||||
const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_type.len);
|
||||
defer dg.gpa.free(llvm_elems);
|
||||
const llvm_i8 = dg.context.intType(8);
|
||||
for (llvm_elems, 0..) |*llvm_elem, i| {
|
||||
llvm_elem.* = try dg.lowerValue(.{
|
||||
.ty = elem_ty,
|
||||
.val = switch (aggregate.storage) {
|
||||
.bytes => unreachable,
|
||||
.elems => |elems| elems[i],
|
||||
.repeated_elem => |elem| elem,
|
||||
}.toValue(),
|
||||
});
|
||||
llvm_elem.* = switch (aggregate.storage) {
|
||||
.bytes => |bytes| llvm_i8.constInt(bytes[i], .False),
|
||||
.elems => |elems| try dg.lowerValue(.{
|
||||
.ty = elem_ty,
|
||||
.val = elems[i].toValue(),
|
||||
}),
|
||||
.repeated_elem => |elem| try dg.lowerValue(.{
|
||||
.ty = elem_ty,
|
||||
.val = elem.toValue(),
|
||||
}),
|
||||
};
|
||||
}
|
||||
return llvm.constVector(
|
||||
llvm_elems.ptr,
|
||||
|
||||
+3
-47
@@ -654,7 +654,7 @@ pub const DeclGen = struct {
|
||||
.@"unreachable",
|
||||
.generic_poison,
|
||||
=> unreachable, // non-runtime values
|
||||
.false, .true => try self.addConstBool(val.toBool(mod)),
|
||||
.false, .true => try self.addConstBool(val.toBool()),
|
||||
},
|
||||
.variable,
|
||||
.extern_func,
|
||||
@@ -974,7 +974,6 @@ pub const DeclGen = struct {
|
||||
/// This function should only be called during function code generation.
|
||||
fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef {
|
||||
const mod = self.module;
|
||||
const target = self.getTarget();
|
||||
const result_ty_ref = try self.resolveType(ty, repr);
|
||||
|
||||
log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
|
||||
@@ -991,51 +990,8 @@ pub const DeclGen = struct {
|
||||
return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod));
|
||||
}
|
||||
},
|
||||
.Bool => switch (repr) {
|
||||
.direct => return try self.spv.constBool(result_ty_ref, val.toBool(mod)),
|
||||
.indirect => return try self.spv.constInt(result_ty_ref, @boolToInt(val.toBool(mod))),
|
||||
},
|
||||
.Float => return switch (ty.floatBits(target)) {
|
||||
16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }),
|
||||
32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }),
|
||||
64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }),
|
||||
80, 128 => unreachable, // TODO
|
||||
else => unreachable,
|
||||
},
|
||||
.ErrorSet => {
|
||||
const value = switch (val.tag()) {
|
||||
.@"error" => blk: {
|
||||
const err_name = val.castTag(.@"error").?.data.name;
|
||||
const kv = try self.module.getErrorValue(err_name);
|
||||
break :blk @intCast(u16, kv.value);
|
||||
},
|
||||
.zero => 0,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
return try self.spv.constInt(result_ty_ref, value);
|
||||
},
|
||||
.ErrorUnion => {
|
||||
const payload_ty = ty.errorUnionPayload();
|
||||
const is_pl = val.errorUnionIsPayload();
|
||||
const error_val = if (!is_pl) val else Value.initTag(.zero);
|
||||
|
||||
const eu_layout = self.errorUnionLayout(payload_ty);
|
||||
if (!eu_layout.payload_has_bits) {
|
||||
return try self.constant(Type.anyerror, error_val, repr);
|
||||
}
|
||||
|
||||
const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef;
|
||||
|
||||
var members: [2]IdRef = undefined;
|
||||
if (eu_layout.error_first) {
|
||||
members[0] = try self.constant(Type.anyerror, error_val, .indirect);
|
||||
members[1] = try self.constant(payload_ty, payload_val, .indirect);
|
||||
} else {
|
||||
members[0] = try self.constant(payload_ty, payload_val, .indirect);
|
||||
members[1] = try self.constant(Type.anyerror, error_val, .indirect);
|
||||
}
|
||||
return try self.spv.constComposite(result_ty_ref, &members);
|
||||
.Bool => {
|
||||
@compileError("TODO merge conflict failure");
|
||||
},
|
||||
// TODO: We can handle most pointers here (decl refs etc), because now they emit an extra
|
||||
// OpVariable that is not really required.
|
||||
|
||||
+22
-15
@@ -2481,25 +2481,32 @@ pub const Type = struct {
|
||||
.struct_type => |struct_type| {
|
||||
if (mod.structPtrUnwrap(struct_type.index)) |s| {
|
||||
assert(s.haveFieldTypes());
|
||||
for (s.fields.values()) |field| {
|
||||
if (field.is_comptime) continue;
|
||||
if ((try field.ty.onePossibleValue(mod)) != null) continue;
|
||||
return null;
|
||||
const field_vals = try mod.gpa.alloc(InternPool.Index, s.fields.count());
|
||||
defer mod.gpa.free(field_vals);
|
||||
for (field_vals, s.fields.values()) |*field_val, field| {
|
||||
if (field.is_comptime) {
|
||||
field_val.* = try field.default_val.intern(field.ty, mod);
|
||||
continue;
|
||||
}
|
||||
if (try field.ty.onePossibleValue(mod)) |field_opv| {
|
||||
field_val.* = try field_opv.intern(field.ty, mod);
|
||||
} else return null;
|
||||
}
|
||||
}
|
||||
// In this case the struct has no runtime-known fields and
|
||||
// therefore has one possible value.
|
||||
|
||||
// TODO: this is incorrect for structs with comptime fields, I think
|
||||
// we should use a temporary allocator to construct an aggregate that
|
||||
// is populated with the comptime values and then intern that value here.
|
||||
// This TODO is repeated in the redundant implementation of
|
||||
// one-possible-value logic in Sema.zig.
|
||||
const empty = try mod.intern(.{ .aggregate = .{
|
||||
// In this case the struct has no runtime-known fields and
|
||||
// therefore has one possible value.
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = field_vals },
|
||||
} })).toValue();
|
||||
}
|
||||
|
||||
// In this case the struct has no fields at all and
|
||||
// therefore has one possible value.
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = &.{} },
|
||||
} });
|
||||
return empty.toValue();
|
||||
} })).toValue();
|
||||
},
|
||||
|
||||
.anon_struct_type => |tuple| {
|
||||
|
||||
+47
-153
@@ -385,7 +385,7 @@ pub const Value = struct {
|
||||
} });
|
||||
},
|
||||
.aggregate => {
|
||||
const old_elems = val.castTag(.aggregate).?.data;
|
||||
const old_elems = val.castTag(.aggregate).?.data[0..ty.arrayLen(mod)];
|
||||
const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len);
|
||||
defer mod.gpa.free(new_elems);
|
||||
const ty_key = mod.intern_pool.indexToKey(ty.toIntern());
|
||||
@@ -656,7 +656,7 @@ pub const Value = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toBool(val: Value, _: *const Module) bool {
|
||||
pub fn toBool(val: Value) bool {
|
||||
return switch (val.toIntern()) {
|
||||
.bool_true => true,
|
||||
.bool_false => false,
|
||||
@@ -697,7 +697,7 @@ pub const Value = struct {
|
||||
switch (ty.zigTypeTag(mod)) {
|
||||
.Void => {},
|
||||
.Bool => {
|
||||
buffer[0] = @boolToInt(val.toBool(mod));
|
||||
buffer[0] = @boolToInt(val.toBool());
|
||||
},
|
||||
.Int, .Enum => {
|
||||
const int_info = ty.intInfo(mod);
|
||||
@@ -736,13 +736,20 @@ pub const Value = struct {
|
||||
},
|
||||
.Struct => switch (ty.containerLayout(mod)) {
|
||||
.Auto => return error.IllDefinedMemoryLayout,
|
||||
.Extern => {
|
||||
const fields = ty.structFields(mod).values();
|
||||
const field_vals = val.castTag(.aggregate).?.data;
|
||||
for (fields, 0..) |field, i| {
|
||||
const off = @intCast(usize, ty.structFieldOffset(i, mod));
|
||||
try writeToMemory(field_vals[i], field.ty, mod, buffer[off..]);
|
||||
}
|
||||
.Extern => for (ty.structFields(mod).values(), 0..) |field, i| {
|
||||
const off = @intCast(usize, ty.structFieldOffset(i, mod));
|
||||
const field_val = switch (val.ip_index) {
|
||||
.none => val.castTag(.aggregate).?.data[i],
|
||||
else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) {
|
||||
.bytes => |bytes| {
|
||||
buffer[off] = bytes[i];
|
||||
continue;
|
||||
},
|
||||
.elems => |elems| elems[i],
|
||||
.repeated_elem => |elem| elem,
|
||||
}.toValue(),
|
||||
};
|
||||
try writeToMemory(field_val, field.ty, mod, buffer[off..]);
|
||||
},
|
||||
.Packed => {
|
||||
const byte_count = (@intCast(usize, ty.bitSize(mod)) + 7) / 8;
|
||||
@@ -812,7 +819,7 @@ pub const Value = struct {
|
||||
.Little => bit_offset / 8,
|
||||
.Big => buffer.len - bit_offset / 8 - 1,
|
||||
};
|
||||
if (val.toBool(mod)) {
|
||||
if (val.toBool()) {
|
||||
buffer[byte_index] |= (@as(u8, 1) << @intCast(u3, bit_offset % 8));
|
||||
} else {
|
||||
buffer[byte_index] &= ~(@as(u8, 1) << @intCast(u3, bit_offset % 8));
|
||||
@@ -1331,24 +1338,7 @@ pub const Value = struct {
|
||||
.gt => {},
|
||||
}
|
||||
|
||||
const lhs_float = lhs.isFloat(mod);
|
||||
const rhs_float = rhs.isFloat(mod);
|
||||
if (lhs_float and rhs_float) {
|
||||
const lhs_tag = lhs.tag();
|
||||
const rhs_tag = rhs.tag();
|
||||
if (lhs_tag == rhs_tag) {
|
||||
const lhs_storage = mod.intern_pool.indexToKey(lhs.toIntern()).float.storage;
|
||||
const rhs_storage = mod.intern_pool.indexToKey(rhs.toIntern()).float.storage;
|
||||
const lhs128: f128 = switch (lhs_storage) {
|
||||
inline else => |x| x,
|
||||
};
|
||||
const rhs128: f128 = switch (rhs_storage) {
|
||||
inline else => |x| x,
|
||||
};
|
||||
return std.math.order(lhs128, rhs128);
|
||||
}
|
||||
}
|
||||
if (lhs_float or rhs_float) {
|
||||
if (lhs.isFloat(mod) or rhs.isFloat(mod)) {
|
||||
const lhs_f128 = lhs.toFloat(f128, mod);
|
||||
const rhs_f128 = rhs.toFloat(f128, mod);
|
||||
return std.math.order(lhs_f128, rhs_f128);
|
||||
@@ -1669,86 +1659,6 @@ pub const Value = struct {
|
||||
return (try orderAdvanced(a, b, mod, opt_sema)).compare(.eq);
|
||||
}
|
||||
|
||||
/// 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 hash(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void {
|
||||
if (val.ip_index != .none) {
|
||||
// The InternPool data structure hashes based on Key to make interned objects
|
||||
// unique. An Index can be treated simply as u32 value for the
|
||||
// purpose of Type/Value hashing and equality.
|
||||
std.hash.autoHash(hasher, val.toIntern());
|
||||
return;
|
||||
}
|
||||
const zig_ty_tag = ty.zigTypeTag(mod);
|
||||
std.hash.autoHash(hasher, zig_ty_tag);
|
||||
if (val.isUndef(mod)) return;
|
||||
// The value is runtime-known and shouldn't affect the hash.
|
||||
if (val.isRuntimeValue(mod)) return;
|
||||
|
||||
switch (zig_ty_tag) {
|
||||
.Opaque => unreachable, // Cannot hash opaque types
|
||||
|
||||
.Void,
|
||||
.NoReturn,
|
||||
.Undefined,
|
||||
.Null,
|
||||
=> {},
|
||||
|
||||
.Type,
|
||||
.Float,
|
||||
.ComptimeFloat,
|
||||
.Bool,
|
||||
.Int,
|
||||
.ComptimeInt,
|
||||
.Pointer,
|
||||
.Optional,
|
||||
.ErrorUnion,
|
||||
.ErrorSet,
|
||||
.Enum,
|
||||
.EnumLiteral,
|
||||
.Fn,
|
||||
=> unreachable, // handled via ip_index check above
|
||||
.Array, .Vector => {
|
||||
const len = ty.arrayLen(mod);
|
||||
const elem_ty = ty.childType(mod);
|
||||
var index: usize = 0;
|
||||
while (index < len) : (index += 1) {
|
||||
const elem_val = val.elemValue(mod, index) catch |err| switch (err) {
|
||||
// Will be solved when arrays and vectors get migrated to the intern pool.
|
||||
error.OutOfMemory => @panic("OOM"),
|
||||
};
|
||||
elem_val.hash(elem_ty, hasher, mod);
|
||||
}
|
||||
},
|
||||
.Struct => {
|
||||
switch (val.tag()) {
|
||||
.aggregate => {
|
||||
const field_values = val.castTag(.aggregate).?.data;
|
||||
for (field_values, 0..) |field_val, i| {
|
||||
const field_ty = ty.structFieldType(i, mod);
|
||||
field_val.hash(field_ty, hasher, mod);
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.Union => {
|
||||
const union_obj = val.cast(Payload.Union).?.data;
|
||||
if (ty.unionTagType(mod)) |tag_ty| {
|
||||
union_obj.tag.hash(tag_ty, hasher, mod);
|
||||
}
|
||||
const active_field_ty = ty.unionFieldType(union_obj.tag, mod);
|
||||
union_obj.val.hash(active_field_ty, hasher, mod);
|
||||
},
|
||||
.Frame => {
|
||||
@panic("TODO implement hashing frame values");
|
||||
},
|
||||
.AnyFrame => {
|
||||
@panic("TODO implement hashing anyframe values");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a more conservative hash function that produces equal hashes for values
|
||||
/// that can coerce into each other.
|
||||
/// This function is used by hash maps and so treats floating-point NaNs as equal
|
||||
@@ -1820,35 +1730,6 @@ pub const Value = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub const ArrayHashContext = struct {
|
||||
ty: Type,
|
||||
mod: *Module,
|
||||
|
||||
pub fn hash(self: @This(), val: Value) u32 {
|
||||
const other_context: HashContext = .{ .ty = self.ty, .mod = self.mod };
|
||||
return @truncate(u32, other_context.hash(val));
|
||||
}
|
||||
pub fn eql(self: @This(), a: Value, b: Value, b_index: usize) bool {
|
||||
_ = b_index;
|
||||
return a.eql(b, self.ty, self.mod);
|
||||
}
|
||||
};
|
||||
|
||||
pub const HashContext = struct {
|
||||
ty: Type,
|
||||
mod: *Module,
|
||||
|
||||
pub fn hash(self: @This(), val: Value) u64 {
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
val.hash(self.ty, &hasher, self.mod);
|
||||
return hasher.final();
|
||||
}
|
||||
|
||||
pub fn eql(self: @This(), a: Value, b: Value) bool {
|
||||
return a.eql(b, self.ty, self.mod);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool {
|
||||
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.ptr => |ptr| switch (ptr.addr) {
|
||||
@@ -1919,14 +1800,25 @@ pub const Value = struct {
|
||||
}
|
||||
|
||||
pub fn sliceLen(val: Value, mod: *Module) u64 {
|
||||
return mod.intern_pool.sliceLen(val.toIntern()).toValue().toUnsignedInt(mod);
|
||||
const ptr = mod.intern_pool.indexToKey(val.toIntern()).ptr;
|
||||
return switch (ptr.len) {
|
||||
.none => switch (mod.intern_pool.indexToKey(switch (ptr.addr) {
|
||||
.decl => |decl| mod.declPtr(decl).ty.toIntern(),
|
||||
.mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),
|
||||
.comptime_field => |comptime_field| mod.intern_pool.typeOf(comptime_field),
|
||||
else => unreachable,
|
||||
})) {
|
||||
.array_type => |array_type| array_type.len,
|
||||
else => 1,
|
||||
},
|
||||
else => ptr.len.toValue().toUnsignedInt(mod),
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the value is a single-item pointer to an array, or an array,
|
||||
/// or an unknown-length pointer, and returns the element value at the index.
|
||||
pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
|
||||
return switch (val.ip_index) {
|
||||
.undef => Value.undef,
|
||||
.none => switch (val.tag()) {
|
||||
.repeated => val.castTag(.repeated).?.data,
|
||||
.aggregate => val.castTag(.aggregate).?.data[index],
|
||||
@@ -1934,6 +1826,9 @@ pub const Value = struct {
|
||||
else => unreachable,
|
||||
},
|
||||
else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.undef => |ty| (try mod.intern(.{
|
||||
.undef = ty.toType().elemType2(mod).toIntern(),
|
||||
})).toValue(),
|
||||
.ptr => |ptr| switch (ptr.addr) {
|
||||
.decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
|
||||
.mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index),
|
||||
@@ -2492,7 +2387,7 @@ pub const Value = struct {
|
||||
}
|
||||
|
||||
return OverflowArithmeticResult{
|
||||
.overflow_bit = boolToInt(overflowed),
|
||||
.overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
|
||||
.wrapped_result = try mod.intValue_big(ty, result_bigint.toConst()),
|
||||
};
|
||||
}
|
||||
@@ -2645,7 +2540,8 @@ 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(mod)) return Value.undef;
|
||||
if (val.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue();
|
||||
if (ty.toIntern() == .bool_type) return makeBool(!val.toBool());
|
||||
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
@@ -2687,7 +2583,8 @@ 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(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue();
|
||||
if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() and rhs.toBool());
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
@@ -2725,7 +2622,8 @@ 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(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue();
|
||||
if (ty.toIntern() == .bool_type) return makeBool(!(lhs.toBool() and rhs.toBool()));
|
||||
|
||||
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);
|
||||
@@ -2752,7 +2650,8 @@ 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(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue();
|
||||
if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() or rhs.toBool());
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
@@ -2789,7 +2688,8 @@ 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(mod) or rhs.isUndef(mod)) return Value.undef;
|
||||
if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue();
|
||||
if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() != rhs.toBool());
|
||||
|
||||
// TODO is this a performance issue? maybe we should try the operation without
|
||||
// resorting to BigInt first.
|
||||
@@ -3233,7 +3133,7 @@ pub const Value = struct {
|
||||
result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits);
|
||||
}
|
||||
return OverflowArithmeticResult{
|
||||
.overflow_bit = boolToInt(overflowed),
|
||||
.overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
|
||||
.wrapped_result = try mod.intValue_big(ty, result_bigint.toConst()),
|
||||
};
|
||||
}
|
||||
@@ -4267,12 +4167,6 @@ pub const Value = struct {
|
||||
return if (x) Value.true else Value.false;
|
||||
}
|
||||
|
||||
pub fn boolToInt(x: bool) Value {
|
||||
const zero: Value = .{ .ip_index = .zero, .legacy = undefined };
|
||||
const one: Value = .{ .ip_index = .one, .legacy = undefined };
|
||||
return if (x) one else zero;
|
||||
}
|
||||
|
||||
pub const RuntimeIndex = InternPool.RuntimeIndex;
|
||||
|
||||
/// This function is used in the debugger pretty formatters in tools/ to fetch the
|
||||
|
||||
@@ -354,8 +354,8 @@ def Zir_Inst__Zir_Inst_Ref_SummaryProvider(value, _=None):
|
||||
|
||||
def Air_Inst__Air_Inst_Ref_SummaryProvider(value, _=None):
|
||||
members = value.type.enum_members
|
||||
# ignore .none
|
||||
return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned + 1 - len(members))
|
||||
# ignore .var_args_param_type and .none
|
||||
return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned + 2 - len(members))
|
||||
|
||||
class Module_Decl__Module_Decl_Index_SynthProvider:
|
||||
def __init__(self, value, _=None): self.value = value
|
||||
@@ -365,7 +365,7 @@ class Module_Decl__Module_Decl_Index_SynthProvider:
|
||||
mod = frame.FindVariable('mod') or frame.FindVariable('module')
|
||||
if mod: break
|
||||
else: return
|
||||
self.ptr = mod.GetChildMemberWithName('allocated_decls').GetChildAtIndex(self.value.unsigned).Clone('decl')
|
||||
self.ptr = mod.GetChildMemberWithName('allocated_decls').GetChildAtIndex(self.value.unsigned).address_of.Clone('decl')
|
||||
except: pass
|
||||
def has_children(self): return True
|
||||
def num_children(self): return 1
|
||||
|
||||
Reference in New Issue
Block a user