mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
Merge pull request #23733 from alichraghi/bp
replace @Type with individual type-creating builtins
This commit is contained in:
+74
-40
@@ -638,7 +638,7 @@
|
||||
{#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an
|
||||
integer type is {#syntax#}65535{#endsyntax#}.
|
||||
</p>
|
||||
{#see_also|Integers|Floats|void|Errors|@Type#}
|
||||
{#see_also|Integers|Floats|void|Errors|@Int#}
|
||||
{#header_close#}
|
||||
{#header_open|Primitive Values#}
|
||||
<div class="table-wrapper">
|
||||
@@ -3723,9 +3723,9 @@ void do_a_thing(struct Foo *foo) {
|
||||
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}@FieldType(T, "a"){#endsyntax#}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{#syntax#}@Type(x){#endsyntax#}</th>
|
||||
<th scope="row">{#syntax#}@Int(x, y){#endsyntax#}</th>
|
||||
<td>-</td>
|
||||
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.builtin.Type{#endsyntax#}</td>
|
||||
<td>{#syntax#}x{#endsyntax#} is a {#syntax#}std.builtin.Signedness{#endsyntax#}, {#syntax#}y{#endsyntax#} is a {#syntax#}u16{#endsyntax#}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{#syntax#}@typeInfo(x){#endsyntax#}</th>
|
||||
@@ -3839,9 +3839,9 @@ void do_a_thing(struct Foo *foo) {
|
||||
<td>{#syntax#}x{#endsyntax#} has no result location (typed initializers do not propagate result locations)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{#syntax#}@Type(x){#endsyntax#}</th>
|
||||
<td>{#syntax#}ptr{#endsyntax#}</td>
|
||||
<td>{#syntax#}x{#endsyntax#} has no result location</td>
|
||||
<th scope="row">{#syntax#}@Int(x, y){#endsyntax#}</th>
|
||||
<td>-</td>
|
||||
<td>{#syntax#}x{#endsyntax#} and {#syntax#}y{#endsyntax#} do not have result locations</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{#syntax#}@typeInfo(x){#endsyntax#}</th>
|
||||
@@ -5755,41 +5755,75 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Type#}
|
||||
<pre>{#syntax#}@Type(comptime info: std.builtin.Type) type{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function is the inverse of {#link|@typeInfo#}. It reifies type information
|
||||
into a {#syntax#}type{#endsyntax#}.
|
||||
</p>
|
||||
<p>
|
||||
It is available for the following types:
|
||||
</p>
|
||||
<ul>
|
||||
<li>{#syntax#}type{#endsyntax#}</li>
|
||||
<li>{#syntax#}noreturn{#endsyntax#}</li>
|
||||
<li>{#syntax#}void{#endsyntax#}</li>
|
||||
<li>{#syntax#}bool{#endsyntax#}</li>
|
||||
<li>{#link|Integers#} - The maximum bit count for an integer type is {#syntax#}65535{#endsyntax#}.</li>
|
||||
<li>{#link|Floats#}</li>
|
||||
<li>{#link|Pointers#}</li>
|
||||
<li>{#syntax#}comptime_int{#endsyntax#}</li>
|
||||
<li>{#syntax#}comptime_float{#endsyntax#}</li>
|
||||
<li>{#syntax#}@TypeOf(undefined){#endsyntax#}</li>
|
||||
<li>{#syntax#}@TypeOf(null){#endsyntax#}</li>
|
||||
<li>{#link|Arrays#}</li>
|
||||
<li>{#link|Optionals#}</li>
|
||||
<li>{#link|Error Set Type#}</li>
|
||||
<li>{#link|Error Union Type#}</li>
|
||||
<li>{#link|Vectors#}</li>
|
||||
<li>{#link|opaque#}</li>
|
||||
<li>{#syntax#}anyframe{#endsyntax#}</li>
|
||||
<li>{#link|struct#}</li>
|
||||
<li>{#link|enum#}</li>
|
||||
<li>{#link|Enum Literals#}</li>
|
||||
<li>{#link|union#}</li>
|
||||
<li>{#link|Functions#}</li>
|
||||
</ul>
|
||||
{#header_open|@EnumLiteral#}
|
||||
<pre>{#syntax#}@EnumLiteral() type{#endsyntax#}</pre>
|
||||
<p>Returns the comptime-only "enum literal" type. This is the type of uncoerced {#link|Enum Literals#}. Values of this type can coerce to any {#link|enum#} with a matching field.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Int#}
|
||||
<pre>{#syntax#}@Int(comptime signedness: std.builtin.Signedness, comptime bits: u16) type{#endsyntax#}</pre>
|
||||
<p>Returns an integer type with the given signedness and bit width.</p>
|
||||
<p>For instance, {#syntax#}@Int(.unsigned, 18){#endsyntax#} returns the type {#syntax#}u18{#endsyntax#}.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Tuple#}
|
||||
<pre>{#syntax#}@Tuple(comptime field_types: []const type) type{#endsyntax#}</pre>
|
||||
<p>Returns a {#link|tuple|Tuples#} type with the given field types.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Pointer#}
|
||||
<pre>{#syntax#}@Pointer(
|
||||
comptime size: std.builtin.Type.Pointer.Size,
|
||||
comptime attrs: std.builtin.Type.Pointer.Attributes,
|
||||
comptime Element: type,
|
||||
comptime sentinel: ?Element,
|
||||
) type{#endsyntax#}</pre>
|
||||
<p>Returns a {#link|pointer|Pointers#} type with the properties specified by the arguments.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Fn#}
|
||||
<pre>{#syntax#}@Fn(
|
||||
comptime param_types: []const type,
|
||||
comptime param_attrs: *const [param_types.len]std.builtin.Type.Fn.Param.Attributes,
|
||||
comptime ReturnType: type,
|
||||
comptime attrs: std.builtin.Type.Fn.Attributes,
|
||||
) type{#endsyntax#}</pre>
|
||||
<p>Returns a {#link|function|Functions#} type with the properties specified by the arguments.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Struct#}
|
||||
<pre>{#syntax#}@Struct(
|
||||
comptime layout: std.builtin.Type.ContainerLayout,
|
||||
comptime BackingInt: ?type,
|
||||
comptime field_names: []const []const u8,
|
||||
comptime field_types: *const [field_names.len]type,
|
||||
comptime field_attrs: *const [field_names.len]std.builtin.Type.StructField.Attributes,
|
||||
) type{#endsyntax#}</pre>
|
||||
<p>Returns a {#link|struct#} type with the properties specified by the arguments.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Union#}
|
||||
<pre>{#syntax#}@Union(
|
||||
comptime layout: std.builtin.Type.ContainerLayout,
|
||||
/// Either the integer tag type, or the integer backing type, depending on `layout`.
|
||||
comptime ArgType: ?type,
|
||||
comptime field_names: []const []const u8,
|
||||
comptime field_types: *const [field_names.len]type,
|
||||
comptime field_attrs: *const [field_names.len]std.builtin.Type.UnionField.Attributes,
|
||||
) type{#endsyntax#}</pre>
|
||||
<p>Returns a {#link|union#} type with the properties specified by the arguments.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@Enum#}
|
||||
<pre>{#syntax#}@Enum(
|
||||
comptime TagInt: type,
|
||||
comptime mode: std.builtin.Type.Enum.Mode,
|
||||
comptime field_names: []const []const u8,
|
||||
comptime field_values: *const [field_names.len]TagInt,
|
||||
) type{#endsyntax#}</pre>
|
||||
<p>Returns an {#link|enum#} type with the properties specified by the arguments.</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@typeInfo#}
|
||||
<pre>{#syntax#}@typeInfo(comptime T: type) std.builtin.Type{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
||||
@@ -11,7 +11,7 @@ pub const std_options: std.Options = .{
|
||||
|
||||
fn myLogFn(
|
||||
comptime level: std.log.Level,
|
||||
comptime scope: @Type(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
|
||||
@@ -41,7 +41,7 @@ test "coercion between unions and enums" {
|
||||
try expect(u_4.tag() == 1);
|
||||
|
||||
// The following example is invalid.
|
||||
// error: coercion from enum '@TypeOf(.enum_literal)' to union 'test_coerce_unions_enum.U2' must initialize 'f32' field 'b'
|
||||
// error: coercion from enum '@EnumLiteral()' to union 'test_coerce_unions_enum.U2' must initialize 'f32' field 'b'
|
||||
//var u_5: U2 = .b;
|
||||
//try expect(u_5.tag() == 2);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noretu
|
||||
|
||||
fn logFn(
|
||||
comptime message_level: log.Level,
|
||||
comptime scope: @TypeOf(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
|
||||
Vendored
+6
-16
@@ -717,23 +717,13 @@ pub const Tag = std.meta.DeclEnum(attributes);
|
||||
|
||||
pub const Arguments = blk: {
|
||||
const decls = @typeInfo(attributes).@"struct".decls;
|
||||
var union_fields: [decls.len]ZigType.UnionField = undefined;
|
||||
for (decls, &union_fields) |decl, *field| {
|
||||
field.* = .{
|
||||
.name = decl.name,
|
||||
.type = @field(attributes, decl.name),
|
||||
.alignment = @alignOf(@field(attributes, decl.name)),
|
||||
};
|
||||
var names: [decls.len][]const u8 = undefined;
|
||||
var types: [decls.len]type = undefined;
|
||||
for (decls, &names, &types) |decl, *name, *T| {
|
||||
name.* = decl.name;
|
||||
T.* = @field(attributes, decl.name);
|
||||
}
|
||||
|
||||
break :blk @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = null,
|
||||
.fields = &union_fields,
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
break :blk @Union(.auto, null, &names, &types, &@splat(.{}));
|
||||
};
|
||||
|
||||
pub fn ArgumentsForTag(comptime tag: Tag) type {
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ fn serializeFloat(comptime T: type, value: T, w: *std.Io.Writer) !void {
|
||||
else => {
|
||||
const size = @bitSizeOf(T);
|
||||
const storage_unit = std.meta.intToEnum(StorageUnit, size) catch unreachable;
|
||||
const IntTy = @Type(.{ .int = .{ .signedness = .unsigned, .bits = size } });
|
||||
const IntTy = @Int(.unsigned, size);
|
||||
const int_val: IntTy = @bitCast(value);
|
||||
return serializeInt(int_val, storage_unit, w);
|
||||
},
|
||||
|
||||
+7
-6
@@ -179,12 +179,13 @@ pub const UnsupportedCodePage = enum(u16) {
|
||||
|
||||
pub const CodePage = blk: {
|
||||
const fields = @typeInfo(SupportedCodePage).@"enum".fields ++ @typeInfo(UnsupportedCodePage).@"enum".fields;
|
||||
break :blk @Type(.{ .@"enum" = .{
|
||||
.tag_type = u16,
|
||||
.decls = &.{},
|
||||
.fields = fields,
|
||||
.is_exhaustive = true,
|
||||
} });
|
||||
var field_names: [fields.len][]const u8 = undefined;
|
||||
var field_values: [fields.len]u16 = undefined;
|
||||
for (fields, &field_names, &field_values) |field, *name, *val| {
|
||||
name.* = field.name;
|
||||
val.* = field.value;
|
||||
}
|
||||
break :blk @Enum(u16, .exhaustive, &field_names, &field_values);
|
||||
};
|
||||
|
||||
pub fn isSupported(code_page: CodePage) bool {
|
||||
|
||||
Vendored
+12
-9
@@ -862,20 +862,23 @@ pub const ErrorDetails = struct {
|
||||
pub const ErrorDetailsWithoutCodePage = blk: {
|
||||
const details_info = @typeInfo(ErrorDetails);
|
||||
const fields = details_info.@"struct".fields;
|
||||
var fields_without_codepage: [fields.len - 1]std.builtin.Type.StructField = undefined;
|
||||
var field_names: [fields.len - 1][]const u8 = undefined;
|
||||
var field_types: [fields.len - 1]type = undefined;
|
||||
var field_attrs: [fields.len - 1]std.builtin.Type.StructField.Attributes = undefined;
|
||||
var i: usize = 0;
|
||||
for (fields) |field| {
|
||||
if (std.mem.eql(u8, field.name, "code_page")) continue;
|
||||
fields_without_codepage[i] = field;
|
||||
field_names[i] = field.name;
|
||||
field_types[i] = field.type;
|
||||
field_attrs[i] = .{
|
||||
.@"comptime" = field.is_comptime,
|
||||
.@"align" = field.alignment,
|
||||
.default_value_ptr = field.default_value_ptr,
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
std.debug.assert(i == fields_without_codepage.len);
|
||||
break :blk @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &fields_without_codepage,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
std.debug.assert(i == fields.len - 1);
|
||||
break :blk @Struct(.auto, null, &field_names, &field_types, &field_attrs);
|
||||
};
|
||||
|
||||
fn cellCount(code_page: SupportedCodePage, source: []const u8, start_index: usize, end_index: usize) usize {
|
||||
|
||||
@@ -298,7 +298,7 @@ fn mainTerminal() void {
|
||||
|
||||
pub fn log(
|
||||
comptime message_level: std.log.Level,
|
||||
comptime scope: @Type(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
|
||||
@@ -290,10 +290,7 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn
|
||||
pub inline fn fneg(a: anytype) @TypeOf(a) {
|
||||
const F = @TypeOf(a);
|
||||
const bits = @typeInfo(F).float.bits;
|
||||
const U = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = bits,
|
||||
} });
|
||||
const U = @Int(.unsigned, bits);
|
||||
const sign_bit_mask = @as(U, 1) << (bits - 1);
|
||||
const negated = @as(U, @bitCast(a)) ^ sign_bit_mask;
|
||||
return @bitCast(negated);
|
||||
|
||||
@@ -66,17 +66,17 @@ pub inline fn floatFromBigInt(comptime T: type, comptime signedness: std.builtin
|
||||
switch (x.len) {
|
||||
0 => return 0,
|
||||
inline 1...4 => |limbs_len| return @floatFromInt(@as(
|
||||
@Type(.{ .int = .{ .signedness = signedness, .bits = 32 * limbs_len } }),
|
||||
@Int(signedness, 32 * limbs_len),
|
||||
@bitCast(x[0..limbs_len].*),
|
||||
)),
|
||||
else => {},
|
||||
}
|
||||
|
||||
// sign implicit fraction round sticky
|
||||
const I = comptime @Type(.{ .int = .{
|
||||
.signedness = signedness,
|
||||
.bits = @as(u16, @intFromBool(signedness == .signed)) + 1 + math.floatFractionalBits(T) + 1 + 1,
|
||||
} });
|
||||
const I = comptime @Int(
|
||||
signedness,
|
||||
@as(u16, @intFromBool(signedness == .signed)) + 1 + math.floatFractionalBits(T) + 1 + 1,
|
||||
);
|
||||
|
||||
const clrsb = clrsb: {
|
||||
var clsb: usize = 0;
|
||||
|
||||
@@ -56,7 +56,7 @@ pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, resul
|
||||
0 => return,
|
||||
inline 1...4 => |limbs_len| {
|
||||
result[0..limbs_len].* = @bitCast(@as(
|
||||
@Type(.{ .int = .{ .signedness = signedness, .bits = 32 * limbs_len } }),
|
||||
@Int(signedness, 32 * limbs_len),
|
||||
@intFromFloat(a),
|
||||
));
|
||||
return;
|
||||
@@ -66,10 +66,7 @@ pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, resul
|
||||
|
||||
// sign implicit fraction
|
||||
const significand_bits = 1 + math.floatFractionalBits(@TypeOf(a));
|
||||
const I = @Type(comptime .{ .int = .{
|
||||
.signedness = signedness,
|
||||
.bits = @as(u16, @intFromBool(signedness == .signed)) + significand_bits,
|
||||
} });
|
||||
const I = @Int(signedness, @as(u16, @intFromBool(signedness == .signed)) + significand_bits);
|
||||
|
||||
const parts = math.frexp(a);
|
||||
const significand_bits_adjusted_to_handle_smin = @as(i32, significand_bits) +
|
||||
|
||||
@@ -159,7 +159,7 @@ inline fn copyFixedLength(
|
||||
else if (len > @sizeOf(usize))
|
||||
@Vector(len, u8)
|
||||
else
|
||||
@Type(.{ .int = .{ .signedness = .unsigned, .bits = len * 8 } });
|
||||
@Int(.unsigned, len * 8);
|
||||
|
||||
const loop_count = @divExact(len, @sizeOf(T));
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ pub fn panic(msg: []const u8, st: ?*std.builtin.StackTrace, addr: ?usize) noretu
|
||||
|
||||
fn logFn(
|
||||
comptime message_level: log.Level,
|
||||
comptime scope: @TypeOf(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ pub const std_options = std.Options{
|
||||
|
||||
fn logOverride(
|
||||
comptime level: std.log.Level,
|
||||
comptime scope: @Type(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
|
||||
+3
-11
@@ -416,7 +416,7 @@ fn createChildOnly(
|
||||
fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap {
|
||||
var map = UserInputOptionsMap.init(arena);
|
||||
inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
|
||||
if (field.type == @Type(.null)) continue;
|
||||
if (field.type == @TypeOf(null)) continue;
|
||||
addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name));
|
||||
}
|
||||
return map;
|
||||
@@ -526,16 +526,11 @@ fn addUserInputOptionFromArg(
|
||||
.pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.one => switch (@typeInfo(ptr_info.child)) {
|
||||
.array => |array_info| {
|
||||
comptime var slice_info = ptr_info;
|
||||
slice_info.size = .slice;
|
||||
slice_info.is_const = true;
|
||||
slice_info.child = array_info.child;
|
||||
slice_info.sentinel_ptr = null;
|
||||
addUserInputOptionFromArg(
|
||||
arena,
|
||||
map,
|
||||
field,
|
||||
@Type(.{ .pointer = slice_info }),
|
||||
@Pointer(.slice, .{ .@"const" = true }, array_info.child, null),
|
||||
maybe_value orelse null,
|
||||
);
|
||||
return;
|
||||
@@ -553,14 +548,11 @@ fn addUserInputOptionFromArg(
|
||||
}) catch @panic("OOM");
|
||||
},
|
||||
else => {
|
||||
comptime var slice_info = ptr_info;
|
||||
slice_info.is_const = true;
|
||||
slice_info.sentinel_ptr = null;
|
||||
addUserInputOptionFromArg(
|
||||
arena,
|
||||
map,
|
||||
field,
|
||||
@Type(.{ .pointer = slice_info }),
|
||||
@Pointer(ptr_info.size, .{ .@"const" = true }, ptr_info.child, null),
|
||||
maybe_value orelse null,
|
||||
);
|
||||
return;
|
||||
|
||||
+8
-32
@@ -528,23 +528,7 @@ pub fn Poller(comptime StreamEnum: type) type {
|
||||
/// Given an enum, returns a struct with fields of that enum, each field
|
||||
/// representing an I/O stream for polling.
|
||||
pub fn PollFiles(comptime StreamEnum: type) type {
|
||||
const enum_fields = @typeInfo(StreamEnum).@"enum".fields;
|
||||
var struct_fields: [enum_fields.len]std.builtin.Type.StructField = undefined;
|
||||
for (&struct_fields, enum_fields) |*struct_field, enum_field| {
|
||||
struct_field.* = .{
|
||||
.name = enum_field.name,
|
||||
.type = std.fs.File,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(std.fs.File),
|
||||
};
|
||||
}
|
||||
return @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &struct_fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
return @Struct(.auto, null, std.meta.fieldNames(StreamEnum), &@splat(std.fs.File), &@splat(.{}));
|
||||
}
|
||||
|
||||
test {
|
||||
@@ -1625,22 +1609,14 @@ pub fn sleep(io: Io, duration: Duration, clock: Clock) SleepError!void {
|
||||
/// fields, each field type the future's result.
|
||||
pub fn SelectUnion(S: type) type {
|
||||
const struct_fields = @typeInfo(S).@"struct".fields;
|
||||
var fields: [struct_fields.len]std.builtin.Type.UnionField = undefined;
|
||||
for (&fields, struct_fields) |*union_field, struct_field| {
|
||||
const F = @typeInfo(struct_field.type).pointer.child;
|
||||
const Result = @TypeOf(@as(F, undefined).result);
|
||||
union_field.* = .{
|
||||
.name = struct_field.name,
|
||||
.type = Result,
|
||||
.alignment = struct_field.alignment,
|
||||
};
|
||||
var names: [struct_fields.len][]const u8 = undefined;
|
||||
var types: [struct_fields.len]type = undefined;
|
||||
for (struct_fields, &names, &types) |struct_field, *union_field_name, *UnionFieldType| {
|
||||
const FieldFuture = @typeInfo(struct_field.type).pointer.child;
|
||||
union_field_name.* = struct_field.name;
|
||||
UnionFieldType.* = @FieldType(FieldFuture, "result");
|
||||
}
|
||||
return @Type(.{ .@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = std.meta.FieldEnum(S),
|
||||
.fields = &fields,
|
||||
.decls = &.{},
|
||||
} });
|
||||
return @Union(.auto, std.meta.FieldEnum(S), &names, &types, &@splat(.{}));
|
||||
}
|
||||
|
||||
/// `s` is a struct with every field a `*Future(T)`, where `T` can be any type,
|
||||
|
||||
@@ -1273,20 +1273,17 @@ pub const TakeLeb128Error = Error || error{Overflow};
|
||||
/// Read a single LEB128 value as type T, or `error.Overflow` if the value cannot fit.
|
||||
pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
|
||||
const result_info = @typeInfo(Result).int;
|
||||
return std.math.cast(Result, try r.takeMultipleOf7Leb128(@Type(.{ .int = .{
|
||||
.signedness = result_info.signedness,
|
||||
.bits = std.mem.alignForwardAnyAlign(u16, result_info.bits, 7),
|
||||
} }))) orelse error.Overflow;
|
||||
return std.math.cast(Result, try r.takeMultipleOf7Leb128(@Int(
|
||||
result_info.signedness,
|
||||
std.mem.alignForwardAnyAlign(u16, result_info.bits, 7),
|
||||
))) orelse error.Overflow;
|
||||
}
|
||||
|
||||
fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
|
||||
const result_info = @typeInfo(Result).int;
|
||||
comptime assert(result_info.bits % 7 == 0);
|
||||
var remaining_bits: std.math.Log2IntCeil(Result) = result_info.bits;
|
||||
const UnsignedResult = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = result_info.bits,
|
||||
} });
|
||||
const UnsignedResult = @Int(.unsigned, result_info.bits);
|
||||
var result: UnsignedResult = 0;
|
||||
var fits = true;
|
||||
while (true) {
|
||||
|
||||
+10
-10
@@ -1890,7 +1890,7 @@ pub fn writeUleb128(w: *Writer, value: anytype) Error!void {
|
||||
try w.writeLeb128(switch (@typeInfo(@TypeOf(value))) {
|
||||
.comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value),
|
||||
.int => |value_info| switch (value_info.signedness) {
|
||||
.signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)),
|
||||
.signed => @as(@Int(.unsigned, value_info.bits -| 1), @intCast(value)),
|
||||
.unsigned => value,
|
||||
},
|
||||
else => comptime unreachable,
|
||||
@@ -1903,7 +1903,7 @@ pub fn writeSleb128(w: *Writer, value: anytype) Error!void {
|
||||
.comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value),
|
||||
.int => |value_info| switch (value_info.signedness) {
|
||||
.signed => value,
|
||||
.unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value),
|
||||
.unsigned => @as(@Int(.signed, value_info.bits + 1), value),
|
||||
},
|
||||
else => comptime unreachable,
|
||||
});
|
||||
@@ -1912,10 +1912,10 @@ pub fn writeSleb128(w: *Writer, value: anytype) Error!void {
|
||||
/// Write a single integer as LEB128 to the given writer.
|
||||
pub fn writeLeb128(w: *Writer, value: anytype) Error!void {
|
||||
const value_info = @typeInfo(@TypeOf(value)).int;
|
||||
try w.writeMultipleOf7Leb128(@as(@Type(.{ .int = .{
|
||||
.signedness = value_info.signedness,
|
||||
.bits = @max(std.mem.alignForwardAnyAlign(u16, value_info.bits, 7), 7),
|
||||
} }), value));
|
||||
try w.writeMultipleOf7Leb128(@as(@Int(
|
||||
value_info.signedness,
|
||||
@max(std.mem.alignForwardAnyAlign(u16, value_info.bits, 7), 7),
|
||||
), value));
|
||||
}
|
||||
|
||||
fn writeMultipleOf7Leb128(w: *Writer, value: anytype) Error!void {
|
||||
@@ -1929,10 +1929,10 @@ fn writeMultipleOf7Leb128(w: *Writer, value: anytype) Error!void {
|
||||
.unsigned => remaining > std.math.maxInt(u7),
|
||||
};
|
||||
byte.* = .{
|
||||
.bits = @bitCast(@as(@Type(.{ .int = .{
|
||||
.signedness = value_info.signedness,
|
||||
.bits = 7,
|
||||
} }), @truncate(remaining))),
|
||||
.bits = @bitCast(@as(
|
||||
@Int(value_info.signedness, 7),
|
||||
@truncate(remaining),
|
||||
)),
|
||||
.more = more,
|
||||
};
|
||||
if (value_info.bits > 7) remaining >>= 7;
|
||||
|
||||
+50
-9
@@ -548,19 +548,19 @@ pub const TypeId = std.meta.Tag(Type);
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Type = union(enum) {
|
||||
type: void,
|
||||
void: void,
|
||||
bool: void,
|
||||
noreturn: void,
|
||||
type,
|
||||
void,
|
||||
bool,
|
||||
noreturn,
|
||||
int: Int,
|
||||
float: Float,
|
||||
pointer: Pointer,
|
||||
array: Array,
|
||||
@"struct": Struct,
|
||||
comptime_float: void,
|
||||
comptime_int: void,
|
||||
undefined: void,
|
||||
null: void,
|
||||
comptime_float,
|
||||
comptime_int,
|
||||
undefined,
|
||||
null,
|
||||
optional: Optional,
|
||||
error_union: ErrorUnion,
|
||||
error_set: ErrorSet,
|
||||
@@ -571,7 +571,7 @@ pub const Type = union(enum) {
|
||||
frame: Frame,
|
||||
@"anyframe": AnyFrame,
|
||||
vector: Vector,
|
||||
enum_literal: void,
|
||||
enum_literal,
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
@@ -619,6 +619,16 @@ pub const Type = union(enum) {
|
||||
slice,
|
||||
c,
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Attributes = struct {
|
||||
@"const": bool = false,
|
||||
@"volatile": bool = false,
|
||||
@"allowzero": bool = false,
|
||||
@"addrspace": ?AddressSpace = null,
|
||||
@"align": ?usize = null,
|
||||
};
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
@@ -668,6 +678,14 @@ pub const Type = union(enum) {
|
||||
const dp: *const sf.type = @ptrCast(@alignCast(sf.default_value_ptr orelse return null));
|
||||
return dp.*;
|
||||
}
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Attributes = struct {
|
||||
@"comptime": bool = false,
|
||||
@"align": ?usize = null,
|
||||
default_value_ptr: ?*const anyopaque = null,
|
||||
};
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
@@ -718,6 +736,10 @@ pub const Type = union(enum) {
|
||||
fields: []const EnumField,
|
||||
decls: []const Declaration,
|
||||
is_exhaustive: bool,
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Mode = enum { exhaustive, nonexhaustive };
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
@@ -726,6 +748,12 @@ pub const Type = union(enum) {
|
||||
name: [:0]const u8,
|
||||
type: type,
|
||||
alignment: comptime_int,
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Attributes = struct {
|
||||
@"align": ?usize = null,
|
||||
};
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
@@ -753,6 +781,19 @@ pub const Type = union(enum) {
|
||||
is_generic: bool,
|
||||
is_noalias: bool,
|
||||
type: ?type,
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Attributes = struct {
|
||||
@"noalias": bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const Attributes = struct {
|
||||
@"callconv": CallingConvention = .auto,
|
||||
varargs: bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -94,12 +94,12 @@ pub fn deserialize(comptime HashResult: type, str: []const u8) Error!HashResult
|
||||
if (kvSplit(field)) |opt_version| {
|
||||
if (mem.eql(u8, opt_version.key, version_param_name)) {
|
||||
if (@hasField(HashResult, "alg_version")) {
|
||||
const value_type_info = switch (@typeInfo(@TypeOf(out.alg_version))) {
|
||||
.optional => |opt| @typeInfo(opt.child),
|
||||
else => |t| t,
|
||||
const ValueType = switch (@typeInfo(@TypeOf(out.alg_version))) {
|
||||
.optional => |opt| opt.child,
|
||||
else => @TypeOf(out.alg_version),
|
||||
};
|
||||
out.alg_version = fmt.parseUnsigned(
|
||||
@Type(value_type_info),
|
||||
ValueType,
|
||||
opt_version.value,
|
||||
10,
|
||||
) catch return Error.InvalidEncoding;
|
||||
|
||||
@@ -606,7 +606,7 @@ pub fn array(
|
||||
const elem_size = @divExact(@bitSizeOf(Elem), 8);
|
||||
var arr: [len_size + elem_size * elems.len]u8 = undefined;
|
||||
std.mem.writeInt(Len, arr[0..len_size], @intCast(elem_size * elems.len), .big);
|
||||
const ElemInt = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Elem) } });
|
||||
const ElemInt = @Int(.unsigned, @bitSizeOf(Elem));
|
||||
for (0.., @as([elems.len]Elem, elems)) |index, elem| {
|
||||
std.mem.writeInt(
|
||||
ElemInt,
|
||||
|
||||
+11
-29
@@ -33,22 +33,8 @@ pub fn fromInt(comptime E: type, integer: anytype) ?E {
|
||||
/// default, which may be undefined.
|
||||
pub fn EnumFieldStruct(comptime E: type, comptime Data: type, comptime field_default: ?Data) type {
|
||||
@setEvalBranchQuota(@typeInfo(E).@"enum".fields.len + eval_branch_quota_cushion);
|
||||
var struct_fields: [@typeInfo(E).@"enum".fields.len]std.builtin.Type.StructField = undefined;
|
||||
for (&struct_fields, @typeInfo(E).@"enum".fields) |*struct_field, enum_field| {
|
||||
struct_field.* = .{
|
||||
.name = enum_field.name,
|
||||
.type = Data,
|
||||
.default_value_ptr = if (field_default) |d| @as(?*const anyopaque, @ptrCast(&d)) else null,
|
||||
.is_comptime = false,
|
||||
.alignment = if (@sizeOf(Data) > 0) @alignOf(Data) else 0,
|
||||
};
|
||||
}
|
||||
return @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &struct_fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
const default_ptr: ?*const anyopaque = if (field_default) |d| @ptrCast(&d) else null;
|
||||
return @Struct(.auto, null, std.meta.fieldNames(E), &@splat(Data), &@splat(.{ .default_value_ptr = default_ptr }));
|
||||
}
|
||||
|
||||
/// Looks up the supplied fields in the given enum type.
|
||||
@@ -1532,19 +1518,15 @@ test "EnumIndexer empty" {
|
||||
test "EnumIndexer large dense unsorted" {
|
||||
@setEvalBranchQuota(500_000); // many `comptimePrint`s
|
||||
// Make an enum with 500 fields with values in *descending* order.
|
||||
const E = @Type(.{ .@"enum" = .{
|
||||
.tag_type = u32,
|
||||
.fields = comptime fields: {
|
||||
var fields: [500]EnumField = undefined;
|
||||
for (&fields, 0..) |*f, i| f.* = .{
|
||||
.name = std.fmt.comptimePrint("f{d}", .{i}),
|
||||
.value = 500 - i,
|
||||
};
|
||||
break :fields &fields;
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
} });
|
||||
const E = @Enum(u32, .exhaustive, names: {
|
||||
var names: [500][]const u8 = undefined;
|
||||
for (&names, 0..) |*name, i| name.* = std.fmt.comptimePrint("f{d}", .{i});
|
||||
break :names &names;
|
||||
}, vals: {
|
||||
var vals: [500]u32 = undefined;
|
||||
for (&vals, 0..) |*val, i| val.* = 500 - i;
|
||||
break :vals &vals;
|
||||
});
|
||||
const Indexer = EnumIndexer(E);
|
||||
try testing.expectEqual(E.f0, Indexer.keyForIndex(499));
|
||||
try testing.expectEqual(E.f499, Indexer.keyForIndex(0));
|
||||
|
||||
+1
-1
@@ -279,7 +279,7 @@ pub fn Alt(
|
||||
/// Helper for calling alternate format methods besides one named "format".
|
||||
pub fn alt(
|
||||
context: anytype,
|
||||
comptime func_name: @TypeOf(.enum_literal),
|
||||
comptime func_name: @EnumLiteral(),
|
||||
) Alt(@TypeOf(context), @field(@TypeOf(context), @tagName(func_name))) {
|
||||
return .{ .data = context };
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ pub fn render(buf: []u8, value: anytype, options: Options) Error![]const u8 {
|
||||
|
||||
const T = @TypeOf(v);
|
||||
comptime std.debug.assert(@typeInfo(T) == .float);
|
||||
const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
|
||||
const I = @Int(.unsigned, @bitSizeOf(T));
|
||||
|
||||
const DT = if (@bitSizeOf(T) <= 64) u64 else u128;
|
||||
const tables = switch (DT) {
|
||||
@@ -1516,7 +1516,7 @@ const FLOAT128_POW5_INV_ERRORS: [154]u64 = .{
|
||||
const builtin = @import("builtin");
|
||||
|
||||
fn check(comptime T: type, value: T, comptime expected: []const u8) !void {
|
||||
const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
|
||||
const I = @Int(.unsigned, @bitSizeOf(T));
|
||||
|
||||
var buf: [6000]u8 = undefined;
|
||||
const value_bits: I = @bitCast(value);
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ pub fn int(input: anytype) @TypeOf(input) {
|
||||
const info = @typeInfo(@TypeOf(input)).int;
|
||||
const bits = info.bits;
|
||||
// Convert input to unsigned integer (easier to deal with)
|
||||
const Uint = @Type(.{ .int = .{ .bits = bits, .signedness = .unsigned } });
|
||||
const Uint = @Int(.unsigned, bits);
|
||||
const u_input: Uint = @bitCast(input);
|
||||
if (bits > 256) @compileError("bit widths > 256 are unsupported, use std.hash.autoHash functionality.");
|
||||
// For bit widths that don't have a dedicated function, use a heuristic
|
||||
|
||||
@@ -91,10 +91,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
|
||||
// Help the optimizer see that hashing an int is easy by inlining!
|
||||
// TODO Check if the situation is better after #561 is resolved.
|
||||
.int => |int| switch (int.signedness) {
|
||||
.signed => hash(hasher, @as(@Type(.{ .int = .{
|
||||
.bits = int.bits,
|
||||
.signedness = .unsigned,
|
||||
} }), @bitCast(key)), strat),
|
||||
.signed => hash(hasher, @as(@Int(.unsigned, int.bits), @bitCast(key)), strat),
|
||||
.unsigned => {
|
||||
if (std.meta.hasUniqueRepresentation(Key)) {
|
||||
@call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) });
|
||||
|
||||
+5
-5
@@ -57,13 +57,13 @@ pub const default_level: Level = switch (builtin.mode) {
|
||||
};
|
||||
|
||||
pub const ScopeLevel = struct {
|
||||
scope: @Type(.enum_literal),
|
||||
scope: @EnumLiteral(),
|
||||
level: Level,
|
||||
};
|
||||
|
||||
fn log(
|
||||
comptime level: Level,
|
||||
comptime scope: @Type(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
@@ -73,7 +73,7 @@ fn log(
|
||||
}
|
||||
|
||||
/// Determine if a specific log message level and scope combination are enabled for logging.
|
||||
pub fn logEnabled(comptime level: Level, comptime scope: @Type(.enum_literal)) bool {
|
||||
pub fn logEnabled(comptime level: Level, comptime scope: @EnumLiteral()) bool {
|
||||
inline for (std.options.log_scope_levels) |scope_level| {
|
||||
if (scope_level.scope == scope) return @intFromEnum(level) <= @intFromEnum(scope_level.level);
|
||||
}
|
||||
@@ -87,7 +87,7 @@ pub fn logEnabled(comptime level: Level, comptime scope: @Type(.enum_literal)) b
|
||||
/// function returns.
|
||||
pub fn defaultLog(
|
||||
comptime level: Level,
|
||||
comptime scope: @Type(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
@@ -115,7 +115,7 @@ pub fn defaultLog(
|
||||
|
||||
/// Returns a scoped logging namespace that logs all messages using the scope
|
||||
/// provided here.
|
||||
pub fn scoped(comptime scope: @Type(.enum_literal)) type {
|
||||
pub fn scoped(comptime scope: @EnumLiteral()) type {
|
||||
return struct {
|
||||
/// Log an error message. This log level is intended to be used
|
||||
/// when something has gone wrong. This might be recoverable or might
|
||||
|
||||
+13
-13
@@ -450,12 +450,7 @@ pub fn wrap(x: anytype, r: anytype) @TypeOf(x) {
|
||||
// in the rare usecase of r not being comptime_int or float,
|
||||
// take the penalty of having an intermediary type conversion,
|
||||
// otherwise the alternative is to unwind iteratively to avoid overflow
|
||||
const R = comptime do: {
|
||||
var info = info_r;
|
||||
info.int.bits += 1;
|
||||
info.int.signedness = .signed;
|
||||
break :do @Type(info);
|
||||
};
|
||||
const R = @Int(.signed, info_r.int.bits + 1);
|
||||
const radius: if (info_r.int.signedness == .signed) @TypeOf(r) else R = r;
|
||||
return @intCast(@mod(x - radius, 2 * @as(R, r)) - r); // provably impossible to overflow
|
||||
},
|
||||
@@ -799,14 +794,14 @@ pub fn Log2IntCeil(comptime T: type) type {
|
||||
pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {
|
||||
assert(from <= to);
|
||||
const signedness: std.builtin.Signedness = if (from < 0) .signed else .unsigned;
|
||||
return @Type(.{ .int = .{
|
||||
.signedness = signedness,
|
||||
.bits = @as(u16, @intFromBool(signedness == .signed)) +
|
||||
return @Int(
|
||||
signedness,
|
||||
@as(u16, @intFromBool(signedness == .signed)) +
|
||||
switch (if (from < 0) @max(@abs(from) - 1, to) else to) {
|
||||
0 => 0,
|
||||
else => |pos_max| 1 + log2(pos_max),
|
||||
},
|
||||
} });
|
||||
);
|
||||
}
|
||||
|
||||
test IntFittingRange {
|
||||
@@ -1107,9 +1102,14 @@ test cast {
|
||||
pub const AlignCastError = error{UnalignedMemory};
|
||||
|
||||
fn AlignCastResult(comptime alignment: Alignment, comptime Ptr: type) type {
|
||||
var ptr_info = @typeInfo(Ptr);
|
||||
ptr_info.pointer.alignment = alignment.toByteUnits();
|
||||
return @Type(ptr_info);
|
||||
const orig = @typeInfo(Ptr).pointer;
|
||||
return @Pointer(orig.size, .{
|
||||
.@"const" = orig.is_const,
|
||||
.@"volatile" = orig.is_volatile,
|
||||
.@"allowzero" = orig.is_allowzero,
|
||||
.@"align" = alignment.toByteUnits(),
|
||||
.@"addrspace" = orig.address_space,
|
||||
}, orig.child, orig.sentinel());
|
||||
}
|
||||
|
||||
/// Align cast a pointer but return an error if it's the wrong alignment
|
||||
|
||||
@@ -2787,11 +2787,11 @@ test "bitNotWrap more than two limbs" {
|
||||
const bits = @bitSizeOf(Limb) * 4 + 2;
|
||||
|
||||
try res.bitNotWrap(&a, .unsigned, bits);
|
||||
const Unsigned = @Type(.{ .int = .{ .signedness = .unsigned, .bits = bits } });
|
||||
const Unsigned = @Int(.unsigned, bits);
|
||||
try testing.expectEqual((try res.toInt(Unsigned)), ~@as(Unsigned, maxInt(Limb)));
|
||||
|
||||
try res.bitNotWrap(&a, .signed, bits);
|
||||
const Signed = @Type(.{ .int = .{ .signedness = .signed, .bits = bits } });
|
||||
const Signed = @Int(.signed, bits);
|
||||
try testing.expectEqual((try res.toInt(Signed)), ~@as(Signed, maxInt(Limb)));
|
||||
}
|
||||
|
||||
|
||||
+8
-26
@@ -14,22 +14,10 @@ pub fn FloatRepr(comptime Float: type) type {
|
||||
exponent: BiasedExponent,
|
||||
sign: std.math.Sign,
|
||||
|
||||
pub const StoredMantissa = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = floatMantissaBits(Float),
|
||||
} });
|
||||
pub const Mantissa = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = 1 + fractional_bits,
|
||||
} });
|
||||
pub const Exponent = @Type(.{ .int = .{
|
||||
.signedness = .signed,
|
||||
.bits = exponent_bits,
|
||||
} });
|
||||
pub const BiasedExponent = enum(@Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = exponent_bits,
|
||||
} })) {
|
||||
pub const StoredMantissa = @Int(.unsigned, floatMantissaBits(Float));
|
||||
pub const Mantissa = @Int(.unsigned, 1 + fractional_bits);
|
||||
pub const Exponent = @Int(.signed, exponent_bits);
|
||||
pub const BiasedExponent = enum(@Int(.unsigned, exponent_bits)) {
|
||||
denormal = 0,
|
||||
min_normal = 1,
|
||||
zero = (1 << (exponent_bits - 1)) - 1,
|
||||
@@ -56,14 +44,8 @@ pub fn FloatRepr(comptime Float: type) type {
|
||||
fraction: Fraction,
|
||||
exponent: Normalized.Exponent,
|
||||
|
||||
pub const Fraction = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = fractional_bits,
|
||||
} });
|
||||
pub const Exponent = @Type(.{ .int = .{
|
||||
.signedness = .signed,
|
||||
.bits = 1 + exponent_bits,
|
||||
} });
|
||||
pub const Fraction = @Int(.unsigned, fractional_bits);
|
||||
pub const Exponent = @Int(.signed, 1 + exponent_bits);
|
||||
|
||||
/// This currently truncates denormal values, which needs to be fixed before this can be used to
|
||||
/// produce a rounded value.
|
||||
@@ -122,7 +104,7 @@ inline fn mantissaOne(comptime T: type) comptime_int {
|
||||
|
||||
/// Creates floating point type T from an unbiased exponent and raw mantissa.
|
||||
inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T {
|
||||
const TBits = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
|
||||
const TBits = @Int(.unsigned, @bitSizeOf(T));
|
||||
const biased_exponent = @as(TBits, exponent + floatExponentMax(T));
|
||||
return @as(T, @bitCast((biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa)));
|
||||
}
|
||||
@@ -209,7 +191,7 @@ pub inline fn floatEps(comptime T: type) T {
|
||||
pub inline fn floatEpsAt(comptime T: type, x: T) T {
|
||||
switch (@typeInfo(T)) {
|
||||
.float => |F| {
|
||||
const U: type = @Type(.{ .int = .{ .signedness = .unsigned, .bits = F.bits } });
|
||||
const U: type = @Int(.unsigned, F.bits);
|
||||
const u: U = @bitCast(x);
|
||||
const y: T = @bitCast(u ^ 1);
|
||||
return @abs(x - y);
|
||||
|
||||
@@ -33,10 +33,7 @@ pub fn log2(x: anytype) @TypeOf(x) {
|
||||
return result;
|
||||
},
|
||||
.int => |int_info| math.log2_int(switch (int_info.signedness) {
|
||||
.signed => @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = int_info.bits -| 1,
|
||||
} }),
|
||||
.signed => @Int(.unsigned, int_info.bits -| 1),
|
||||
.unsigned => T,
|
||||
}, @intCast(x)),
|
||||
else => @compileError("log2 not implemented for " ++ @typeName(T)),
|
||||
|
||||
@@ -65,7 +65,7 @@ test "log_int" {
|
||||
// Test all unsigned integers with 2, 3, ..., 64 bits.
|
||||
// We cannot test 0 or 1 bits since base must be > 1.
|
||||
inline for (2..64 + 1) |bits| {
|
||||
const T = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @intCast(bits) } });
|
||||
const T = @Int(.unsigned, @intCast(bits));
|
||||
|
||||
// for base = 2, 3, ..., min(maxInt(T),1024)
|
||||
var base: T = 1;
|
||||
|
||||
@@ -6,10 +6,7 @@ const expect = std.testing.expect;
|
||||
pub fn signbit(x: anytype) bool {
|
||||
return switch (@typeInfo(@TypeOf(x))) {
|
||||
.int, .comptime_int => x,
|
||||
.float => |float| @as(@Type(.{ .int = .{
|
||||
.signedness = .signed,
|
||||
.bits = float.bits,
|
||||
} }), @bitCast(x)),
|
||||
.float => |float| @as(@Int(.signed, float.bits), @bitCast(x)),
|
||||
.comptime_float => @as(i128, @bitCast(@as(f128, x))), // any float type will do
|
||||
else => @compileError("std.math.signbit does not support " ++ @typeName(@TypeOf(x))),
|
||||
} < 0;
|
||||
|
||||
@@ -80,7 +80,7 @@ test sqrt_int {
|
||||
/// Returns the return type `sqrt` will return given an operand of type `T`.
|
||||
pub fn Sqrt(comptime T: type) type {
|
||||
return switch (@typeInfo(T)) {
|
||||
.int => |int| @Type(.{ .int = .{ .signedness = .unsigned, .bits = (int.bits + 1) / 2 } }),
|
||||
.int => |int| @Int(.unsigned, (int.bits + 1) / 2),
|
||||
else => T,
|
||||
};
|
||||
}
|
||||
|
||||
+57
-106
@@ -846,17 +846,18 @@ fn Span(comptime T: type) type {
|
||||
return ?Span(optional_info.child);
|
||||
},
|
||||
.pointer => |ptr_info| {
|
||||
var new_ptr_info = ptr_info;
|
||||
switch (ptr_info.size) {
|
||||
.c => {
|
||||
new_ptr_info.sentinel_ptr = &@as(ptr_info.child, 0);
|
||||
new_ptr_info.is_allowzero = false;
|
||||
},
|
||||
.many => if (ptr_info.sentinel() == null) @compileError("invalid type given to std.mem.span: " ++ @typeName(T)),
|
||||
const new_sentinel: ?ptr_info.child = switch (ptr_info.size) {
|
||||
.one, .slice => @compileError("invalid type given to std.mem.span: " ++ @typeName(T)),
|
||||
}
|
||||
new_ptr_info.size = .slice;
|
||||
return @Type(.{ .pointer = new_ptr_info });
|
||||
.many => ptr_info.sentinel() orelse @compileError("invalid type given to std.mem.span: " ++ @typeName(T)),
|
||||
.c => 0,
|
||||
};
|
||||
return @Pointer(.slice, .{
|
||||
.@"const" = ptr_info.is_const,
|
||||
.@"volatile" = ptr_info.is_volatile,
|
||||
.@"allowzero" = ptr_info.is_allowzero and ptr_info.size != .c,
|
||||
.@"align" = ptr_info.alignment,
|
||||
.@"addrspace" = ptr_info.address_space,
|
||||
}, ptr_info.child, new_sentinel);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@@ -910,45 +911,18 @@ fn SliceTo(comptime T: type, comptime end: std.meta.Elem(T)) type {
|
||||
return ?SliceTo(optional_info.child, end);
|
||||
},
|
||||
.pointer => |ptr_info| {
|
||||
var new_ptr_info = ptr_info;
|
||||
new_ptr_info.size = .slice;
|
||||
switch (ptr_info.size) {
|
||||
.one => switch (@typeInfo(ptr_info.child)) {
|
||||
.array => |array_info| {
|
||||
new_ptr_info.child = array_info.child;
|
||||
// The return type must only be sentinel terminated if we are guaranteed
|
||||
// to find the value searched for, which is only the case if it matches
|
||||
// the sentinel of the type passed.
|
||||
if (array_info.sentinel()) |s| {
|
||||
if (end == s) {
|
||||
new_ptr_info.sentinel_ptr = &end;
|
||||
} else {
|
||||
new_ptr_info.sentinel_ptr = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.many, .slice => {
|
||||
// The return type must only be sentinel terminated if we are guaranteed
|
||||
// to find the value searched for, which is only the case if it matches
|
||||
// the sentinel of the type passed.
|
||||
if (ptr_info.sentinel()) |s| {
|
||||
if (end == s) {
|
||||
new_ptr_info.sentinel_ptr = &end;
|
||||
} else {
|
||||
new_ptr_info.sentinel_ptr = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
.c => {
|
||||
new_ptr_info.sentinel_ptr = &end;
|
||||
// C pointers are always allowzero, but we don't want the return type to be.
|
||||
assert(new_ptr_info.is_allowzero);
|
||||
new_ptr_info.is_allowzero = false;
|
||||
},
|
||||
}
|
||||
return @Type(.{ .pointer = new_ptr_info });
|
||||
const Elem = std.meta.Elem(T);
|
||||
const have_sentinel: bool = switch (ptr_info.size) {
|
||||
.one, .slice, .many => if (std.meta.sentinel(T)) |s| s == end else false,
|
||||
.c => false,
|
||||
};
|
||||
return @Pointer(.slice, .{
|
||||
.@"const" = ptr_info.is_const,
|
||||
.@"volatile" = ptr_info.is_volatile,
|
||||
.@"allowzero" = ptr_info.is_allowzero and ptr_info.size != .c,
|
||||
.@"align" = ptr_info.alignment,
|
||||
.@"addrspace" = ptr_info.address_space,
|
||||
}, Elem, if (have_sentinel) end else null);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@@ -3951,38 +3925,25 @@ test reverse {
|
||||
}
|
||||
}
|
||||
fn ReverseIterator(comptime T: type) type {
|
||||
const Pointer = blk: {
|
||||
switch (@typeInfo(T)) {
|
||||
.pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.one => switch (@typeInfo(ptr_info.child)) {
|
||||
.array => |array_info| {
|
||||
var new_ptr_info = ptr_info;
|
||||
new_ptr_info.size = .many;
|
||||
new_ptr_info.child = array_info.child;
|
||||
new_ptr_info.sentinel_ptr = array_info.sentinel_ptr;
|
||||
break :blk @Type(.{ .pointer = new_ptr_info });
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.slice => {
|
||||
var new_ptr_info = ptr_info;
|
||||
new_ptr_info.size = .many;
|
||||
break :blk @Type(.{ .pointer = new_ptr_info });
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'");
|
||||
const ptr = switch (@typeInfo(T)) {
|
||||
.pointer => |ptr| ptr,
|
||||
else => @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'"),
|
||||
};
|
||||
const Element = std.meta.Elem(Pointer);
|
||||
const ElementPointer = @Type(.{ .pointer = ptr: {
|
||||
var ptr = @typeInfo(Pointer).pointer;
|
||||
ptr.size = .one;
|
||||
ptr.child = Element;
|
||||
ptr.sentinel_ptr = null;
|
||||
break :ptr ptr;
|
||||
} });
|
||||
switch (ptr.size) {
|
||||
.slice => {},
|
||||
.one => if (@typeInfo(ptr.child) != .array) @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'"),
|
||||
.many, .c => @compileError("expected slice or pointer to array, found '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
const Element = std.meta.Elem(T);
|
||||
const attrs: std.builtin.Type.Pointer.Attributes = .{
|
||||
.@"const" = ptr.is_const,
|
||||
.@"volatile" = ptr.is_volatile,
|
||||
.@"allowzero" = ptr.is_allowzero,
|
||||
.@"align" = ptr.alignment,
|
||||
.@"addrspace" = ptr.address_space,
|
||||
};
|
||||
const Pointer = @Pointer(.many, attrs, Element, std.meta.sentinel(T));
|
||||
const ElementPointer = @Pointer(.one, attrs, Element, null);
|
||||
return struct {
|
||||
ptr: Pointer,
|
||||
index: usize,
|
||||
@@ -4342,19 +4303,14 @@ fn CopyPtrAttrs(
|
||||
comptime size: std.builtin.Type.Pointer.Size,
|
||||
comptime child: type,
|
||||
) type {
|
||||
const info = @typeInfo(source).pointer;
|
||||
return @Type(.{
|
||||
.pointer = .{
|
||||
.size = size,
|
||||
.is_const = info.is_const,
|
||||
.is_volatile = info.is_volatile,
|
||||
.is_allowzero = info.is_allowzero,
|
||||
.alignment = info.alignment,
|
||||
.address_space = info.address_space,
|
||||
.child = child,
|
||||
.sentinel_ptr = null,
|
||||
},
|
||||
});
|
||||
const ptr = @typeInfo(source).pointer;
|
||||
return @Pointer(size, .{
|
||||
.@"const" = ptr.is_const,
|
||||
.@"volatile" = ptr.is_volatile,
|
||||
.@"allowzero" = ptr.is_allowzero,
|
||||
.@"align" = ptr.alignment,
|
||||
.@"addrspace" = ptr.address_space,
|
||||
}, child, null);
|
||||
}
|
||||
|
||||
fn AsBytesReturnType(comptime P: type) type {
|
||||
@@ -4936,19 +4892,14 @@ test "freeing empty string with null-terminated sentinel" {
|
||||
/// Returns a slice with the given new alignment,
|
||||
/// all other pointer attributes copied from `AttributeSource`.
|
||||
fn AlignedSlice(comptime AttributeSource: type, comptime new_alignment: usize) type {
|
||||
const info = @typeInfo(AttributeSource).pointer;
|
||||
return @Type(.{
|
||||
.pointer = .{
|
||||
.size = .slice,
|
||||
.is_const = info.is_const,
|
||||
.is_volatile = info.is_volatile,
|
||||
.is_allowzero = info.is_allowzero,
|
||||
.alignment = new_alignment,
|
||||
.address_space = info.address_space,
|
||||
.child = info.child,
|
||||
.sentinel_ptr = null,
|
||||
},
|
||||
});
|
||||
const ptr = @typeInfo(AttributeSource).pointer;
|
||||
return @Pointer(.slice, .{
|
||||
.@"const" = ptr.is_const,
|
||||
.@"volatile" = ptr.is_volatile,
|
||||
.@"allowzero" = ptr.is_allowzero,
|
||||
.@"align" = new_alignment,
|
||||
.@"addrspace" = ptr.address_space,
|
||||
}, ptr.child, null);
|
||||
}
|
||||
|
||||
/// Returns the largest slice in the given bytes that conforms to the new alignment,
|
||||
|
||||
+52
-136
@@ -171,58 +171,34 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
|
||||
switch (@typeInfo(T)) {
|
||||
.pointer => |info| switch (info.size) {
|
||||
.one => switch (@typeInfo(info.child)) {
|
||||
.array => |array_info| return @Type(.{
|
||||
.pointer = .{
|
||||
.size = info.size,
|
||||
.is_const = info.is_const,
|
||||
.is_volatile = info.is_volatile,
|
||||
.alignment = info.alignment,
|
||||
.address_space = info.address_space,
|
||||
.child = @Type(.{
|
||||
.array = .{
|
||||
.len = array_info.len,
|
||||
.child = array_info.child,
|
||||
.sentinel_ptr = @as(?*const anyopaque, @ptrCast(&sentinel_val)),
|
||||
},
|
||||
}),
|
||||
.is_allowzero = info.is_allowzero,
|
||||
.sentinel_ptr = info.sentinel_ptr,
|
||||
},
|
||||
}),
|
||||
.array => |array_info| return @Pointer(.one, .{
|
||||
.@"const" = info.is_const,
|
||||
.@"volatile" = info.is_volatile,
|
||||
.@"allowzero" = info.is_allowzero,
|
||||
.@"align" = info.alignment,
|
||||
.@"addrspace" = info.address_space,
|
||||
}, [array_info.len:sentinel_val]array_info.child, null),
|
||||
else => {},
|
||||
},
|
||||
.many, .slice => return @Type(.{
|
||||
.pointer = .{
|
||||
.size = info.size,
|
||||
.is_const = info.is_const,
|
||||
.is_volatile = info.is_volatile,
|
||||
.alignment = info.alignment,
|
||||
.address_space = info.address_space,
|
||||
.child = info.child,
|
||||
.is_allowzero = info.is_allowzero,
|
||||
.sentinel_ptr = @as(?*const anyopaque, @ptrCast(&sentinel_val)),
|
||||
},
|
||||
}),
|
||||
.many, .slice => |size| return @Pointer(size, .{
|
||||
.@"const" = info.is_const,
|
||||
.@"volatile" = info.is_volatile,
|
||||
.@"allowzero" = info.is_allowzero,
|
||||
.@"align" = info.alignment,
|
||||
.@"addrspace" = info.address_space,
|
||||
}, info.child, sentinel_val),
|
||||
else => {},
|
||||
},
|
||||
.optional => |info| switch (@typeInfo(info.child)) {
|
||||
.pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.many => return @Type(.{
|
||||
.optional = .{
|
||||
.child = @Type(.{
|
||||
.pointer = .{
|
||||
.size = ptr_info.size,
|
||||
.is_const = ptr_info.is_const,
|
||||
.is_volatile = ptr_info.is_volatile,
|
||||
.alignment = ptr_info.alignment,
|
||||
.address_space = ptr_info.address_space,
|
||||
.child = ptr_info.child,
|
||||
.is_allowzero = ptr_info.is_allowzero,
|
||||
.sentinel_ptr = @as(?*const anyopaque, @ptrCast(&sentinel_val)),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
.many => return ?@Pointer(.many, .{
|
||||
.@"const" = ptr_info.is_const,
|
||||
.@"volatile" = ptr_info.is_volatile,
|
||||
.@"allowzero" = ptr_info.is_allowzero,
|
||||
.@"align" = ptr_info.alignment,
|
||||
.@"addrspace" = ptr_info.address_space,
|
||||
.child = ptr_info.child,
|
||||
}, ptr_info.child, sentinel_val),
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
@@ -487,46 +463,22 @@ test tags {
|
||||
|
||||
/// Returns an enum with a variant named after each field of `T`.
|
||||
pub fn FieldEnum(comptime T: type) type {
|
||||
const field_infos = fields(T);
|
||||
const field_names = fieldNames(T);
|
||||
|
||||
if (field_infos.len == 0) {
|
||||
return @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u0,
|
||||
.fields = &.{},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (@typeInfo(T) == .@"union") {
|
||||
if (@typeInfo(T).@"union".tag_type) |tag_type| {
|
||||
for (std.enums.values(tag_type), 0..) |v, i| {
|
||||
switch (@typeInfo(T)) {
|
||||
.@"union" => |@"union"| if (@"union".tag_type) |EnumTag| {
|
||||
for (std.enums.values(EnumTag), 0..) |v, i| {
|
||||
if (@intFromEnum(v) != i) break; // enum values not consecutive
|
||||
if (!std.mem.eql(u8, @tagName(v), field_infos[i].name)) break; // fields out of order
|
||||
if (!std.mem.eql(u8, @tagName(v), field_names[i])) break; // fields out of order
|
||||
} else {
|
||||
return tag_type;
|
||||
return EnumTag;
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
var enumFields: [field_infos.len]std.builtin.Type.EnumField = undefined;
|
||||
var decls = [_]std.builtin.Type.Declaration{};
|
||||
inline for (field_infos, 0..) |field, i| {
|
||||
enumFields[i] = .{
|
||||
.name = field.name,
|
||||
.value = i,
|
||||
};
|
||||
}
|
||||
return @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = std.math.IntFittingRange(0, field_infos.len - 1),
|
||||
.fields = &enumFields,
|
||||
.decls = &decls,
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
const IntTag = std.math.IntFittingRange(0, field_names.len -| 1);
|
||||
return @Enum(IntTag, .exhaustive, field_names, &std.simd.iota(IntTag, field_names.len));
|
||||
}
|
||||
|
||||
fn expectEqualEnum(expected: anytype, actual: @TypeOf(expected)) !void {
|
||||
@@ -583,20 +535,11 @@ test FieldEnum {
|
||||
}
|
||||
|
||||
pub fn DeclEnum(comptime T: type) type {
|
||||
const fieldInfos = std.meta.declarations(T);
|
||||
var enumDecls: [fieldInfos.len]std.builtin.Type.EnumField = undefined;
|
||||
var decls = [_]std.builtin.Type.Declaration{};
|
||||
inline for (fieldInfos, 0..) |field, i| {
|
||||
enumDecls[i] = .{ .name = field.name, .value = i };
|
||||
}
|
||||
return @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = std.math.IntFittingRange(0, if (fieldInfos.len == 0) 0 else fieldInfos.len - 1),
|
||||
.fields = &enumDecls,
|
||||
.decls = &decls,
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
const decls = declarations(T);
|
||||
var names: [decls.len][]const u8 = undefined;
|
||||
for (&names, decls) |*name, decl| name.* = decl.name;
|
||||
const IntTag = std.math.IntFittingRange(0, decls.len -| 1);
|
||||
return @Enum(IntTag, .exhaustive, &names, &std.simd.iota(IntTag, decls.len));
|
||||
}
|
||||
|
||||
test DeclEnum {
|
||||
@@ -868,25 +811,26 @@ pub fn declList(comptime Namespace: type, comptime Decl: type) []const *const De
|
||||
}
|
||||
}
|
||||
|
||||
/// Deprecated: use @Int
|
||||
pub fn Int(comptime signedness: std.builtin.Signedness, comptime bit_count: u16) type {
|
||||
return @Type(.{
|
||||
.int = .{
|
||||
.signedness = signedness,
|
||||
.bits = bit_count,
|
||||
},
|
||||
});
|
||||
return @Int(signedness, bit_count);
|
||||
}
|
||||
|
||||
pub fn Float(comptime bit_count: u8) type {
|
||||
return @Type(.{
|
||||
.float = .{ .bits = bit_count },
|
||||
});
|
||||
return switch (bit_count) {
|
||||
16 => f16,
|
||||
32 => f32,
|
||||
64 => f64,
|
||||
80 => f80,
|
||||
128 => f128,
|
||||
else => @compileError("invalid float bit count"),
|
||||
};
|
||||
}
|
||||
|
||||
test Float {
|
||||
try testing.expectEqual(f16, Float(16));
|
||||
try testing.expectEqual(f32, Float(32));
|
||||
try testing.expectEqual(f64, Float(64));
|
||||
try testing.expectEqual(f80, Float(80));
|
||||
try testing.expectEqual(f128, Float(128));
|
||||
}
|
||||
|
||||
@@ -912,42 +856,14 @@ pub fn ArgsTuple(comptime Function: type) type {
|
||||
argument_field_list[i] = T;
|
||||
}
|
||||
|
||||
return CreateUniqueTuple(argument_field_list.len, argument_field_list);
|
||||
return Tuple(&argument_field_list);
|
||||
}
|
||||
|
||||
/// For a given anonymous list of types, returns a new tuple type
|
||||
/// with those types as fields.
|
||||
/// Deprecated; use `@Tuple` instead.
|
||||
///
|
||||
/// Examples:
|
||||
/// - `Tuple(&[_]type {})` ⇒ `tuple { }`
|
||||
/// - `Tuple(&[_]type {f32})` ⇒ `tuple { f32 }`
|
||||
/// - `Tuple(&[_]type {f32,u32})` ⇒ `tuple { f32, u32 }`
|
||||
/// To be removed after Zig 0.16.0 releases.
|
||||
pub fn Tuple(comptime types: []const type) type {
|
||||
return CreateUniqueTuple(types.len, types[0..types.len].*);
|
||||
}
|
||||
|
||||
fn CreateUniqueTuple(comptime N: comptime_int, comptime types: [N]type) type {
|
||||
var tuple_fields: [types.len]std.builtin.Type.StructField = undefined;
|
||||
inline for (types, 0..) |T, i| {
|
||||
@setEvalBranchQuota(10_000);
|
||||
var num_buf: [128]u8 = undefined;
|
||||
tuple_fields[i] = .{
|
||||
.name = std.fmt.bufPrintSentinel(&num_buf, "{d}", .{i}, 0) catch unreachable,
|
||||
.type = T,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(T),
|
||||
};
|
||||
}
|
||||
|
||||
return @Type(.{
|
||||
.@"struct" = .{
|
||||
.is_tuple = true,
|
||||
.layout = .auto,
|
||||
.decls = &.{},
|
||||
.fields = &tuple_fields,
|
||||
},
|
||||
});
|
||||
return @Tuple(types);
|
||||
}
|
||||
|
||||
const TupleTester = struct {
|
||||
|
||||
@@ -20,24 +20,16 @@ pub fn TrailerFlags(comptime Fields: type) type {
|
||||
|
||||
pub const ActiveFields = std.enums.EnumFieldStruct(FieldEnum, bool, false);
|
||||
pub const FieldValues = blk: {
|
||||
var fields: [bit_count]Type.StructField = undefined;
|
||||
for (@typeInfo(Fields).@"struct".fields, 0..) |struct_field, i| {
|
||||
fields[i] = Type.StructField{
|
||||
.name = struct_field.name,
|
||||
.type = ?struct_field.type,
|
||||
.default_value_ptr = &@as(?struct_field.type, null),
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(?struct_field.type),
|
||||
};
|
||||
var field_names: [bit_count][]const u8 = undefined;
|
||||
var field_types: [bit_count]type = undefined;
|
||||
var field_attrs: [bit_count]std.builtin.Type.StructField.Attributes = undefined;
|
||||
for (@typeInfo(Fields).@"struct".fields, &field_names, &field_types, &field_attrs) |field, *new_name, *NewType, *new_attrs| {
|
||||
new_name.* = field.name;
|
||||
NewType.* = ?field.type;
|
||||
const default: ?field.type = null;
|
||||
new_attrs.* = .{ .default_value_ptr = &default };
|
||||
}
|
||||
break :blk @Type(.{
|
||||
.@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
},
|
||||
});
|
||||
break :blk @Struct(.auto, null, &field_names, &field_types, &field_attrs);
|
||||
};
|
||||
|
||||
pub const Self = @This();
|
||||
|
||||
@@ -32,12 +32,17 @@ pub fn MultiArrayList(comptime T: type) type {
|
||||
const Elem = switch (@typeInfo(T)) {
|
||||
.@"struct" => T,
|
||||
.@"union" => |u| struct {
|
||||
pub const Bare = @Type(.{ .@"union" = .{
|
||||
.layout = u.layout,
|
||||
.tag_type = null,
|
||||
.fields = u.fields,
|
||||
.decls = &.{},
|
||||
} });
|
||||
pub const Bare = Bare: {
|
||||
var field_names: [u.fields.len][]const u8 = undefined;
|
||||
var field_types: [u.fields.len]type = undefined;
|
||||
var field_attrs: [u.fields.len]std.builtin.Type.UnionField.Attributes = undefined;
|
||||
for (u.fields, &field_names, &field_types, &field_attrs) |field, *name, *Type, *attrs| {
|
||||
name.* = field.name;
|
||||
Type.* = field.type;
|
||||
attrs.* = .{ .@"align" = field.alignment };
|
||||
}
|
||||
break :Bare @Union(u.layout, null, &field_names, &field_types, &field_attrs);
|
||||
};
|
||||
pub const Tag =
|
||||
u.tag_type orelse @compileError("MultiArrayList does not support untagged unions");
|
||||
tags: Tag,
|
||||
@@ -609,20 +614,18 @@ pub fn MultiArrayList(comptime T: type) type {
|
||||
}
|
||||
|
||||
const Entry = entry: {
|
||||
var entry_fields: [fields.len]std.builtin.Type.StructField = undefined;
|
||||
for (&entry_fields, sizes.fields) |*entry_field, i| entry_field.* = .{
|
||||
.name = fields[i].name ++ "_ptr",
|
||||
.type = *fields[i].type,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = fields[i].is_comptime,
|
||||
.alignment = fields[i].alignment,
|
||||
};
|
||||
break :entry @Type(.{ .@"struct" = .{
|
||||
.layout = .@"extern",
|
||||
.fields = &entry_fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
var field_names: [fields.len][]const u8 = undefined;
|
||||
var field_types: [fields.len]type = undefined;
|
||||
var field_attrs: [fields.len]std.builtin.Type.StructField.Attributes = undefined;
|
||||
for (sizes.fields, &field_names, &field_types, &field_attrs) |i, *name, *Type, *attrs| {
|
||||
name.* = fields[i].name ++ "_ptr";
|
||||
Type.* = *fields[i].type;
|
||||
attrs.* = .{
|
||||
.@"comptime" = fields[i].is_comptime,
|
||||
.@"align" = fields[i].alignment,
|
||||
};
|
||||
}
|
||||
break :entry @Struct(.@"extern", null, &field_names, &field_types, &field_attrs);
|
||||
};
|
||||
/// This function is used in the debugger pretty formatters in tools/ to fetch the
|
||||
/// child field order and entry type to facilitate fancy debug printing for this type.
|
||||
@@ -1023,23 +1026,9 @@ test "struct with many fields" {
|
||||
const ManyFields = struct {
|
||||
fn Type(count: comptime_int) type {
|
||||
@setEvalBranchQuota(50000);
|
||||
var fields: [count]std.builtin.Type.StructField = undefined;
|
||||
for (0..count) |i| {
|
||||
fields[i] = .{
|
||||
.name = std.fmt.comptimePrint("a{}", .{i}),
|
||||
.type = u32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(u32),
|
||||
};
|
||||
}
|
||||
const info: std.builtin.Type = .{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} };
|
||||
return @Type(info);
|
||||
var field_names: [count][]const u8 = undefined;
|
||||
for (&field_names, 0..) |*n, i| n.* = std.fmt.comptimePrint("a{d}", .{i});
|
||||
return @Struct(.@"extern", null, &field_names, &@splat(u32), &@splat(.{}));
|
||||
}
|
||||
|
||||
fn doTest(ally: std.mem.Allocator, count: comptime_int) !void {
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ pub const Options = struct {
|
||||
|
||||
logFn: fn (
|
||||
comptime message_level: log.Level,
|
||||
comptime scope: @TypeOf(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void = log.defaultLog,
|
||||
|
||||
+40
-24
@@ -773,7 +773,6 @@ pub const EnvVar = enum {
|
||||
pub const SimpleComptimeReason = enum(u32) {
|
||||
// Evaluating at comptime because a builtin operand must be comptime-known.
|
||||
// These messages all mention a specific builtin.
|
||||
operand_Type,
|
||||
operand_setEvalBranchQuota,
|
||||
operand_setFloatMode,
|
||||
operand_branchHint,
|
||||
@@ -809,25 +808,34 @@ pub const SimpleComptimeReason = enum(u32) {
|
||||
// Evaluating at comptime because types must be comptime-known.
|
||||
// Reasons other than `.type` are just more specific messages.
|
||||
type,
|
||||
int_signedness,
|
||||
int_bit_width,
|
||||
array_sentinel,
|
||||
array_length,
|
||||
pointer_size,
|
||||
pointer_attrs,
|
||||
pointer_sentinel,
|
||||
slice_sentinel,
|
||||
array_length,
|
||||
vector_length,
|
||||
error_set_contents,
|
||||
struct_fields,
|
||||
enum_fields,
|
||||
union_fields,
|
||||
function_ret_ty,
|
||||
function_parameters,
|
||||
fn_ret_ty,
|
||||
fn_param_types,
|
||||
fn_param_attrs,
|
||||
fn_attrs,
|
||||
struct_layout,
|
||||
struct_field_names,
|
||||
struct_field_types,
|
||||
struct_field_attrs,
|
||||
union_layout,
|
||||
union_field_names,
|
||||
union_field_types,
|
||||
union_field_attrs,
|
||||
tuple_field_types,
|
||||
enum_field_names,
|
||||
enum_field_values,
|
||||
|
||||
// Evaluating at comptime because decl/field name must be comptime-known.
|
||||
decl_name,
|
||||
field_name,
|
||||
struct_field_name,
|
||||
enum_field_name,
|
||||
union_field_name,
|
||||
tuple_field_name,
|
||||
tuple_field_index,
|
||||
|
||||
// Evaluating at comptime because it is an attribute of a global declaration.
|
||||
@@ -856,7 +864,6 @@ pub const SimpleComptimeReason = enum(u32) {
|
||||
pub fn message(r: SimpleComptimeReason) []const u8 {
|
||||
return switch (r) {
|
||||
// zig fmt: off
|
||||
.operand_Type => "operand to '@Type' must be comptime-known",
|
||||
.operand_setEvalBranchQuota => "operand to '@setEvalBranchQuota' must be comptime-known",
|
||||
.operand_setFloatMode => "operand to '@setFloatMode' must be comptime-known",
|
||||
.operand_branchHint => "operand to '@branchHint' must be comptime-known",
|
||||
@@ -888,24 +895,33 @@ pub const SimpleComptimeReason = enum(u32) {
|
||||
.clobber => "clobber must be comptime-known",
|
||||
|
||||
.type => "types must be comptime-known",
|
||||
.int_signedness => "integer signedness must be comptime-known",
|
||||
.int_bit_width => "integer bit width must be comptime-known",
|
||||
.array_sentinel => "array sentinel value must be comptime-known",
|
||||
.array_length => "array length must be comptime-known",
|
||||
.pointer_size => "pointer size must be comptime-known",
|
||||
.pointer_attrs => "pointer attributes must be comptime-known",
|
||||
.pointer_sentinel => "pointer sentinel value must be comptime-known",
|
||||
.slice_sentinel => "slice sentinel value must be comptime-known",
|
||||
.array_length => "array length must be comptime-known",
|
||||
.vector_length => "vector length must be comptime-known",
|
||||
.error_set_contents => "error set contents must be comptime-known",
|
||||
.struct_fields => "struct fields must be comptime-known",
|
||||
.enum_fields => "enum fields must be comptime-known",
|
||||
.union_fields => "union fields must be comptime-known",
|
||||
.function_ret_ty => "function return type must be comptime-known",
|
||||
.function_parameters => "function parameters must be comptime-known",
|
||||
.fn_ret_ty => "function return type must be comptime-known",
|
||||
.fn_param_types => "function parameter types must be comptime-known",
|
||||
.fn_param_attrs => "function parameter attributes must be comptime-known",
|
||||
.fn_attrs => "function attributes must be comptime-known",
|
||||
.struct_layout => "struct layout must be comptime-known",
|
||||
.struct_field_names => "struct field names must be comptime-known",
|
||||
.struct_field_types => "struct field types must be comptime-known",
|
||||
.struct_field_attrs => "struct field attributes must be comptime-known",
|
||||
.union_layout => "union layout must be comptime-known",
|
||||
.union_field_names => "union field names must be comptime-known",
|
||||
.union_field_types => "union field types must be comptime-known",
|
||||
.union_field_attrs => "union field attributes must be comptime-known",
|
||||
.tuple_field_types => "tuple field types must be comptime-known",
|
||||
.enum_field_names => "enum field names must be comptime-known",
|
||||
.enum_field_values => "enum field values must be comptime-known",
|
||||
|
||||
.decl_name => "declaration name must be comptime-known",
|
||||
.field_name => "field name must be comptime-known",
|
||||
.struct_field_name => "struct field name must be comptime-known",
|
||||
.enum_field_name => "enum field name must be comptime-known",
|
||||
.union_field_name => "union field name must be comptime-known",
|
||||
.tuple_field_name => "tuple field name must be comptime-known",
|
||||
.tuple_field_index => "tuple field index must be comptime-known",
|
||||
|
||||
.container_var_init => "initializer of container-level variable must be comptime-known",
|
||||
|
||||
+150
-46
@@ -833,7 +833,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
||||
=> {
|
||||
var buf: [2]Ast.Node.Index = undefined;
|
||||
const params = tree.builtinCallParams(&buf, node).?;
|
||||
return builtinCall(gz, scope, ri, node, params, false);
|
||||
return builtinCall(gz, scope, ri, node, params, false, .anon);
|
||||
},
|
||||
|
||||
.call_one,
|
||||
@@ -1194,14 +1194,20 @@ fn nameStratExpr(
|
||||
},
|
||||
.builtin_call_two,
|
||||
.builtin_call_two_comma,
|
||||
.builtin_call,
|
||||
.builtin_call_comma,
|
||||
=> {
|
||||
const builtin_token = tree.nodeMainToken(node);
|
||||
const builtin_name = tree.tokenSlice(builtin_token);
|
||||
if (!std.mem.eql(u8, builtin_name, "@Type")) return null;
|
||||
var buf: [2]Ast.Node.Index = undefined;
|
||||
const params = tree.builtinCallParams(&buf, node).?;
|
||||
if (params.len != 1) return null; // let `builtinCall` error
|
||||
return try builtinReify(gz, scope, ri, node, params[0], name_strat);
|
||||
const info = BuiltinFn.list.get(builtin_name) orelse return null;
|
||||
switch (info.tag) {
|
||||
.Enum, .Struct, .Union => {
|
||||
var buf: [2]Ast.Node.Index = undefined;
|
||||
const params = tree.builtinCallParams(&buf, node).?;
|
||||
return try builtinCall(gz, scope, ri, node, params, false, name_strat);
|
||||
},
|
||||
else => return null,
|
||||
}
|
||||
},
|
||||
else => return null,
|
||||
}
|
||||
@@ -1406,7 +1412,7 @@ fn fnProtoExprInner(
|
||||
.none;
|
||||
|
||||
const ret_ty_node = fn_proto.ast.return_type.unwrap().?;
|
||||
const ret_ty = try comptimeExpr(&block_scope, scope, coerced_type_ri, ret_ty_node, .function_ret_ty);
|
||||
const ret_ty = try comptimeExpr(&block_scope, scope, coerced_type_ri, ret_ty_node, .fn_ret_ty);
|
||||
|
||||
const result = try block_scope.addFunc(.{
|
||||
.src_node = fn_proto.ast.proto_node,
|
||||
@@ -2629,7 +2635,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
|
||||
const params = tree.builtinCallParams(&buf, inner_node).?;
|
||||
|
||||
try emitDbgNode(gz, inner_node);
|
||||
const result = try builtinCall(gz, scope, .{ .rl = .none }, inner_node, params, allow_branch_hint);
|
||||
const result = try builtinCall(gz, scope, .{ .rl = .none }, inner_node, params, allow_branch_hint, .anon);
|
||||
noreturn_src_node = try addEnsureResult(gz, result, inner_node);
|
||||
},
|
||||
|
||||
@@ -2707,6 +2713,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
||||
.elem_type,
|
||||
.indexable_ptr_elem_type,
|
||||
.splat_op_result_ty,
|
||||
.reify_int,
|
||||
.vector_type,
|
||||
.indexable_ptr_len,
|
||||
.anyframe_type,
|
||||
@@ -8942,7 +8949,7 @@ fn unionInit(
|
||||
params: []const Ast.Node.Index,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const union_type = try typeExpr(gz, scope, params[0]);
|
||||
const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .union_field_name);
|
||||
const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .union_field_names);
|
||||
const field_type = try gz.addPlNode(.field_type_ref, node, Zir.Inst.FieldTypeRef{
|
||||
.container_type = union_type,
|
||||
.field_name = field_name,
|
||||
@@ -9210,6 +9217,7 @@ fn builtinCall(
|
||||
node: Ast.Node.Index,
|
||||
params: []const Ast.Node.Index,
|
||||
allow_branch_hint: bool,
|
||||
reify_name_strat: Zir.Inst.NameStrategy,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
const tree = astgen.tree;
|
||||
@@ -9443,9 +9451,140 @@ fn builtinCall(
|
||||
return rvalue(gz, ri, try gz.addNodeExtended(.in_comptime, node), node);
|
||||
},
|
||||
|
||||
.Type => {
|
||||
return builtinReify(gz, scope, ri, node, params[0], .anon);
|
||||
.EnumLiteral => return rvalue(gz, ri, .enum_literal_type, node),
|
||||
.Int => {
|
||||
const signedness_ty = try gz.addBuiltinValue(node, .signedness);
|
||||
const result = try gz.addPlNode(.reify_int, node, Zir.Inst.Bin{
|
||||
.lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = signedness_ty } }, params[0], .int_signedness),
|
||||
.rhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, params[1], .int_bit_width),
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.Tuple => {
|
||||
const result = try gz.addExtendedPayload(.reify_tuple, Zir.Inst.UnNode{
|
||||
.node = gz.nodeIndexToRelative(node),
|
||||
.operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_type_type } }, params[0], .tuple_field_types),
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.Pointer => {
|
||||
const ptr_size_ty = try gz.addBuiltinValue(node, .pointer_size);
|
||||
const ptr_attrs_ty = try gz.addBuiltinValue(node, .pointer_attributes);
|
||||
const size = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = ptr_size_ty } }, params[0], .pointer_size);
|
||||
const attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = ptr_attrs_ty } }, params[1], .pointer_attrs);
|
||||
const elem_ty = try typeExpr(gz, scope, params[2]);
|
||||
const sentinel_ty = try gz.addExtendedPayload(.reify_pointer_sentinel_ty, Zir.Inst.UnNode{
|
||||
.node = gz.nodeIndexToRelative(params[2]),
|
||||
.operand = elem_ty,
|
||||
});
|
||||
const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = sentinel_ty } }, params[3], .pointer_sentinel);
|
||||
const result = try gz.addExtendedPayload(.reify_pointer, Zir.Inst.ReifyPointer{
|
||||
.node = gz.nodeIndexToRelative(node),
|
||||
.size = size,
|
||||
.attrs = attrs,
|
||||
.elem_ty = elem_ty,
|
||||
.sentinel = sentinel,
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.Fn => {
|
||||
const fn_attrs_ty = try gz.addBuiltinValue(node, .fn_attributes);
|
||||
const param_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_type_type } }, params[0], .fn_param_types);
|
||||
const param_attrs_ty = try gz.addExtendedPayloadSmall(
|
||||
.reify_slice_arg_ty,
|
||||
@intFromEnum(Zir.Inst.ReifySliceArgInfo.type_to_fn_param_attrs),
|
||||
Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[0]), .operand = param_types },
|
||||
);
|
||||
const param_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = param_attrs_ty } }, params[1], .fn_param_attrs);
|
||||
const ret_ty = try comptimeExpr(gz, scope, coerced_type_ri, params[2], .fn_ret_ty);
|
||||
const fn_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = fn_attrs_ty } }, params[3], .fn_attrs);
|
||||
const result = try gz.addExtendedPayload(.reify_fn, Zir.Inst.ReifyFn{
|
||||
.node = gz.nodeIndexToRelative(node),
|
||||
.param_types = param_types,
|
||||
.param_attrs = param_attrs,
|
||||
.ret_ty = ret_ty,
|
||||
.fn_attrs = fn_attrs,
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.Struct => {
|
||||
const container_layout_ty = try gz.addBuiltinValue(node, .container_layout);
|
||||
const layout = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = container_layout_ty } }, params[0], .struct_layout);
|
||||
const backing_ty = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .optional_type_type } }, params[1], .type);
|
||||
const field_names = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_slice_const_u8_type } }, params[2], .struct_field_names);
|
||||
const field_types_ty = try gz.addExtendedPayloadSmall(
|
||||
.reify_slice_arg_ty,
|
||||
@intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_struct_field_type),
|
||||
Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
|
||||
);
|
||||
const field_attrs_ty = try gz.addExtendedPayloadSmall(
|
||||
.reify_slice_arg_ty,
|
||||
@intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_struct_field_attrs),
|
||||
Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
|
||||
);
|
||||
const field_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_types_ty } }, params[3], .struct_field_types);
|
||||
const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .struct_field_attrs);
|
||||
const result = try gz.addExtendedPayloadSmall(.reify_struct, @intFromEnum(reify_name_strat), Zir.Inst.ReifyStruct{
|
||||
.src_line = gz.astgen.source_line,
|
||||
.node = node,
|
||||
.layout = layout,
|
||||
.backing_ty = backing_ty,
|
||||
.field_names = field_names,
|
||||
.field_types = field_types,
|
||||
.field_attrs = field_attrs,
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.Union => {
|
||||
const container_layout_ty = try gz.addBuiltinValue(node, .container_layout);
|
||||
const layout = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = container_layout_ty } }, params[0], .union_layout);
|
||||
const arg_ty = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .optional_type_type } }, params[1], .type);
|
||||
const field_names = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_slice_const_u8_type } }, params[2], .union_field_names);
|
||||
const field_types_ty = try gz.addExtendedPayloadSmall(
|
||||
.reify_slice_arg_ty,
|
||||
@intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_union_field_type),
|
||||
Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
|
||||
);
|
||||
const field_attrs_ty = try gz.addExtendedPayloadSmall(
|
||||
.reify_slice_arg_ty,
|
||||
@intFromEnum(Zir.Inst.ReifySliceArgInfo.string_to_union_field_attrs),
|
||||
Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(params[2]), .operand = field_names },
|
||||
);
|
||||
const field_types = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_types_ty } }, params[3], .union_field_types);
|
||||
const field_attrs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_attrs_ty } }, params[4], .union_field_attrs);
|
||||
const result = try gz.addExtendedPayloadSmall(.reify_union, @intFromEnum(reify_name_strat), Zir.Inst.ReifyUnion{
|
||||
.src_line = gz.astgen.source_line,
|
||||
.node = node,
|
||||
.layout = layout,
|
||||
.arg_ty = arg_ty,
|
||||
.field_names = field_names,
|
||||
.field_types = field_types,
|
||||
.field_attrs = field_attrs,
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.Enum => {
|
||||
const enum_mode_ty = try gz.addBuiltinValue(node, .enum_mode);
|
||||
const tag_ty = try typeExpr(gz, scope, params[0]);
|
||||
const mode = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = enum_mode_ty } }, params[1], .type);
|
||||
const field_names = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_slice_const_u8_type } }, params[2], .enum_field_names);
|
||||
const field_values_ty = try gz.addExtendedPayload(.reify_enum_value_slice_ty, Zir.Inst.BinNode{
|
||||
.node = gz.nodeIndexToRelative(node),
|
||||
.lhs = tag_ty,
|
||||
.rhs = field_names,
|
||||
});
|
||||
const field_values = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = field_values_ty } }, params[3], .enum_field_values);
|
||||
const result = try gz.addExtendedPayloadSmall(.reify_enum, @intFromEnum(reify_name_strat), Zir.Inst.ReifyEnum{
|
||||
.src_line = gz.astgen.source_line,
|
||||
.node = node,
|
||||
.tag_ty = tag_ty,
|
||||
.mode = mode,
|
||||
.field_names = field_names,
|
||||
.field_values = field_values,
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
|
||||
.panic => {
|
||||
try emitDbgNode(gz, node);
|
||||
return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .panic);
|
||||
@@ -9764,41 +9903,6 @@ fn builtinCall(
|
||||
},
|
||||
}
|
||||
}
|
||||
fn builtinReify(
|
||||
gz: *GenZir,
|
||||
scope: *Scope,
|
||||
ri: ResultInfo,
|
||||
node: Ast.Node.Index,
|
||||
arg_node: Ast.Node.Index,
|
||||
name_strat: Zir.Inst.NameStrategy,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
|
||||
const type_info_ty = try gz.addBuiltinValue(node, .type_info);
|
||||
const operand = try expr(gz, scope, .{ .rl = .{ .coerced_ty = type_info_ty } }, arg_node);
|
||||
|
||||
try gz.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
try astgen.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const payload_index = try astgen.addExtra(Zir.Inst.Reify{
|
||||
.node = node, // Absolute node index -- see the definition of `Reify`.
|
||||
.operand = operand,
|
||||
.src_line = astgen.source_line,
|
||||
});
|
||||
const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
|
||||
astgen.instructions.appendAssumeCapacity(.{
|
||||
.tag = .extended,
|
||||
.data = .{ .extended = .{
|
||||
.opcode = .reify,
|
||||
.small = @intFromEnum(name_strat),
|
||||
.operand = payload_index,
|
||||
} },
|
||||
});
|
||||
gz.instructions.appendAssumeCapacity(new_index);
|
||||
const result = new_index.toRef();
|
||||
return rvalue(gz, ri, result, node);
|
||||
}
|
||||
|
||||
fn hasDeclOrField(
|
||||
gz: *GenZir,
|
||||
|
||||
@@ -866,6 +866,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
|
||||
// These builtins take no args and do not consume the result pointer.
|
||||
.src,
|
||||
.This,
|
||||
.EnumLiteral,
|
||||
.return_address,
|
||||
.error_return_trace,
|
||||
.frame,
|
||||
@@ -906,7 +907,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
|
||||
.embed_file,
|
||||
.error_name,
|
||||
.set_runtime_safety,
|
||||
.Type,
|
||||
.Tuple,
|
||||
.c_undef,
|
||||
.c_include,
|
||||
.wasm_memory_size,
|
||||
@@ -1058,6 +1059,48 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
|
||||
_ = try astrl.expr(args[3], block, ResultInfo.none);
|
||||
return false;
|
||||
},
|
||||
.Int => {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
|
||||
return false;
|
||||
},
|
||||
.Pointer => {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[2], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[3], block, ResultInfo.type_only);
|
||||
return false;
|
||||
},
|
||||
.Fn => {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[2], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[3], block, ResultInfo.type_only);
|
||||
return false;
|
||||
},
|
||||
.Struct => {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[2], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[3], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[4], block, ResultInfo.type_only);
|
||||
return false;
|
||||
},
|
||||
.Union => {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[2], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[3], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[4], block, ResultInfo.type_only);
|
||||
return false;
|
||||
},
|
||||
.Enum => {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[2], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[3], block, ResultInfo.type_only);
|
||||
return false;
|
||||
},
|
||||
.Vector => {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
_ = try astrl.expr(args[1], block, ResultInfo.type_only);
|
||||
|
||||
@@ -110,7 +110,14 @@ pub const Tag = enum {
|
||||
This,
|
||||
trap,
|
||||
truncate,
|
||||
Type,
|
||||
EnumLiteral,
|
||||
Int,
|
||||
Tuple,
|
||||
Pointer,
|
||||
Fn,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
type_info,
|
||||
type_name,
|
||||
TypeOf,
|
||||
@@ -937,12 +944,61 @@ pub const list = list: {
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Type",
|
||||
"@EnumLiteral",
|
||||
.{
|
||||
.tag = .Type,
|
||||
.tag = .EnumLiteral,
|
||||
.param_count = 0,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Int",
|
||||
.{
|
||||
.tag = .Int,
|
||||
.param_count = 2,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Tuple",
|
||||
.{
|
||||
.tag = .Tuple,
|
||||
.param_count = 1,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Pointer",
|
||||
.{
|
||||
.tag = .Pointer,
|
||||
.param_count = 4,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Fn",
|
||||
.{
|
||||
.tag = .Fn,
|
||||
.param_count = 4,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Struct",
|
||||
.{
|
||||
.tag = .Struct,
|
||||
.param_count = 5,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Union",
|
||||
.{
|
||||
.tag = .Union,
|
||||
.param_count = 5,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Enum",
|
||||
.{
|
||||
.tag = .Enum,
|
||||
.param_count = 4,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@typeInfo",
|
||||
.{
|
||||
|
||||
+131
-8
@@ -260,6 +260,10 @@ pub const Inst = struct {
|
||||
/// `[N:S]T` syntax. Source location is the array type expression node.
|
||||
/// Uses the `pl_node` union field. Payload is `ArrayTypeSentinel`.
|
||||
array_type_sentinel,
|
||||
/// `@Int` builtin.
|
||||
/// Uses the `pl_node` union field with `Bin` payload.
|
||||
/// lhs is signedness, rhs is bit count.
|
||||
reify_int,
|
||||
/// `@Vector` builtin.
|
||||
/// Uses the `pl_node` union field with `Bin` payload.
|
||||
/// lhs is length, rhs is element type.
|
||||
@@ -1112,6 +1116,7 @@ pub const Inst = struct {
|
||||
.array_mul,
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.reify_int,
|
||||
.vector_type,
|
||||
.elem_type,
|
||||
.indexable_ptr_elem_type,
|
||||
@@ -1409,6 +1414,7 @@ pub const Inst = struct {
|
||||
.array_mul,
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.reify_int,
|
||||
.vector_type,
|
||||
.elem_type,
|
||||
.indexable_ptr_elem_type,
|
||||
@@ -1644,6 +1650,7 @@ pub const Inst = struct {
|
||||
.array_mul = .pl_node,
|
||||
.array_type = .pl_node,
|
||||
.array_type_sentinel = .pl_node,
|
||||
.reify_int = .pl_node,
|
||||
.vector_type = .pl_node,
|
||||
.elem_type = .un_node,
|
||||
.indexable_ptr_elem_type = .un_node,
|
||||
@@ -2035,10 +2042,43 @@ pub const Inst = struct {
|
||||
/// Implement builtin `@errorFromInt`.
|
||||
/// `operand` is payload index to `UnNode`.
|
||||
error_from_int,
|
||||
/// Implement builtin `@Type`.
|
||||
/// `operand` is payload index to `Reify`.
|
||||
/// Given a comptime-known operand of type `[]const A`, returns the type `*const [operand.len]B`.
|
||||
/// The types `A` and `B` are determined from `ReifySliceArgInfo`.
|
||||
/// This instruction is used to provide result types to arguments of `@Fn`, `@Struct`, etc.
|
||||
/// `operand` is payload index to `UnNode`.
|
||||
/// `small` is a bitcast `ReifySliceArgInfo`.
|
||||
reify_slice_arg_ty,
|
||||
/// Like `reify_slice_arg_ty` for the specific case of `[]const []const u8` to `[]const TagInt`,
|
||||
/// as needed for `@Enum`.
|
||||
/// `operand` is payload index to `BinNode`. lhs is the type `TagInt`. rhs is the `[]const []const u8` value.
|
||||
/// `small` is unused.
|
||||
reify_enum_value_slice_ty,
|
||||
/// Given a comptime-known operand of type `type`, returns the type `?operand` if possible, otherwise `?noreturn`.
|
||||
/// Used for the final arg of `@Pointer` to allow reifying pointers to opaque types.
|
||||
/// `operand` is payload index to `UnNode`.
|
||||
/// `small` is unused.
|
||||
reify_pointer_sentinel_ty,
|
||||
/// Implements builtin `@Tuple`.
|
||||
/// `operand` is payload index to `UnNode`.
|
||||
reify_tuple,
|
||||
/// Implements builtin `@Pointer`.
|
||||
/// `operand` is payload index to `ReifyPointer`.
|
||||
reify_pointer,
|
||||
/// Implements builtin `@Fn`.
|
||||
/// `operand` is payload index to `ReifyFn`.
|
||||
reify_fn,
|
||||
/// Implements builtin `@Struct`.
|
||||
/// `operand` is payload index to `ReifyStruct`.
|
||||
/// `small` contains `NameStrategy`.
|
||||
reify,
|
||||
reify_struct,
|
||||
/// Implements builtin `@Union`.
|
||||
/// `operand` is payload index to `ReifyUnion`.
|
||||
/// `small` contains `NameStrategy`.
|
||||
reify_union,
|
||||
/// Implements builtin `@Enum`.
|
||||
/// `operand` is payload index to `ReifyEnum`.
|
||||
/// `small` contains `NameStrategy`.
|
||||
reify_enum,
|
||||
/// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins.
|
||||
/// `small` 0=>weak 1=>strong
|
||||
/// `operand` is payload index to `Cmpxchg`.
|
||||
@@ -2226,6 +2266,11 @@ pub const Inst = struct {
|
||||
manyptr_const_u8_sentinel_0_type,
|
||||
slice_const_u8_type,
|
||||
slice_const_u8_sentinel_0_type,
|
||||
manyptr_const_slice_const_u8_type,
|
||||
slice_const_slice_const_u8_type,
|
||||
optional_type_type,
|
||||
manyptr_const_type_type,
|
||||
slice_const_type_type,
|
||||
vector_8_i8_type,
|
||||
vector_16_i8_type,
|
||||
vector_32_i8_type,
|
||||
@@ -3169,6 +3214,23 @@ pub const Inst = struct {
|
||||
rhs: Ref,
|
||||
};
|
||||
|
||||
pub const ReifySliceArgInfo = enum(u16) {
|
||||
/// Input element type is `type`.
|
||||
/// Output element type is `std.builtin.Type.Fn.Param.Attributes`.
|
||||
type_to_fn_param_attrs,
|
||||
/// Input element type is `[]const u8`.
|
||||
/// Output element type is `type`.
|
||||
string_to_struct_field_type,
|
||||
/// Identical to `string_to_struct_field_type` aside from emitting slightly different error messages.
|
||||
string_to_union_field_type,
|
||||
/// Input element type is `[]const u8`.
|
||||
/// Output element type is `std.builtin.Type.StructField.Attributes`.
|
||||
string_to_struct_field_attrs,
|
||||
/// Input element type is `[]const u8`.
|
||||
/// Output element type is `std.builtin.Type.UnionField.Attributes`.
|
||||
string_to_union_field_attrs,
|
||||
};
|
||||
|
||||
pub const UnNode = struct {
|
||||
node: Ast.Node.Offset,
|
||||
operand: Ref,
|
||||
@@ -3179,12 +3241,55 @@ pub const Inst = struct {
|
||||
index: u32,
|
||||
};
|
||||
|
||||
pub const Reify = struct {
|
||||
pub const ReifyPointer = struct {
|
||||
node: Ast.Node.Offset,
|
||||
size: Ref,
|
||||
attrs: Ref,
|
||||
elem_ty: Ref,
|
||||
sentinel: Ref,
|
||||
};
|
||||
|
||||
pub const ReifyFn = struct {
|
||||
node: Ast.Node.Offset,
|
||||
param_types: Ref,
|
||||
param_attrs: Ref,
|
||||
ret_ty: Ref,
|
||||
fn_attrs: Ref,
|
||||
};
|
||||
|
||||
pub const ReifyStruct = struct {
|
||||
src_line: u32,
|
||||
/// This node is absolute, because `reify` instructions are tracked across updates, and
|
||||
/// this simplifies the logic for getting source locations for types.
|
||||
node: Ast.Node.Index,
|
||||
operand: Ref,
|
||||
layout: Ref,
|
||||
backing_ty: Ref,
|
||||
field_names: Ref,
|
||||
field_types: Ref,
|
||||
field_attrs: Ref,
|
||||
};
|
||||
|
||||
pub const ReifyUnion = struct {
|
||||
src_line: u32,
|
||||
/// This node is absolute, because `reify` instructions are tracked across updates, and
|
||||
/// this simplifies the logic for getting source locations for types.
|
||||
node: Ast.Node.Index,
|
||||
layout: Ref,
|
||||
arg_ty: Ref,
|
||||
field_names: Ref,
|
||||
field_types: Ref,
|
||||
field_attrs: Ref,
|
||||
};
|
||||
|
||||
pub const ReifyEnum = struct {
|
||||
src_line: u32,
|
||||
/// This node is absolute, because `reify` instructions are tracked across updates, and
|
||||
/// this simplifies the logic for getting source locations for types.
|
||||
node: Ast.Node.Index,
|
||||
tag_ty: Ref,
|
||||
mode: Ref,
|
||||
field_names: Ref,
|
||||
field_values: Ref,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
@@ -3496,14 +3601,19 @@ pub const Inst = struct {
|
||||
calling_convention,
|
||||
address_space,
|
||||
float_mode,
|
||||
signedness,
|
||||
reduce_op,
|
||||
call_modifier,
|
||||
prefetch_options,
|
||||
export_options,
|
||||
extern_options,
|
||||
type_info,
|
||||
branch_hint,
|
||||
clobbers,
|
||||
pointer_size,
|
||||
pointer_attributes,
|
||||
fn_attributes,
|
||||
container_layout,
|
||||
enum_mode,
|
||||
// Values
|
||||
calling_convention_c,
|
||||
calling_convention_inline,
|
||||
@@ -4190,6 +4300,7 @@ fn findTrackableInner(
|
||||
.array_mul,
|
||||
.array_type,
|
||||
.array_type_sentinel,
|
||||
.reify_int,
|
||||
.vector_type,
|
||||
.elem_type,
|
||||
.indexable_ptr_elem_type,
|
||||
@@ -4432,6 +4543,12 @@ fn findTrackableInner(
|
||||
.select,
|
||||
.int_from_error,
|
||||
.error_from_int,
|
||||
.reify_slice_arg_ty,
|
||||
.reify_enum_value_slice_ty,
|
||||
.reify_pointer_sentinel_ty,
|
||||
.reify_tuple,
|
||||
.reify_pointer,
|
||||
.reify_fn,
|
||||
.cmpxchg,
|
||||
.c_va_arg,
|
||||
.c_va_copy,
|
||||
@@ -4463,7 +4580,11 @@ fn findTrackableInner(
|
||||
},
|
||||
|
||||
// Reifications and opaque declarations need tracking, but have no body.
|
||||
.reify, .opaque_decl => return contents.other.append(gpa, inst),
|
||||
.reify_enum,
|
||||
.reify_struct,
|
||||
.reify_union,
|
||||
.opaque_decl,
|
||||
=> return contents.other.append(gpa, inst),
|
||||
|
||||
// Struct declarations need tracking and have bodies.
|
||||
.struct_decl => {
|
||||
@@ -5246,7 +5367,9 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
|
||||
.union_decl,
|
||||
.enum_decl,
|
||||
.opaque_decl,
|
||||
.reify,
|
||||
.reify_enum,
|
||||
.reify_struct,
|
||||
.reify_union,
|
||||
=> {}, // tracked in order, as the owner instructions of explicit container types
|
||||
else => unreachable, // assertion failure; not trackable
|
||||
},
|
||||
|
||||
@@ -81,23 +81,15 @@ fn ToUnsigned(comptime T: type) type {
|
||||
}
|
||||
|
||||
/// Constructs a [*c] pointer with the const and volatile annotations
|
||||
/// from SelfType for pointing to a C flexible array of ElementType.
|
||||
pub fn FlexibleArrayType(comptime SelfType: type, comptime ElementType: type) type {
|
||||
switch (@typeInfo(SelfType)) {
|
||||
.pointer => |ptr| {
|
||||
return @Type(.{ .pointer = .{
|
||||
.size = .c,
|
||||
.is_const = ptr.is_const,
|
||||
.is_volatile = ptr.is_volatile,
|
||||
.alignment = @alignOf(ElementType),
|
||||
.address_space = .generic,
|
||||
.child = ElementType,
|
||||
.is_allowzero = true,
|
||||
.sentinel_ptr = null,
|
||||
} });
|
||||
},
|
||||
else => |info| @compileError("Invalid self type \"" ++ @tagName(info) ++ "\" for flexible array getter: " ++ @typeName(SelfType)),
|
||||
}
|
||||
/// from Self for pointing to a C flexible array of Element.
|
||||
pub fn FlexibleArrayType(comptime Self: type, comptime Element: type) type {
|
||||
return switch (@typeInfo(Self)) {
|
||||
.pointer => |ptr| @Pointer(.c, .{
|
||||
.@"const" = ptr.is_const,
|
||||
.@"volatile" = ptr.is_volatile,
|
||||
}, Element, null),
|
||||
else => |info| @compileError("Invalid self type \"" ++ @tagName(info) ++ "\" for flexible array getter: " ++ @typeName(Self)),
|
||||
};
|
||||
}
|
||||
|
||||
/// Promote the type of an integer literal until it fits as C would.
|
||||
@@ -219,7 +211,7 @@ fn castInt(comptime DestType: type, target: anytype) DestType {
|
||||
const dest = @typeInfo(DestType).int;
|
||||
const source = @typeInfo(@TypeOf(target)).int;
|
||||
|
||||
const Int = @Type(.{ .int = .{ .bits = dest.bits, .signedness = source.signedness } });
|
||||
const Int = @Int(source.signedness, dest.bits);
|
||||
|
||||
if (dest.bits < source.bits)
|
||||
return @as(DestType, @bitCast(@as(Int, @truncate(target))))
|
||||
|
||||
@@ -8614,39 +8614,18 @@ pub const Metadata = packed struct(u32) {
|
||||
nodes: anytype,
|
||||
w: *Writer,
|
||||
) !void {
|
||||
comptime var fmt_str: []const u8 = "";
|
||||
const names = comptime std.meta.fieldNames(@TypeOf(nodes));
|
||||
comptime var fields: [2 + names.len]std.builtin.Type.StructField = undefined;
|
||||
inline for (fields[0..2], .{ "distinct", "node" }) |*field, name| {
|
||||
fmt_str = fmt_str ++ "{[" ++ name ++ "]s}";
|
||||
field.* = .{
|
||||
.name = name,
|
||||
.type = []const u8,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf([]const u8),
|
||||
};
|
||||
}
|
||||
fmt_str = fmt_str ++ "(";
|
||||
inline for (fields[2..], names) |*field, name| {
|
||||
fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
|
||||
const T = std.fmt.Alt(FormatData, format);
|
||||
field.* = .{
|
||||
.name = name,
|
||||
.type = T,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(T),
|
||||
};
|
||||
}
|
||||
|
||||
comptime var fmt_str: []const u8 = "{[distinct]s}{[node]s}(";
|
||||
inline for (names) |name| fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
|
||||
fmt_str = fmt_str ++ ")\n";
|
||||
|
||||
var fmt_args: @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} }) = undefined;
|
||||
const field_names = @as([]const []const u8, &.{ "distinct", "node" }) ++ names;
|
||||
comptime var field_types: [2 + names.len]type = undefined;
|
||||
@memset(field_types[0..2], []const u8);
|
||||
@memset(field_types[2..], std.fmt.Alt(FormatData, format));
|
||||
|
||||
var fmt_args: @Struct(.auto, null, field_names, &field_types, &@splat(.{})) = undefined;
|
||||
fmt_args.distinct = @tagName(distinct);
|
||||
fmt_args.node = @tagName(node);
|
||||
inline for (names) |name| @field(fmt_args, name) = try formatter.fmt(
|
||||
|
||||
@@ -1062,6 +1062,11 @@ pub const Inst = struct {
|
||||
manyptr_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.manyptr_const_u8_sentinel_0_type),
|
||||
slice_const_u8_type = @intFromEnum(InternPool.Index.slice_const_u8_type),
|
||||
slice_const_u8_sentinel_0_type = @intFromEnum(InternPool.Index.slice_const_u8_sentinel_0_type),
|
||||
manyptr_const_slice_const_u8_type = @intFromEnum(InternPool.Index.manyptr_const_slice_const_u8_type),
|
||||
slice_const_slice_const_u8_type = @intFromEnum(InternPool.Index.slice_const_slice_const_u8_type),
|
||||
optional_type_type = @intFromEnum(InternPool.Index.optional_type_type),
|
||||
manyptr_const_type_type = @intFromEnum(InternPool.Index.manyptr_const_type_type),
|
||||
slice_const_type_type = @intFromEnum(InternPool.Index.slice_const_type_type),
|
||||
vector_8_i8_type = @intFromEnum(InternPool.Index.vector_8_i8_type),
|
||||
vector_16_i8_type = @intFromEnum(InternPool.Index.vector_16_i8_type),
|
||||
vector_32_i8_type = @intFromEnum(InternPool.Index.vector_32_i8_type),
|
||||
|
||||
+90
-79
@@ -1153,23 +1153,17 @@ const Local = struct {
|
||||
fn PtrArrayElem(comptime len: usize) type {
|
||||
const elem_info = @typeInfo(Elem).@"struct";
|
||||
const elem_fields = elem_info.fields;
|
||||
var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;
|
||||
for (&new_fields, elem_fields) |*new_field, elem_field| {
|
||||
const T = *[len]elem_field.type;
|
||||
new_field.* = .{
|
||||
.name = elem_field.name,
|
||||
.type = T,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(T),
|
||||
};
|
||||
var new_names: [elem_fields.len][]const u8 = undefined;
|
||||
var new_types: [elem_fields.len]type = undefined;
|
||||
for (elem_fields, &new_names, &new_types) |elem_field, *new_name, *NewType| {
|
||||
new_name.* = elem_field.name;
|
||||
NewType.* = *[len]elem_field.type;
|
||||
}
|
||||
if (elem_info.is_tuple) {
|
||||
return @Tuple(&new_types);
|
||||
} else {
|
||||
return @Struct(.auto, null, &new_names, &new_types, &@splat(.{}));
|
||||
}
|
||||
return @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &new_fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = elem_info.is_tuple,
|
||||
} });
|
||||
}
|
||||
fn PtrElem(comptime opts: struct {
|
||||
size: std.builtin.Type.Pointer.Size,
|
||||
@@ -1177,32 +1171,17 @@ const Local = struct {
|
||||
}) type {
|
||||
const elem_info = @typeInfo(Elem).@"struct";
|
||||
const elem_fields = elem_info.fields;
|
||||
var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;
|
||||
for (&new_fields, elem_fields) |*new_field, elem_field| {
|
||||
const T = @Type(.{ .pointer = .{
|
||||
.size = opts.size,
|
||||
.is_const = opts.is_const,
|
||||
.is_volatile = false,
|
||||
.alignment = @alignOf(elem_field.type),
|
||||
.address_space = .generic,
|
||||
.child = elem_field.type,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = null,
|
||||
} });
|
||||
new_field.* = .{
|
||||
.name = elem_field.name,
|
||||
.type = T,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(T),
|
||||
};
|
||||
var new_names: [elem_fields.len][]const u8 = undefined;
|
||||
var new_types: [elem_fields.len]type = undefined;
|
||||
for (elem_fields, &new_names, &new_types) |elem_field, *new_name, *NewType| {
|
||||
new_name.* = elem_field.name;
|
||||
NewType.* = @Pointer(opts.size, .{ .@"const" = opts.is_const }, elem_field.type, null);
|
||||
}
|
||||
if (elem_info.is_tuple) {
|
||||
return @Tuple(&new_types);
|
||||
} else {
|
||||
return @Struct(.auto, null, &new_names, &new_types, &@splat(.{}));
|
||||
}
|
||||
return @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &new_fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = elem_info.is_tuple,
|
||||
} });
|
||||
}
|
||||
|
||||
pub fn addOne(mutable: Mutable) Allocator.Error!PtrElem(.{ .size = .one }) {
|
||||
@@ -2017,8 +1996,7 @@ pub const Key = union(enum) {
|
||||
error_union_type: ErrorUnionType,
|
||||
simple_type: SimpleType,
|
||||
/// This represents a struct that has been explicitly declared in source code,
|
||||
/// or was created with `@Type`. It is unique and based on a declaration.
|
||||
/// It may be a tuple, if declared like this: `struct {A, B, C}`.
|
||||
/// or was created with `@Struct`. It is unique and based on a declaration.
|
||||
struct_type: NamespaceType,
|
||||
/// This is a tuple type. Tuples are logically similar to structs, but have some
|
||||
/// important differences in semantics; they do not undergo staged type resolution,
|
||||
@@ -2175,7 +2153,7 @@ pub const Key = union(enum) {
|
||||
/// The union for which this is a tag type.
|
||||
union_type: Index,
|
||||
},
|
||||
/// This type originates from a reification via `@Type`, or from an anonymous initialization.
|
||||
/// This type originates from a reification via `@Enum`, `@Struct`, `@Union` or from an anonymous initialization.
|
||||
/// It is hashed based on its ZIR instruction index and fields, attributes, etc.
|
||||
/// To avoid making this key overly complex, the type-specific data is hashed by Sema.
|
||||
reified: struct {
|
||||
@@ -4641,6 +4619,13 @@ pub const Index = enum(u32) {
|
||||
slice_const_u8_type,
|
||||
slice_const_u8_sentinel_0_type,
|
||||
|
||||
manyptr_const_slice_const_u8_type,
|
||||
slice_const_slice_const_u8_type,
|
||||
|
||||
optional_type_type,
|
||||
manyptr_const_type_type,
|
||||
slice_const_type_type,
|
||||
|
||||
vector_8_i8_type,
|
||||
vector_16_i8_type,
|
||||
vector_32_i8_type,
|
||||
@@ -5201,6 +5186,45 @@ pub const static_keys: [static_len]Key = .{
|
||||
},
|
||||
} },
|
||||
|
||||
// [*]const []const u8
|
||||
.{ .ptr_type = .{
|
||||
.child = .slice_const_u8_type,
|
||||
.flags = .{
|
||||
.size = .many,
|
||||
.is_const = true,
|
||||
},
|
||||
} },
|
||||
|
||||
// []const []const u8
|
||||
.{ .ptr_type = .{
|
||||
.child = .slice_const_u8_type,
|
||||
.flags = .{
|
||||
.size = .slice,
|
||||
.is_const = true,
|
||||
},
|
||||
} },
|
||||
|
||||
// ?type
|
||||
.{ .opt_type = .type_type },
|
||||
|
||||
// [*]const type
|
||||
.{ .ptr_type = .{
|
||||
.child = .type_type,
|
||||
.flags = .{
|
||||
.size = .many,
|
||||
.is_const = true,
|
||||
},
|
||||
} },
|
||||
|
||||
// []const type
|
||||
.{ .ptr_type = .{
|
||||
.child = .type_type,
|
||||
.flags = .{
|
||||
.size = .slice,
|
||||
.is_const = true,
|
||||
},
|
||||
} },
|
||||
|
||||
// @Vector(8, i8)
|
||||
.{ .vector_type = .{ .len = 8, .child = .i8_type } },
|
||||
// @Vector(16, i8)
|
||||
@@ -10225,16 +10249,8 @@ pub fn getGeneratedTagEnumType(
|
||||
}
|
||||
|
||||
pub const OpaqueTypeInit = struct {
|
||||
key: union(enum) {
|
||||
declared: struct {
|
||||
zir_index: TrackedInst.Index,
|
||||
captures: []const CaptureValue,
|
||||
},
|
||||
reified: struct {
|
||||
zir_index: TrackedInst.Index,
|
||||
// No type hash since reifid opaques have no data other than the `@Type` location
|
||||
},
|
||||
},
|
||||
zir_index: TrackedInst.Index,
|
||||
captures: []const CaptureValue,
|
||||
};
|
||||
|
||||
pub fn getOpaqueType(
|
||||
@@ -10243,16 +10259,10 @@ pub fn getOpaqueType(
|
||||
tid: Zcu.PerThread.Id,
|
||||
ini: OpaqueTypeInit,
|
||||
) Allocator.Error!WipNamespaceType.Result {
|
||||
var gop = try ip.getOrPutKey(gpa, tid, .{ .opaque_type = switch (ini.key) {
|
||||
.declared => |d| .{ .declared = .{
|
||||
.zir_index = d.zir_index,
|
||||
.captures = .{ .external = d.captures },
|
||||
} },
|
||||
.reified => |r| .{ .reified = .{
|
||||
.zir_index = r.zir_index,
|
||||
.type_hash = 0,
|
||||
} },
|
||||
} });
|
||||
var gop = try ip.getOrPutKey(gpa, tid, .{ .opaque_type = .{ .declared = .{
|
||||
.zir_index = ini.zir_index,
|
||||
.captures = .{ .external = ini.captures },
|
||||
} } });
|
||||
defer gop.deinit();
|
||||
if (gop == .existing) return .{ .existing = gop.existing };
|
||||
|
||||
@@ -10261,30 +10271,19 @@ pub fn getOpaqueType(
|
||||
const extra = local.getMutableExtra(gpa);
|
||||
try items.ensureUnusedCapacity(1);
|
||||
|
||||
try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + switch (ini.key) {
|
||||
.declared => |d| d.captures.len,
|
||||
.reified => 0,
|
||||
});
|
||||
try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len);
|
||||
const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{
|
||||
.name = undefined, // set by `finish`
|
||||
.name_nav = undefined, // set by `finish`
|
||||
.namespace = undefined, // set by `finish`
|
||||
.zir_index = switch (ini.key) {
|
||||
inline else => |x| x.zir_index,
|
||||
},
|
||||
.captures_len = switch (ini.key) {
|
||||
.declared => |d| @intCast(d.captures.len),
|
||||
.reified => std.math.maxInt(u32),
|
||||
},
|
||||
.zir_index = ini.zir_index,
|
||||
.captures_len = @intCast(ini.captures.len),
|
||||
});
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .type_opaque,
|
||||
.data = extra_index,
|
||||
});
|
||||
switch (ini.key) {
|
||||
.declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
|
||||
.reified => {},
|
||||
}
|
||||
extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)});
|
||||
return .{
|
||||
.wip = .{
|
||||
.tid = tid,
|
||||
@@ -10555,6 +10554,8 @@ pub fn slicePtrType(ip: *const InternPool, index: Index) Index {
|
||||
switch (index) {
|
||||
.slice_const_u8_type => return .manyptr_const_u8_type,
|
||||
.slice_const_u8_sentinel_0_type => return .manyptr_const_u8_sentinel_0_type,
|
||||
.slice_const_slice_const_u8_type => return .manyptr_const_slice_const_u8_type,
|
||||
.slice_const_type_type => return .manyptr_const_type_type,
|
||||
else => {},
|
||||
}
|
||||
const item = index.unwrap(ip).getItem(ip);
|
||||
@@ -12013,8 +12014,13 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
|
||||
.manyptr_u8_type,
|
||||
.manyptr_const_u8_type,
|
||||
.manyptr_const_u8_sentinel_0_type,
|
||||
.manyptr_const_slice_const_u8_type,
|
||||
.slice_const_u8_type,
|
||||
.slice_const_u8_sentinel_0_type,
|
||||
.slice_const_slice_const_u8_type,
|
||||
.optional_type_type,
|
||||
.manyptr_const_type_type,
|
||||
.slice_const_type_type,
|
||||
.vector_8_i8_type,
|
||||
.vector_16_i8_type,
|
||||
.vector_32_i8_type,
|
||||
@@ -12355,8 +12361,12 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
|
||||
.manyptr_u8_type,
|
||||
.manyptr_const_u8_type,
|
||||
.manyptr_const_u8_sentinel_0_type,
|
||||
.manyptr_const_slice_const_u8_type,
|
||||
.slice_const_u8_type,
|
||||
.slice_const_u8_sentinel_0_type,
|
||||
.slice_const_slice_const_u8_type,
|
||||
.manyptr_const_type_type,
|
||||
.slice_const_type_type,
|
||||
=> .pointer,
|
||||
|
||||
.vector_8_i8_type,
|
||||
@@ -12408,6 +12418,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
|
||||
.vector_8_f64_type,
|
||||
=> .vector,
|
||||
|
||||
.optional_type_type => .optional,
|
||||
.optional_noreturn_type => .optional,
|
||||
.anyerror_void_error_union_type => .error_union,
|
||||
.empty_tuple_type => .@"struct",
|
||||
|
||||
+1236
-1285
@@ -1167,6 +1167,7 @@ fn analyzeBodyInner(
|
||||
.array_mul => try sema.zirArrayMul(block, inst),
|
||||
.array_type => try sema.zirArrayType(block, inst),
|
||||
.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
|
||||
.reify_int => try sema.zirReifyInt(block, inst),
|
||||
.vector_type => try sema.zirVectorType(block, inst),
|
||||
.as_node => try sema.zirAsNode(block, inst),
|
||||
.as_shift_operand => try sema.zirAsShiftOperand(block, inst),
|
||||
@@ -1411,7 +1412,6 @@ fn analyzeBodyInner(
|
||||
.select => try sema.zirSelect( block, extended),
|
||||
.int_from_error => try sema.zirIntFromError( block, extended),
|
||||
.error_from_int => try sema.zirErrorFromInt( block, extended),
|
||||
.reify => try sema.zirReify( block, extended, inst),
|
||||
.cmpxchg => try sema.zirCmpxchg( block, extended),
|
||||
.c_va_arg => try sema.zirCVaArg( block, extended),
|
||||
.c_va_copy => try sema.zirCVaCopy( block, extended),
|
||||
@@ -1424,6 +1424,16 @@ fn analyzeBodyInner(
|
||||
.work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),
|
||||
.in_comptime => try sema.zirInComptime( block),
|
||||
.closure_get => try sema.zirClosureGet( block, extended),
|
||||
|
||||
.reify_slice_arg_ty => try sema.zirReifySliceArgTy( block, extended),
|
||||
.reify_enum_value_slice_ty => try sema.zirReifyEnumValueSliceTy(block, extended),
|
||||
.reify_pointer_sentinel_ty => try sema.zirReifyPointerSentinelTy(block, extended),
|
||||
.reify_tuple => try sema.zirReifyTuple( block, extended),
|
||||
.reify_pointer => try sema.zirReifyPointer( block, extended),
|
||||
.reify_fn => try sema.zirReifyFn( block, extended),
|
||||
.reify_struct => try sema.zirReifyStruct( block, extended, inst),
|
||||
.reify_union => try sema.zirReifyUnion( block, extended, inst),
|
||||
.reify_enum => try sema.zirReifyEnum( block, extended, inst),
|
||||
// zig fmt: on
|
||||
|
||||
.set_float_mode => {
|
||||
@@ -3517,10 +3527,8 @@ fn zirOpaqueDecl(
|
||||
extra_index += captures_len * 2;
|
||||
|
||||
const opaque_init: InternPool.OpaqueTypeInit = .{
|
||||
.key = .{ .declared = .{
|
||||
.zir_index = tracked_inst,
|
||||
.captures = captures,
|
||||
} },
|
||||
.zir_index = tracked_inst,
|
||||
.captures = captures,
|
||||
};
|
||||
const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, opaque_init)) {
|
||||
.existing => |ty| {
|
||||
@@ -7386,7 +7394,7 @@ fn analyzeCall(
|
||||
const body = sema.code.bodySlice(extra.end, extra.data.type.body_len);
|
||||
|
||||
generic_block.comptime_reason = .{ .reason = .{
|
||||
.r = .{ .simple = .function_parameters },
|
||||
.r = .{ .simple = .fn_param_types },
|
||||
.src = param_src,
|
||||
} };
|
||||
|
||||
@@ -7470,7 +7478,7 @@ fn analyzeCall(
|
||||
sema.inst_map = generic_inst_map;
|
||||
|
||||
generic_block.comptime_reason = .{ .reason = .{
|
||||
.r = .{ .simple = .function_ret_ty },
|
||||
.r = .{ .simple = .fn_ret_ty },
|
||||
.src = func_ret_ty_src,
|
||||
} };
|
||||
|
||||
@@ -8927,7 +8935,7 @@ fn zirFunc(
|
||||
const ret_ty_body = sema.code.bodySlice(extra_index, extra.data.ret_ty.body_len);
|
||||
extra_index += ret_ty_body.len;
|
||||
|
||||
const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, .type, .{ .simple = .function_ret_ty });
|
||||
const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, .type, .{ .simple = .fn_ret_ty });
|
||||
break :blk ret_ty_val.toType();
|
||||
},
|
||||
};
|
||||
@@ -9171,6 +9179,181 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc:
|
||||
}
|
||||
}
|
||||
|
||||
fn checkParamTypeCommon(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
param_idx: u32,
|
||||
param_ty: Type,
|
||||
param_is_noalias: bool,
|
||||
param_src: LazySrcLoc,
|
||||
cc: std.builtin.CallingConvention,
|
||||
) CompileError!void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const target = zcu.getTarget();
|
||||
|
||||
if (!param_ty.isValidParamType(zcu)) {
|
||||
const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
|
||||
return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{
|
||||
opaque_str, param_ty.fmt(pt),
|
||||
});
|
||||
}
|
||||
if (!param_ty.isGenericPoison() and
|
||||
!target_util.fnCallConvAllowsZigTypes(cc) and
|
||||
!try sema.validateExternType(param_ty, .param_ty))
|
||||
{
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
|
||||
param_ty.fmt(pt), @tagName(cc),
|
||||
});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, param_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
switch (cc) {
|
||||
.x86_64_interrupt, .x86_interrupt => {
|
||||
const err_code_size = target.ptrBitWidth();
|
||||
switch (param_idx) {
|
||||
0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}),
|
||||
1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }),
|
||||
else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), param_idx + 1 }),
|
||||
}
|
||||
},
|
||||
.arc_interrupt,
|
||||
.arm_interrupt,
|
||||
.microblaze_interrupt,
|
||||
.mips64_interrupt,
|
||||
.mips_interrupt,
|
||||
.riscv64_interrupt,
|
||||
.riscv32_interrupt,
|
||||
.sh_interrupt,
|
||||
.avr_interrupt,
|
||||
.csky_interrupt,
|
||||
.m68k_interrupt,
|
||||
.msp430_interrupt,
|
||||
.avr_signal,
|
||||
=> return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}),
|
||||
else => {},
|
||||
}
|
||||
if (param_is_noalias and !param_ty.isGenericPoison() and !param_ty.isPtrAtRuntime(zcu) and !param_ty.isSliceAtRuntime(zcu)) {
|
||||
return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
|
||||
}
|
||||
}
|
||||
|
||||
fn checkReturnTypeAndCallConvCommon(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
bare_ret_ty: Type,
|
||||
ret_ty_src: LazySrcLoc,
|
||||
@"callconv": std.builtin.CallingConvention,
|
||||
callconv_src: LazySrcLoc,
|
||||
/// non-`null` only if the function is varargs.
|
||||
opt_varargs_src: ?LazySrcLoc,
|
||||
inferred_error_set: bool,
|
||||
is_noinline: bool,
|
||||
) CompileError!void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
if (opt_varargs_src) |varargs_src| {
|
||||
try sema.checkCallConvSupportsVarArgs(block, varargs_src, @"callconv");
|
||||
}
|
||||
if (inferred_error_set and !bare_ret_ty.isGenericPoison()) {
|
||||
try sema.validateErrorUnionPayloadType(block, bare_ret_ty, ret_ty_src);
|
||||
}
|
||||
const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else "";
|
||||
if (!bare_ret_ty.isValidReturnType(zcu)) {
|
||||
const opaque_str = if (bare_ret_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
|
||||
return sema.fail(block, ret_ty_src, "{s}return type '{s}{f}' not allowed", .{
|
||||
opaque_str, ies_ret_ty_prefix, bare_ret_ty.fmt(pt),
|
||||
});
|
||||
}
|
||||
if (!bare_ret_ty.isGenericPoison() and
|
||||
!target_util.fnCallConvAllowsZigTypes(@"callconv") and
|
||||
(inferred_error_set or !try sema.validateExternType(bare_ret_ty, .ret_ty)))
|
||||
{
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{
|
||||
ies_ret_ty_prefix, bare_ret_ty.fmt(pt), @tagName(@"callconv"),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
if (!inferred_error_set) {
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, bare_ret_ty, .ret_ty);
|
||||
try sema.addDeclaredHereNote(msg, bare_ret_ty);
|
||||
}
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
validate_incoming_stack_align: {
|
||||
const a: u64 = switch (@"callconv") {
|
||||
inline else => |payload| if (@TypeOf(payload) != void and @hasField(@TypeOf(payload), "incoming_stack_alignment"))
|
||||
payload.incoming_stack_alignment orelse break :validate_incoming_stack_align
|
||||
else
|
||||
break :validate_incoming_stack_align,
|
||||
};
|
||||
if (!std.math.isPowerOfTwo(a)) {
|
||||
return sema.fail(block, callconv_src, "calling convention incoming stack alignment '{d}' is not a power of two", .{a});
|
||||
}
|
||||
}
|
||||
switch (@"callconv") {
|
||||
.x86_64_interrupt,
|
||||
.x86_interrupt,
|
||||
.arm_interrupt,
|
||||
.mips64_interrupt,
|
||||
.mips_interrupt,
|
||||
.riscv64_interrupt,
|
||||
.riscv32_interrupt,
|
||||
.sh_interrupt,
|
||||
.arc_interrupt,
|
||||
.avr_interrupt,
|
||||
.csky_interrupt,
|
||||
.m68k_interrupt,
|
||||
.microblaze_interrupt,
|
||||
.msp430_interrupt,
|
||||
.avr_signal,
|
||||
=> {
|
||||
const ret_ok = !inferred_error_set and switch (bare_ret_ty.toIntern()) {
|
||||
.void_type, .noreturn_type => true,
|
||||
else => false,
|
||||
};
|
||||
if (!ret_ok) {
|
||||
return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(@"callconv")});
|
||||
}
|
||||
},
|
||||
.@"inline" => if (is_noinline) {
|
||||
return sema.fail(block, callconv_src, "'noinline' function cannot have calling convention 'inline'", .{});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
switch (zcu.callconvSupported(@"callconv")) {
|
||||
.ok => {},
|
||||
.bad_arch => |allowed_archs| {
|
||||
const ArchListFormatter = struct {
|
||||
archs: []const std.Target.Cpu.Arch,
|
||||
pub fn format(formatter: @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||
for (formatter.archs, 0..) |arch, i| {
|
||||
if (i != 0)
|
||||
try w.writeAll(", ");
|
||||
try w.print("'{s}'", .{@tagName(arch)});
|
||||
}
|
||||
}
|
||||
};
|
||||
return sema.fail(block, callconv_src, "calling convention '{s}' only available on architectures {f}", .{
|
||||
@tagName(@"callconv"),
|
||||
ArchListFormatter{ .archs = allowed_archs },
|
||||
});
|
||||
},
|
||||
.bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{
|
||||
@tagName(@"callconv"),
|
||||
@tagName(bad_backend),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn callConvIsCallable(cc: std.builtin.CallingConvention.Tag) bool {
|
||||
return switch (cc) {
|
||||
.naked,
|
||||
@@ -9259,7 +9442,6 @@ fn funcCommon(
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = sema.gpa;
|
||||
const target = zcu.getTarget();
|
||||
const ip = &zcu.intern_pool;
|
||||
const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
|
||||
const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
|
||||
@@ -9293,26 +9475,14 @@ fn funcCommon(
|
||||
if (param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc)) {
|
||||
return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
|
||||
}
|
||||
if (!param_ty.isValidParamType(zcu)) {
|
||||
const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
|
||||
return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{
|
||||
opaque_str, param_ty.fmt(pt),
|
||||
});
|
||||
}
|
||||
if (!param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
|
||||
param_ty.fmt(pt), @tagName(cc),
|
||||
});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, param_ty);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
try sema.checkParamTypeCommon(
|
||||
block,
|
||||
@intCast(i),
|
||||
param_ty,
|
||||
is_noalias,
|
||||
param_src,
|
||||
cc,
|
||||
);
|
||||
if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{
|
||||
@@ -9327,209 +9497,40 @@ fn funcCommon(
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
if (!param_ty_generic and is_noalias and
|
||||
!(param_ty.zigTypeTag(zcu) == .pointer or param_ty.isPtrLikeOptional(zcu)))
|
||||
{
|
||||
return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
|
||||
}
|
||||
switch (cc) {
|
||||
.x86_64_interrupt, .x86_interrupt => {
|
||||
const err_code_size = target.ptrBitWidth();
|
||||
switch (i) {
|
||||
0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}),
|
||||
1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }),
|
||||
else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), i + 1 }),
|
||||
}
|
||||
},
|
||||
.arc_interrupt,
|
||||
.arm_interrupt,
|
||||
.microblaze_interrupt,
|
||||
.mips64_interrupt,
|
||||
.mips_interrupt,
|
||||
.riscv64_interrupt,
|
||||
.riscv32_interrupt,
|
||||
.sh_interrupt,
|
||||
.avr_interrupt,
|
||||
.csky_interrupt,
|
||||
.m68k_interrupt,
|
||||
.msp430_interrupt,
|
||||
.avr_signal,
|
||||
=> return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (var_args) {
|
||||
if (is_generic) {
|
||||
return sema.fail(block, func_src, "generic function cannot be variadic", .{});
|
||||
}
|
||||
const va_args_src = block.src(.{
|
||||
.fn_proto_param = .{
|
||||
.fn_proto_node_offset = src_node_offset,
|
||||
.param_index = @intCast(block.params.len), // va_arg must be the last parameter
|
||||
},
|
||||
});
|
||||
try sema.checkCallConvSupportsVarArgs(block, va_args_src, cc);
|
||||
if (var_args and is_generic) {
|
||||
return sema.fail(block, func_src, "generic function cannot be variadic", .{});
|
||||
}
|
||||
|
||||
const ret_poison = bare_return_type.isGenericPoison();
|
||||
|
||||
const param_types = block.params.items(.ty);
|
||||
|
||||
if (inferred_error_set) {
|
||||
assert(has_body);
|
||||
if (!ret_poison)
|
||||
try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
|
||||
const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{
|
||||
.owner_nav = sema.owner.unwrap().nav_val,
|
||||
|
||||
.param_types = param_types,
|
||||
.noalias_bits = noalias_bits,
|
||||
.comptime_bits = comptime_bits,
|
||||
.bare_return_type = bare_return_type.toIntern(),
|
||||
.cc = cc,
|
||||
.is_var_args = var_args,
|
||||
.is_generic = is_generic,
|
||||
.is_noinline = is_noinline,
|
||||
|
||||
.zir_body_inst = try block.trackZir(func_inst),
|
||||
.lbrace_line = src_locs.lbrace_line,
|
||||
.rbrace_line = src_locs.rbrace_line,
|
||||
.lbrace_column = @as(u16, @truncate(src_locs.columns)),
|
||||
.rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
|
||||
});
|
||||
return finishFunc(
|
||||
sema,
|
||||
block,
|
||||
func_index,
|
||||
.none,
|
||||
ret_poison,
|
||||
bare_return_type,
|
||||
ret_ty_src,
|
||||
cc,
|
||||
ret_ty_requires_comptime,
|
||||
func_inst,
|
||||
cc_src,
|
||||
is_noinline,
|
||||
);
|
||||
}
|
||||
|
||||
const func_ty = try ip.getFuncType(gpa, pt.tid, .{
|
||||
.param_types = param_types,
|
||||
.noalias_bits = noalias_bits,
|
||||
.comptime_bits = comptime_bits,
|
||||
.return_type = bare_return_type.toIntern(),
|
||||
.cc = cc,
|
||||
.is_var_args = var_args,
|
||||
.is_generic = is_generic,
|
||||
.is_noinline = is_noinline,
|
||||
});
|
||||
|
||||
if (has_body) {
|
||||
const func_index = try ip.getFuncDecl(gpa, pt.tid, .{
|
||||
.owner_nav = sema.owner.unwrap().nav_val,
|
||||
.ty = func_ty,
|
||||
.cc = cc,
|
||||
.is_noinline = is_noinline,
|
||||
.zir_body_inst = try block.trackZir(func_inst),
|
||||
.lbrace_line = src_locs.lbrace_line,
|
||||
.rbrace_line = src_locs.rbrace_line,
|
||||
.lbrace_column = @as(u16, @truncate(src_locs.columns)),
|
||||
.rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
|
||||
});
|
||||
return finishFunc(
|
||||
sema,
|
||||
block,
|
||||
func_index,
|
||||
func_ty,
|
||||
ret_poison,
|
||||
bare_return_type,
|
||||
ret_ty_src,
|
||||
cc,
|
||||
ret_ty_requires_comptime,
|
||||
func_inst,
|
||||
cc_src,
|
||||
is_noinline,
|
||||
);
|
||||
}
|
||||
|
||||
return finishFunc(
|
||||
sema,
|
||||
try sema.checkReturnTypeAndCallConvCommon(
|
||||
block,
|
||||
.none,
|
||||
func_ty,
|
||||
ret_poison,
|
||||
bare_return_type,
|
||||
ret_ty_src,
|
||||
cc,
|
||||
ret_ty_requires_comptime,
|
||||
func_inst,
|
||||
cc_src,
|
||||
if (var_args) block.src(.{ .fn_proto_param = .{
|
||||
.fn_proto_node_offset = src_node_offset,
|
||||
.param_index = @intCast(block.params.len),
|
||||
} }) else null,
|
||||
inferred_error_set,
|
||||
is_noinline,
|
||||
);
|
||||
}
|
||||
|
||||
fn finishFunc(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
opt_func_index: InternPool.Index,
|
||||
func_ty: InternPool.Index,
|
||||
ret_poison: bool,
|
||||
bare_return_type: Type,
|
||||
ret_ty_src: LazySrcLoc,
|
||||
cc_resolved: std.builtin.CallingConvention,
|
||||
ret_ty_requires_comptime: bool,
|
||||
func_inst: Zir.Inst.Index,
|
||||
cc_src: LazySrcLoc,
|
||||
is_noinline: bool,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const gpa = sema.gpa;
|
||||
|
||||
const return_type: Type = if (opt_func_index == .none or ret_poison)
|
||||
bare_return_type
|
||||
else
|
||||
.fromInterned(ip.funcTypeReturnType(ip.typeOf(opt_func_index)));
|
||||
|
||||
if (!return_type.isValidReturnType(zcu)) {
|
||||
const opaque_str = if (return_type.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
|
||||
return sema.fail(block, ret_ty_src, "{s}return type '{f}' not allowed", .{
|
||||
opaque_str, return_type.fmt(pt),
|
||||
});
|
||||
}
|
||||
if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(cc_resolved) and
|
||||
!try sema.validateExternType(return_type, .ret_ty))
|
||||
{
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{s}'", .{
|
||||
return_type.fmt(pt), @tagName(cc_resolved),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, return_type, .ret_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, return_type);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
|
||||
// If the return type is comptime-only but not dependent on parameters then
|
||||
// all parameter types also need to be comptime.
|
||||
if (opt_func_index != .none and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {
|
||||
if (has_body and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {
|
||||
for (block.params.items(.is_comptime)) |is_comptime| {
|
||||
if (!is_comptime) break;
|
||||
} else break :comptime_check;
|
||||
|
||||
const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else "";
|
||||
const msg = try sema.errMsg(
|
||||
ret_ty_src,
|
||||
"function with comptime-only return type '{f}' requires all parameters to be comptime",
|
||||
.{return_type.fmt(pt)},
|
||||
"function with comptime-only return type '{s}{f}' requires all parameters to be comptime",
|
||||
.{ ies_ret_ty_prefix, bare_return_type.fmt(pt) },
|
||||
);
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
try sema.explainWhyTypeIsComptime(msg, ret_ty_src, return_type);
|
||||
try sema.explainWhyTypeIsComptime(msg, ret_ty_src, bare_return_type);
|
||||
|
||||
const tags = sema.code.instructions.items(.tag);
|
||||
const data = sema.code.instructions.items(.data);
|
||||
@@ -9556,68 +9557,56 @@ fn finishFunc(
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
|
||||
validate_incoming_stack_align: {
|
||||
const a: u64 = switch (cc_resolved) {
|
||||
inline else => |payload| if (@TypeOf(payload) != void and @hasField(@TypeOf(payload), "incoming_stack_alignment"))
|
||||
payload.incoming_stack_alignment orelse break :validate_incoming_stack_align
|
||||
else
|
||||
break :validate_incoming_stack_align,
|
||||
};
|
||||
if (!std.math.isPowerOfTwo(a)) {
|
||||
return sema.fail(block, cc_src, "calling convention incoming stack alignment '{d}' is not a power of two", .{a});
|
||||
}
|
||||
const param_types = block.params.items(.ty);
|
||||
|
||||
if (inferred_error_set) {
|
||||
assert(has_body);
|
||||
return .fromIntern(try ip.getFuncDeclIes(gpa, pt.tid, .{
|
||||
.owner_nav = sema.owner.unwrap().nav_val,
|
||||
|
||||
.param_types = param_types,
|
||||
.noalias_bits = noalias_bits,
|
||||
.comptime_bits = comptime_bits,
|
||||
.bare_return_type = bare_return_type.toIntern(),
|
||||
.cc = cc,
|
||||
.is_var_args = var_args,
|
||||
.is_generic = is_generic,
|
||||
.is_noinline = is_noinline,
|
||||
|
||||
.zir_body_inst = try block.trackZir(func_inst),
|
||||
.lbrace_line = src_locs.lbrace_line,
|
||||
.rbrace_line = src_locs.rbrace_line,
|
||||
.lbrace_column = @as(u16, @truncate(src_locs.columns)),
|
||||
.rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
|
||||
}));
|
||||
}
|
||||
|
||||
switch (cc_resolved) {
|
||||
.x86_64_interrupt,
|
||||
.x86_interrupt,
|
||||
.arm_interrupt,
|
||||
.mips64_interrupt,
|
||||
.mips_interrupt,
|
||||
.riscv64_interrupt,
|
||||
.riscv32_interrupt,
|
||||
.sh_interrupt,
|
||||
.arc_interrupt,
|
||||
.avr_interrupt,
|
||||
.csky_interrupt,
|
||||
.m68k_interrupt,
|
||||
.microblaze_interrupt,
|
||||
.msp430_interrupt,
|
||||
.avr_signal,
|
||||
=> if (return_type.zigTypeTag(zcu) != .void and return_type.zigTypeTag(zcu) != .noreturn) {
|
||||
return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(cc_resolved)});
|
||||
},
|
||||
.@"inline" => if (is_noinline) {
|
||||
return sema.fail(block, cc_src, "'noinline' function cannot have calling convention 'inline'", .{});
|
||||
},
|
||||
else => {},
|
||||
const func_ty = try ip.getFuncType(gpa, pt.tid, .{
|
||||
.param_types = param_types,
|
||||
.noalias_bits = noalias_bits,
|
||||
.comptime_bits = comptime_bits,
|
||||
.return_type = bare_return_type.toIntern(),
|
||||
.cc = cc,
|
||||
.is_var_args = var_args,
|
||||
.is_generic = is_generic,
|
||||
.is_noinline = is_noinline,
|
||||
});
|
||||
|
||||
if (has_body) {
|
||||
return .fromIntern(try ip.getFuncDecl(gpa, pt.tid, .{
|
||||
.owner_nav = sema.owner.unwrap().nav_val,
|
||||
.ty = func_ty,
|
||||
.cc = cc,
|
||||
.is_noinline = is_noinline,
|
||||
.zir_body_inst = try block.trackZir(func_inst),
|
||||
.lbrace_line = src_locs.lbrace_line,
|
||||
.rbrace_line = src_locs.rbrace_line,
|
||||
.lbrace_column = @as(u16, @truncate(src_locs.columns)),
|
||||
.rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
|
||||
}));
|
||||
}
|
||||
|
||||
switch (zcu.callconvSupported(cc_resolved)) {
|
||||
.ok => {},
|
||||
.bad_arch => |allowed_archs| {
|
||||
const ArchListFormatter = struct {
|
||||
archs: []const std.Target.Cpu.Arch,
|
||||
pub fn format(formatter: @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||
for (formatter.archs, 0..) |arch, i| {
|
||||
if (i != 0)
|
||||
try w.writeAll(", ");
|
||||
try w.print("'{s}'", .{@tagName(arch)});
|
||||
}
|
||||
}
|
||||
};
|
||||
return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {f}", .{
|
||||
@tagName(cc_resolved),
|
||||
ArchListFormatter{ .archs = allowed_archs },
|
||||
});
|
||||
},
|
||||
.bad_backend => |bad_backend| return sema.fail(block, cc_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{
|
||||
@tagName(cc_resolved),
|
||||
@tagName(bad_backend),
|
||||
}),
|
||||
}
|
||||
|
||||
return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty);
|
||||
return .fromIntern(func_ty);
|
||||
}
|
||||
|
||||
fn zirParam(
|
||||
@@ -19395,7 +19384,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
if (union_ty.zigTypeTag(pt.zcu) != .@"union") {
|
||||
return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)});
|
||||
}
|
||||
const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_name });
|
||||
const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names });
|
||||
const init = try sema.resolveInst(extra.init);
|
||||
return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
|
||||
}
|
||||
@@ -20553,7 +20542,338 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
return block.addUnOp(.tag_name, casted_operand);
|
||||
}
|
||||
|
||||
fn zirReify(
|
||||
fn zirReifyInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const signedness_src = block.builtinCallArgSrc(inst_data.src_node, 0);
|
||||
const bits_src = block.builtinCallArgSrc(inst_data.src_node, 1);
|
||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||
const signedness = try sema.resolveBuiltinEnum(block, signedness_src, extra.lhs, .Signedness, .{ .simple = .int_signedness });
|
||||
const bits: u16 = @intCast(try sema.resolveInt(block, bits_src, extra.rhs, .u16, .{ .simple = .int_bit_width }));
|
||||
return .fromType(try sema.pt.intType(signedness, bits));
|
||||
}
|
||||
|
||||
fn zirReifySliceArgTy(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||
const info: Zir.Inst.ReifySliceArgInfo = @enumFromInt(extended.small);
|
||||
|
||||
const src = block.nodeOffset(extra.node);
|
||||
|
||||
const comptime_reason: std.zig.SimpleComptimeReason, const in_scalar_ty: Type, const out_scalar_ty: Type = switch (info) {
|
||||
// zig fmt: off
|
||||
.type_to_fn_param_attrs => .{ .fn_param_attrs, .type, try sema.getBuiltinType(src, .@"Type.Fn.Param.Attributes") },
|
||||
.string_to_struct_field_type => .{ .struct_field_types, .slice_const_u8, .type },
|
||||
.string_to_union_field_type => .{ .union_field_types, .slice_const_u8, .type },
|
||||
.string_to_struct_field_attrs => .{ .struct_field_attrs, .slice_const_u8, try sema.getBuiltinType(src, .@"Type.StructField.Attributes") },
|
||||
.string_to_union_field_attrs => .{ .union_field_attrs, .slice_const_u8, try sema.getBuiltinType(src, .@"Type.UnionField.Attributes") },
|
||||
// zig fmt: on
|
||||
};
|
||||
|
||||
const operand_ty = try pt.ptrTypeSema(.{
|
||||
.child = in_scalar_ty.toIntern(),
|
||||
.flags = .{ .size = .slice, .is_const = true },
|
||||
});
|
||||
|
||||
const operand_uncoerced = try sema.resolveInst(extra.operand);
|
||||
const operand_coerced = try sema.coerce(block, operand_ty, operand_uncoerced, src);
|
||||
const operand_val = try sema.resolveConstDefinedValue(block, src, operand_coerced, .{ .simple = comptime_reason });
|
||||
const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
|
||||
if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);
|
||||
const len = try len_val.toUnsignedIntSema(pt);
|
||||
|
||||
return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = len,
|
||||
.child = out_scalar_ty.toIntern(),
|
||||
})));
|
||||
}
|
||||
|
||||
fn zirReifyEnumValueSliceTy(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
|
||||
|
||||
const int_tag_ty_src = block.builtinCallArgSrc(extra.node, 0);
|
||||
const field_names_src = block.builtinCallArgSrc(extra.node, 2);
|
||||
|
||||
const int_tag_ty = try sema.resolveType(block, int_tag_ty_src, extra.lhs);
|
||||
|
||||
const operand_uncoerced = try sema.resolveInst(extra.rhs);
|
||||
const operand_coerced = try sema.coerce(block, .slice_const_slice_const_u8, operand_uncoerced, field_names_src);
|
||||
const operand_val = try sema.resolveConstDefinedValue(block, field_names_src, operand_coerced, .{ .simple = .enum_field_names });
|
||||
const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
|
||||
if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, field_names_src, null);
|
||||
const len = try len_val.toUnsignedIntSema(pt);
|
||||
|
||||
return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = len,
|
||||
.child = int_tag_ty.toIntern(),
|
||||
})));
|
||||
}
|
||||
|
||||
fn zirReifyPointerSentinelTy(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||
const src = block.nodeOffset(extra.node);
|
||||
const elem_ty = try sema.resolveType(block, src, extra.operand);
|
||||
return .fromType(switch (elem_ty.zigTypeTag(zcu)) {
|
||||
else => try pt.optionalType(elem_ty.toIntern()),
|
||||
// These types cannot be the child of an optional. To allow reifying pointers to them still,
|
||||
// we treat the "sentinel" argument to `@Pointer` as `?noreturn` instead of `?T`.
|
||||
.@"opaque", .null => .optional_noreturn,
|
||||
});
|
||||
}
|
||||
|
||||
fn zirReifyTuple(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||
const operand_src = block.builtinCallArgSrc(extra.node, 0);
|
||||
|
||||
const types_uncoerced = try sema.resolveInst(extra.operand);
|
||||
const types_coerced = try sema.coerce(block, .slice_const_type, types_uncoerced, operand_src);
|
||||
const types_slice_val = try sema.resolveConstDefinedValue(block, operand_src, types_coerced, .{ .simple = .tuple_field_types });
|
||||
const types_array_val = try sema.derefSliceAsArray(block, operand_src, types_slice_val, .{ .simple = .tuple_field_types });
|
||||
const fields_len: u32 = @intCast(types_array_val.typeOf(zcu).arrayLen(zcu));
|
||||
|
||||
const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
|
||||
for (field_types, 0..) |*field_ty, field_idx| {
|
||||
const field_ty_val = try types_array_val.elemValue(pt, field_idx);
|
||||
if (field_ty_val.isUndef(zcu)) {
|
||||
return sema.failWithUseOfUndef(block, operand_src, null);
|
||||
}
|
||||
field_ty.* = field_ty_val.toIntern();
|
||||
}
|
||||
|
||||
const field_values = try sema.arena.alloc(InternPool.Index, fields_len);
|
||||
@memset(field_values, .none);
|
||||
|
||||
return .fromIntern(try zcu.intern_pool.getTupleType(zcu.gpa, pt.tid, .{
|
||||
.types = field_types,
|
||||
.values = field_values,
|
||||
}));
|
||||
}
|
||||
|
||||
fn zirReifyPointer(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
const extra = sema.code.extraData(Zir.Inst.ReifyPointer, extended.operand).data;
|
||||
const src = block.nodeOffset(extra.node);
|
||||
const size_src = block.builtinCallArgSrc(extra.node, 0);
|
||||
const attrs_src = block.builtinCallArgSrc(extra.node, 1);
|
||||
const elem_ty_src = block.builtinCallArgSrc(extra.node, 2);
|
||||
const sentinel_src = block.builtinCallArgSrc(extra.node, 3);
|
||||
|
||||
const size_ty = try sema.getBuiltinType(size_src, .@"Type.Pointer.Size");
|
||||
const attrs_ty = try sema.getBuiltinType(attrs_src, .@"Type.Pointer.Attributes");
|
||||
|
||||
const size_uncoerced = try sema.resolveInst(extra.size);
|
||||
const size_coerced = try sema.coerce(block, size_ty, size_uncoerced, size_src);
|
||||
const size_val = try sema.resolveConstDefinedValue(block, size_src, size_coerced, .{ .simple = .pointer_size });
|
||||
const size = try sema.interpretBuiltinType(block, size_src, size_val, std.builtin.Type.Pointer.Size);
|
||||
|
||||
const attrs_uncoerced = try sema.resolveInst(extra.attrs);
|
||||
const attrs_coerced = try sema.coerce(block, attrs_ty, attrs_uncoerced, attrs_src);
|
||||
const attrs_val = try sema.resolveConstDefinedValue(block, attrs_src, attrs_coerced, .{ .simple = .pointer_attrs });
|
||||
const attrs = try sema.interpretBuiltinType(block, attrs_src, attrs_val, std.builtin.Type.Pointer.Attributes);
|
||||
|
||||
const @"align": Alignment = if (attrs.@"align") |bytes| a: {
|
||||
break :a try sema.validateAlign(block, attrs_src, bytes);
|
||||
} else .none;
|
||||
|
||||
const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_ty);
|
||||
|
||||
switch (elem_ty.zigTypeTag(zcu)) {
|
||||
.noreturn => return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}),
|
||||
// This needs to be disallowed, because the sentinel parameter would otherwise have type
|
||||
// `?@TypeOf(null)`, which is not a valid type because you cannot differentiate between
|
||||
// constructing the "inner" null value and the "outer" null value.
|
||||
.null => return sema.fail(block, elem_ty_src, "cannot reify pointer to '@TypeOf(null)'", .{}),
|
||||
.@"fn" => switch (size) {
|
||||
.one => {},
|
||||
.many, .c, .slice => return sema.fail(block, src, "function pointers must be single pointers", .{}),
|
||||
},
|
||||
.@"opaque" => switch (size) {
|
||||
.one => {},
|
||||
.many, .c, .slice => return sema.fail(block, src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}),
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (size == .c and !try sema.validateExternType(elem_ty, .other)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
|
||||
try sema.addDeclaredHereNote(msg, elem_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
|
||||
const sentinel_ty = try pt.optionalType(elem_ty.toIntern());
|
||||
const sentinel_uncoerced = try sema.resolveInst(extra.sentinel);
|
||||
const sentinel_coerced = try sema.coerce(block, sentinel_ty, sentinel_uncoerced, sentinel_src);
|
||||
const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel_coerced, .{ .simple = .pointer_sentinel });
|
||||
const opt_sentinel = sentinel_val.optionalValue(zcu);
|
||||
if (opt_sentinel) |sentinel| {
|
||||
switch (size) {
|
||||
.many, .slice => {},
|
||||
.one, .c => return sema.fail(block, sentinel_src, "sentinels are only allowed on slices and unknown-length pointers", .{}),
|
||||
}
|
||||
try checkSentinelType(sema, block, sentinel_src, elem_ty);
|
||||
if (sentinel.canMutateComptimeVarState(zcu)) {
|
||||
const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel", .no_embedded_nulls);
|
||||
return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel);
|
||||
}
|
||||
}
|
||||
|
||||
return .fromType(try pt.ptrTypeSema(.{
|
||||
.child = elem_ty.toIntern(),
|
||||
.sentinel = if (opt_sentinel) |s| s.toIntern() else .none,
|
||||
.flags = .{
|
||||
.size = size,
|
||||
.is_const = attrs.@"const",
|
||||
.is_volatile = attrs.@"volatile",
|
||||
.is_allowzero = attrs.@"allowzero",
|
||||
.address_space = attrs.@"addrspace" orelse as: {
|
||||
if (elem_ty.zigTypeTag(zcu) == .@"fn" and zcu.getTarget().cpu.arch == .avr) break :as .flash;
|
||||
break :as .generic;
|
||||
},
|
||||
.alignment = @"align",
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
fn zirReifyFn(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
const extra = sema.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
|
||||
const param_types_src = block.builtinCallArgSrc(extra.node, 0);
|
||||
const param_attrs_src = block.builtinCallArgSrc(extra.node, 1);
|
||||
const ret_ty_src = block.builtinCallArgSrc(extra.node, 2);
|
||||
const fn_attrs_src = block.builtinCallArgSrc(extra.node, 3);
|
||||
|
||||
const single_param_attrs_ty = try sema.getBuiltinType(param_attrs_src, .@"Type.Fn.Param.Attributes");
|
||||
const fn_attrs_ty = try sema.getBuiltinType(fn_attrs_src, .@"Type.Fn.Attributes");
|
||||
|
||||
const param_types_uncoerced = try sema.resolveInst(extra.param_types);
|
||||
const param_types_coerced = try sema.coerce(block, .slice_const_type, param_types_uncoerced, param_types_src);
|
||||
const param_types_slice = try sema.resolveConstDefinedValue(block, param_types_src, param_types_coerced, .{ .simple = .fn_param_types });
|
||||
const param_types_arr = try sema.derefSliceAsArray(block, param_types_src, param_types_slice, .{ .simple = .fn_param_types });
|
||||
|
||||
const params_len = param_types_arr.typeOf(zcu).arrayLen(zcu);
|
||||
|
||||
const param_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = params_len,
|
||||
.child = single_param_attrs_ty.toIntern(),
|
||||
}));
|
||||
const param_attrs_uncoerced = try sema.resolveInst(extra.param_attrs);
|
||||
const param_attrs_coerced = try sema.coerce(block, param_attrs_ty, param_attrs_uncoerced, param_attrs_src);
|
||||
const param_attrs_slice = try sema.resolveConstDefinedValue(block, param_attrs_src, param_attrs_coerced, .{ .simple = .fn_param_attrs });
|
||||
const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs });
|
||||
|
||||
const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty);
|
||||
|
||||
const fn_attrs_uncoerced = try sema.resolveInst(extra.fn_attrs);
|
||||
const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src);
|
||||
const fn_attrs_val = try sema.resolveConstDefinedValue(block, fn_attrs_src, fn_attrs_coerced, .{ .simple = .fn_attrs });
|
||||
const fn_attrs = try sema.interpretBuiltinType(block, fn_attrs_src, fn_attrs_val, std.builtin.Type.Fn.Attributes);
|
||||
|
||||
var noalias_bits: u32 = 0;
|
||||
const param_types_ip = try sema.arena.alloc(InternPool.Index, @intCast(params_len));
|
||||
for (param_types_ip, 0..@intCast(params_len)) |*param_ty_ip, param_idx| {
|
||||
const param_ty: Type = (try param_types_arr.elemValue(pt, param_idx)).toType();
|
||||
const param_attrs = try sema.interpretBuiltinType(
|
||||
block,
|
||||
param_attrs_src,
|
||||
try param_attrs_arr.elemValue(pt, param_idx),
|
||||
std.builtin.Type.Fn.Param.Attributes,
|
||||
);
|
||||
try sema.checkParamTypeCommon(
|
||||
block,
|
||||
@intCast(param_idx),
|
||||
param_ty,
|
||||
param_attrs.@"noalias",
|
||||
param_types_src,
|
||||
fn_attrs.@"callconv",
|
||||
);
|
||||
if (try param_ty.comptimeOnlySema(pt)) {
|
||||
return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)});
|
||||
}
|
||||
if (param_attrs.@"noalias") {
|
||||
if (param_idx > 31) {
|
||||
return sema.fail(block, param_attrs_src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{});
|
||||
}
|
||||
noalias_bits |= @as(u32, 1) << @intCast(param_idx);
|
||||
}
|
||||
param_ty_ip.* = param_ty.toIntern();
|
||||
}
|
||||
|
||||
if (fn_attrs.varargs) {
|
||||
try sema.checkCallConvSupportsVarArgs(block, fn_attrs_src, fn_attrs.@"callconv");
|
||||
}
|
||||
|
||||
try sema.checkReturnTypeAndCallConvCommon(
|
||||
block,
|
||||
ret_ty,
|
||||
ret_ty_src,
|
||||
fn_attrs.@"callconv",
|
||||
fn_attrs_src,
|
||||
if (fn_attrs.varargs) fn_attrs_src else null,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
if (try ret_ty.comptimeOnlySema(pt)) {
|
||||
return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});
|
||||
}
|
||||
|
||||
return .fromIntern(try ip.getFuncType(gpa, pt.tid, .{
|
||||
.param_types = param_types_ip,
|
||||
.noalias_bits = noalias_bits,
|
||||
.comptime_bits = 0,
|
||||
.return_type = ret_ty.toIntern(),
|
||||
.cc = fn_attrs.@"callconv",
|
||||
.is_var_args = fn_attrs.varargs,
|
||||
.is_generic = false,
|
||||
.is_noinline = false,
|
||||
}));
|
||||
}
|
||||
|
||||
fn zirReifyStruct(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
@@ -20563,579 +20883,188 @@ fn zirReify(
|
||||
const zcu = pt.zcu;
|
||||
const gpa = sema.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
|
||||
const extra = sema.code.extraData(Zir.Inst.Reify, extended.operand).data;
|
||||
const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
|
||||
const tracked_inst = try block.trackZir(inst);
|
||||
const src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = LazySrcLoc.Offset.nodeOffset(.zero),
|
||||
.offset = .nodeOffset(.zero),
|
||||
};
|
||||
const operand_src: LazySrcLoc = .{
|
||||
|
||||
const layout_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{
|
||||
.node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero, // `tracked_inst` is precisely the `reify` instruction, so offset is 0
|
||||
.arg_index = 0,
|
||||
},
|
||||
},
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 0,
|
||||
} },
|
||||
};
|
||||
const type_info_ty = try sema.getBuiltinType(src, .Type);
|
||||
const uncasted_operand = try sema.resolveInst(extra.operand);
|
||||
const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
|
||||
const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{ .simple = .operand_Type });
|
||||
const union_val = ip.indexToKey(val.toIntern()).un;
|
||||
if (try sema.anyUndef(block, operand_src, Value.fromInterned(union_val.val))) {
|
||||
return sema.failWithUseOfUndef(block, operand_src, null);
|
||||
const backing_ty_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 1,
|
||||
} },
|
||||
};
|
||||
const field_names_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 2,
|
||||
} },
|
||||
};
|
||||
const field_types_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 3,
|
||||
} },
|
||||
};
|
||||
const field_attrs_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 4,
|
||||
} },
|
||||
};
|
||||
|
||||
const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout");
|
||||
const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.StructField.Attributes");
|
||||
|
||||
const layout_uncoerced = try sema.resolveInst(extra.layout);
|
||||
const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src);
|
||||
const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .struct_layout });
|
||||
const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout);
|
||||
|
||||
const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty);
|
||||
const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src);
|
||||
const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .type });
|
||||
|
||||
const field_names_uncoerced = try sema.resolveInst(extra.field_names);
|
||||
const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
|
||||
const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .struct_field_names });
|
||||
const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .struct_field_names });
|
||||
|
||||
const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu));
|
||||
|
||||
const field_types_ty = try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = fields_len,
|
||||
.child = .type_type,
|
||||
}));
|
||||
const field_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = fields_len,
|
||||
.child = single_field_attrs_ty.toIntern(),
|
||||
}));
|
||||
|
||||
const field_types_uncoerced = try sema.resolveInst(extra.field_types);
|
||||
const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src);
|
||||
const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .struct_field_types });
|
||||
const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .struct_field_types });
|
||||
|
||||
const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs);
|
||||
const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src);
|
||||
const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .struct_field_attrs });
|
||||
const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .struct_field_attrs });
|
||||
|
||||
// Before we begin, check for undefs...
|
||||
if (try sema.anyUndef(block, field_attrs_src, field_attrs_arr)) {
|
||||
return sema.failWithUseOfUndef(block, field_attrs_src, null);
|
||||
}
|
||||
const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), zcu).?;
|
||||
switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
|
||||
.type => return .type_type,
|
||||
.void => return .void_type,
|
||||
.bool => return .bool_type,
|
||||
.noreturn => return .noreturn_type,
|
||||
.comptime_float => return .comptime_float_type,
|
||||
.comptime_int => return .comptime_int_type,
|
||||
.undefined => return .undefined_type,
|
||||
.null => return .null_type,
|
||||
.@"anyframe" => return sema.failWithUseOfAsync(block, src),
|
||||
.enum_literal => return .enum_literal_type,
|
||||
.int => {
|
||||
const int = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Int);
|
||||
const ty = try pt.intType(int.signedness, int.bits);
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.vector => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const len_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls),
|
||||
).?);
|
||||
const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
const len: u32 = @intCast(try len_val.toUnsignedIntSema(pt));
|
||||
const child_ty = child_val.toType();
|
||||
|
||||
try sema.checkVectorElemType(block, src, child_ty);
|
||||
|
||||
const ty = try pt.vectorType(.{
|
||||
.len = len,
|
||||
.child = child_ty.toIntern(),
|
||||
});
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.float => {
|
||||
const float = try sema.interpretBuiltinType(block, operand_src, .fromInterned(union_val.val), std.builtin.Type.Float);
|
||||
|
||||
const ty: Type = switch (float.bits) {
|
||||
16 => .f16,
|
||||
32 => .f32,
|
||||
64 => .f64,
|
||||
80 => .f80,
|
||||
128 => .f128,
|
||||
else => return sema.fail(block, src, "{d}-bit float unsupported", .{float.bits}),
|
||||
};
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.pointer => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const size_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "size", .no_embedded_nulls),
|
||||
).?);
|
||||
const is_const_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_const", .no_embedded_nulls),
|
||||
).?);
|
||||
const is_volatile_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_volatile", .no_embedded_nulls),
|
||||
).?);
|
||||
const alignment_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "alignment", .no_embedded_nulls),
|
||||
).?);
|
||||
const address_space_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "address_space", .no_embedded_nulls),
|
||||
).?);
|
||||
const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
|
||||
).?);
|
||||
const is_allowzero_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_allowzero", .no_embedded_nulls),
|
||||
).?);
|
||||
const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
if (!try sema.intFitsInType(alignment_val, align_ty, null)) {
|
||||
return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
|
||||
}
|
||||
const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);
|
||||
const abi_align = try sema.validateAlign(block, src, alignment_val_int);
|
||||
|
||||
const elem_ty = child_val.toType();
|
||||
if (abi_align != .none) {
|
||||
try elem_ty.resolveLayout(pt);
|
||||
}
|
||||
|
||||
const ptr_size = try sema.interpretBuiltinType(block, operand_src, size_val, std.builtin.Type.Pointer.Size);
|
||||
|
||||
const actual_sentinel: InternPool.Index = s: {
|
||||
if (!sentinel_val.isNull(zcu)) {
|
||||
if (ptr_size == .one or ptr_size == .c) {
|
||||
return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
|
||||
}
|
||||
const sentinel_ptr_val = sentinel_val.optionalValue(zcu).?;
|
||||
const ptr_ty = try pt.singleMutPtrType(elem_ty);
|
||||
const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
|
||||
try sema.checkSentinelType(block, src, elem_ty);
|
||||
if (sent_val.canMutateComptimeVarState(zcu)) {
|
||||
const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls);
|
||||
return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sent_val);
|
||||
}
|
||||
break :s sent_val.toIntern();
|
||||
}
|
||||
break :s .none;
|
||||
};
|
||||
|
||||
if (elem_ty.zigTypeTag(zcu) == .noreturn) {
|
||||
return sema.fail(block, src, "pointer to noreturn not allowed", .{});
|
||||
} else if (elem_ty.zigTypeTag(zcu) == .@"fn") {
|
||||
if (ptr_size != .one) {
|
||||
return sema.fail(block, src, "function pointers must be single pointers", .{});
|
||||
}
|
||||
} else if (ptr_size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {
|
||||
return sema.fail(block, src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});
|
||||
} else if (ptr_size == .c) {
|
||||
if (!try sema.validateExternType(elem_ty, .other)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src, elem_ty, .other);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, elem_ty);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
}
|
||||
|
||||
const ty = try pt.ptrTypeSema(.{
|
||||
.child = elem_ty.toIntern(),
|
||||
.sentinel = actual_sentinel,
|
||||
.flags = .{
|
||||
.size = ptr_size,
|
||||
.is_const = is_const_val.toBool(),
|
||||
.is_volatile = is_volatile_val.toBool(),
|
||||
.alignment = abi_align,
|
||||
.address_space = try sema.interpretBuiltinType(block, operand_src, address_space_val, std.builtin.AddressSpace),
|
||||
.is_allowzero = is_allowzero_val.toBool(),
|
||||
},
|
||||
});
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.array => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const len_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "len", .no_embedded_nulls),
|
||||
).?);
|
||||
const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
|
||||
).?);
|
||||
const sentinel_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
const len = try len_val.toUnsignedIntSema(pt);
|
||||
const child_ty = child_val.toType();
|
||||
const sentinel = if (sentinel_val.optionalValue(zcu)) |p| blk: {
|
||||
const ptr_ty = try pt.singleMutPtrType(child_ty);
|
||||
try sema.checkSentinelType(block, src, child_ty);
|
||||
const sentinel = (try sema.pointerDeref(block, src, p, ptr_ty)).?;
|
||||
if (sentinel.canMutateComptimeVarState(zcu)) {
|
||||
const sentinel_name = try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls);
|
||||
return sema.failWithContainsReferenceToComptimeVar(block, src, sentinel_name, "sentinel", sentinel);
|
||||
}
|
||||
break :blk sentinel;
|
||||
} else null;
|
||||
|
||||
const ty = try pt.arrayType(.{
|
||||
.len = len,
|
||||
.sentinel = if (sentinel) |s| s.toIntern() else .none,
|
||||
.child = child_ty.toIntern(),
|
||||
});
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.optional => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const child_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "child", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
const child_ty = child_val.toType();
|
||||
|
||||
const ty = try pt.optionalType(child_ty.toIntern());
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.error_union => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const error_set_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "error_set", .no_embedded_nulls),
|
||||
).?);
|
||||
const payload_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "payload", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
const error_set_ty = error_set_val.toType();
|
||||
const payload_ty = payload_val.toType();
|
||||
|
||||
if (error_set_ty.zigTypeTag(zcu) != .error_set) {
|
||||
return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{});
|
||||
}
|
||||
|
||||
const ty = try pt.errorUnionType(error_set_ty, payload_ty);
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.error_set => {
|
||||
const payload_val = Value.fromInterned(union_val.val).optionalValue(zcu) orelse
|
||||
return .anyerror_type;
|
||||
|
||||
const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{ .simple = .error_set_contents });
|
||||
|
||||
const len = try sema.usizeCast(block, src, names_val.typeOf(zcu).arrayLen(zcu));
|
||||
var names: InferredErrorSet.NameMap = .{};
|
||||
try names.ensureUnusedCapacity(sema.arena, len);
|
||||
for (0..len) |i| {
|
||||
const elem_val = try names_val.elemValue(pt, i);
|
||||
const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
|
||||
const name_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
const name = try sema.sliceToIpString(block, src, name_val, .{ .simple = .error_set_contents });
|
||||
_ = try pt.getErrorValue(name);
|
||||
const gop = names.getOrPutAssumeCapacity(name);
|
||||
if (gop.found_existing) {
|
||||
return sema.fail(block, src, "duplicate error '{f}'", .{
|
||||
name.fmt(ip),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const ty = try pt.errorSetFromUnsortedNames(names.keys());
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.@"struct" => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const layout_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "layout", .no_embedded_nulls),
|
||||
).?);
|
||||
const backing_integer_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "backing_integer", .no_embedded_nulls),
|
||||
).?);
|
||||
const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls),
|
||||
).?);
|
||||
const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
|
||||
).?);
|
||||
const is_tuple_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_tuple", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
|
||||
|
||||
// Decls
|
||||
if (try decls_val.sliceLen(pt) > 0) {
|
||||
return sema.fail(block, src, "reified structs must have no decls", .{});
|
||||
}
|
||||
|
||||
if (layout != .@"packed" and !backing_integer_val.isNull(zcu)) {
|
||||
return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
|
||||
}
|
||||
|
||||
const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .struct_fields });
|
||||
|
||||
if (is_tuple_val.toBool()) {
|
||||
switch (layout) {
|
||||
.@"extern" => return sema.fail(block, src, "extern tuples are not supported", .{}),
|
||||
.@"packed" => return sema.fail(block, src, "packed tuples are not supported", .{}),
|
||||
.auto => {},
|
||||
}
|
||||
return sema.reifyTuple(block, src, fields_arr);
|
||||
} else {
|
||||
return sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy);
|
||||
}
|
||||
},
|
||||
.@"enum" => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "tag_type", .no_embedded_nulls),
|
||||
).?);
|
||||
const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls),
|
||||
).?);
|
||||
const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
|
||||
).?);
|
||||
const is_exhaustive_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_exhaustive", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
if (try decls_val.sliceLen(pt) > 0) {
|
||||
return sema.fail(block, src, "reified enums must have no decls", .{});
|
||||
}
|
||||
|
||||
const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .enum_fields });
|
||||
|
||||
return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy);
|
||||
},
|
||||
.@"opaque" => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
// Decls
|
||||
if (try decls_val.sliceLen(pt) > 0) {
|
||||
return sema.fail(block, src, "reified opaque must have no decls", .{});
|
||||
}
|
||||
|
||||
const wip_ty = switch (try ip.getOpaqueType(gpa, pt.tid, .{
|
||||
.key = .{ .reified = .{
|
||||
.zir_index = try block.trackZir(inst),
|
||||
} },
|
||||
})) {
|
||||
.existing => |ty| {
|
||||
try sema.addTypeReferenceEntry(src, ty);
|
||||
return Air.internedToRef(ty);
|
||||
},
|
||||
.wip => |wip| wip,
|
||||
};
|
||||
errdefer wip_ty.cancel(ip, pt.tid);
|
||||
|
||||
const type_name = try sema.createTypeName(
|
||||
block,
|
||||
name_strategy,
|
||||
"opaque",
|
||||
inst,
|
||||
wip_ty.index,
|
||||
);
|
||||
wip_ty.setName(ip, type_name.name, type_name.nav);
|
||||
|
||||
const new_namespace_index = try pt.createNamespace(.{
|
||||
.parent = block.namespace.toOptional(),
|
||||
.owner_type = wip_ty.index,
|
||||
.file_scope = block.getFileScopeIndex(zcu),
|
||||
.generation = zcu.generation,
|
||||
});
|
||||
|
||||
try sema.addTypeReferenceEntry(src, wip_ty.index);
|
||||
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
|
||||
return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
|
||||
},
|
||||
.@"union" => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const layout_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "layout", .no_embedded_nulls),
|
||||
).?);
|
||||
const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "tag_type", .no_embedded_nulls),
|
||||
).?);
|
||||
const fields_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "fields", .no_embedded_nulls),
|
||||
).?);
|
||||
const decls_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "decls", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
if (try decls_val.sliceLen(pt) > 0) {
|
||||
return sema.fail(block, src, "reified unions must have no decls", .{});
|
||||
}
|
||||
const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
|
||||
|
||||
const has_tag = tag_type_val.optionalValue(zcu) != null;
|
||||
|
||||
if (has_tag) {
|
||||
switch (layout) {
|
||||
.@"extern" => return sema.fail(block, src, "extern union does not support enum tag type", .{}),
|
||||
.@"packed" => return sema.fail(block, src, "packed union does not support enum tag type", .{}),
|
||||
.auto => {},
|
||||
}
|
||||
}
|
||||
|
||||
const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });
|
||||
|
||||
return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
|
||||
},
|
||||
.@"fn" => {
|
||||
const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
|
||||
const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "calling_convention", .no_embedded_nulls),
|
||||
).?);
|
||||
const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_generic", .no_embedded_nulls),
|
||||
).?);
|
||||
const is_var_args_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_var_args", .no_embedded_nulls),
|
||||
).?);
|
||||
const return_type_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "return_type", .no_embedded_nulls),
|
||||
).?);
|
||||
const params_slice_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "params", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
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();
|
||||
const cc = try sema.analyzeValueAsCallconv(block, src, calling_convention_val);
|
||||
if (is_var_args) {
|
||||
try sema.checkCallConvSupportsVarArgs(block, src, cc);
|
||||
}
|
||||
|
||||
const return_type = return_type_val.optionalValue(zcu) orelse
|
||||
return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
|
||||
|
||||
const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{ .simple = .function_parameters });
|
||||
|
||||
const args_len = try sema.usizeCast(block, src, params_val.typeOf(zcu).arrayLen(zcu));
|
||||
const param_types = try sema.arena.alloc(InternPool.Index, args_len);
|
||||
|
||||
var noalias_bits: u32 = 0;
|
||||
for (param_types, 0..) |*param_type, i| {
|
||||
const elem_val = try params_val.elemValue(pt, i);
|
||||
const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
|
||||
const param_is_generic_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_generic", .no_embedded_nulls),
|
||||
).?);
|
||||
const param_is_noalias_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "is_noalias", .no_embedded_nulls),
|
||||
).?);
|
||||
const opt_param_type_val = try elem_val.fieldValue(pt, elem_struct_type.nameIndex(
|
||||
ip,
|
||||
try ip.getOrPutString(gpa, pt.tid, "type", .no_embedded_nulls),
|
||||
).?);
|
||||
|
||||
if (param_is_generic_val.toBool()) {
|
||||
return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{});
|
||||
}
|
||||
|
||||
const param_type_val = opt_param_type_val.optionalValue(zcu) orelse
|
||||
return sema.fail(block, src, "Type.Fn.Param.type must be non-null for @Type", .{});
|
||||
param_type.* = param_type_val.toIntern();
|
||||
|
||||
if (param_is_noalias_val.toBool()) {
|
||||
if (!Type.fromInterned(param_type.*).isPtrAtRuntime(zcu)) {
|
||||
return sema.fail(block, src, "non-pointer parameter declared noalias", .{});
|
||||
}
|
||||
noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse
|
||||
return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
|
||||
}
|
||||
}
|
||||
|
||||
const ty = try pt.funcType(.{
|
||||
.param_types = param_types,
|
||||
.noalias_bits = noalias_bits,
|
||||
.return_type = return_type.toIntern(),
|
||||
.cc = cc,
|
||||
.is_var_args = is_var_args,
|
||||
});
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
},
|
||||
.frame => return sema.failWithUseOfAsync(block, src),
|
||||
if (try sema.anyUndef(block, field_types_src, field_types_arr)) {
|
||||
return sema.failWithUseOfUndef(block, field_types_src, null);
|
||||
}
|
||||
// We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
|
||||
if (try sema.anyUndef(block, backing_ty_src, backing_int_ty_val)) {
|
||||
return sema.failWithUseOfUndef(block, backing_ty_src, null);
|
||||
}
|
||||
}
|
||||
|
||||
fn reifyEnum(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
inst: Zir.Inst.Index,
|
||||
src: LazySrcLoc,
|
||||
tag_ty: Type,
|
||||
is_exhaustive: bool,
|
||||
fields_val: Value,
|
||||
name_strategy: Zir.Inst.NameStrategy,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = sema.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
// This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.
|
||||
|
||||
const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
|
||||
|
||||
// The validation work here is non-trivial, and it's possible the type already exists.
|
||||
// So in this first pass, let's just construct a hash to optimize for this case. If the
|
||||
// inputs turn out to be invalid, we can cancel the WIP type later.
|
||||
|
||||
var any_comptime_fields = false;
|
||||
var any_default_inits = false;
|
||||
var any_aligned_fields = false;
|
||||
|
||||
// For deduplication purposes, we must create a hash including all details of this type.
|
||||
// TODO: use a longer hash!
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
std.hash.autoHash(&hasher, tag_ty.toIntern());
|
||||
std.hash.autoHash(&hasher, is_exhaustive);
|
||||
std.hash.autoHash(&hasher, fields_len);
|
||||
|
||||
std.hash.autoHash(&hasher, layout);
|
||||
std.hash.autoHash(&hasher, backing_int_ty_val);
|
||||
// The field *type* array has already been deduplicated for us thanks to the InternPool!
|
||||
std.hash.autoHash(&hasher, field_types_arr);
|
||||
// However, for field names and attributes, we need to actually iterate the individual fields,
|
||||
// because the presence of pointers (the `[]const u8` for the name and the `*const anyopaque`
|
||||
// for the default value) means that distinct interned values could ultimately result in the
|
||||
// same struct type.
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
const field_name_val = try field_names_arr.elemValue(pt, field_idx);
|
||||
const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 1));
|
||||
const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .struct_field_names });
|
||||
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .enum_field_name });
|
||||
const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
|
||||
std.builtin.Type.StructField.Attributes,
|
||||
"comptime",
|
||||
).?);
|
||||
const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
|
||||
std.builtin.Type.StructField.Attributes,
|
||||
"align",
|
||||
).?);
|
||||
const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
|
||||
std.builtin.Type.StructField.Attributes,
|
||||
"default_value_ptr",
|
||||
).?);
|
||||
|
||||
const field_default: InternPool.Index = d: {
|
||||
const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none;
|
||||
const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
|
||||
const ptr_ty = try pt.singleConstPtrType(field_ty);
|
||||
const deref_val = try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
|
||||
block,
|
||||
field_attrs_src,
|
||||
.{ .simple = .struct_field_default_value },
|
||||
);
|
||||
// Resolve the value so that lazy values do not create distinct types.
|
||||
break :d (try sema.resolveLazyValue(deref_val)).toIntern();
|
||||
};
|
||||
|
||||
std.hash.autoHash(&hasher, .{
|
||||
field_name,
|
||||
field_value_val.toIntern(),
|
||||
field_attr_comptime,
|
||||
field_attr_align,
|
||||
field_default,
|
||||
});
|
||||
|
||||
if (field_attr_comptime.toBool()) any_comptime_fields = true;
|
||||
if (field_attr_align.optionalValue(zcu)) |_| any_aligned_fields = true;
|
||||
if (field_default != .none) any_default_inits = true;
|
||||
}
|
||||
|
||||
const tracked_inst = try block.trackZir(inst);
|
||||
// Some basic validation to avoid a bogus `getStructType` call...
|
||||
const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: {
|
||||
switch (layout) {
|
||||
.auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}),
|
||||
.@"packed" => {},
|
||||
}
|
||||
break :ty backing.toType();
|
||||
} else null;
|
||||
if (any_aligned_fields and layout == .@"packed") {
|
||||
return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{});
|
||||
}
|
||||
if (any_comptime_fields and layout != .auto) {
|
||||
return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout});
|
||||
}
|
||||
|
||||
const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{
|
||||
.has_values = true,
|
||||
.tag_mode = if (is_exhaustive) .explicit else .nonexhaustive,
|
||||
.fields_len = fields_len,
|
||||
const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
|
||||
.layout = layout,
|
||||
.fields_len = @intCast(fields_len),
|
||||
.known_non_opv = false,
|
||||
.requires_comptime = .unknown,
|
||||
.any_comptime_fields = any_comptime_fields,
|
||||
.any_default_inits = any_default_inits,
|
||||
.any_aligned_fields = any_aligned_fields,
|
||||
.inits_resolved = true,
|
||||
.key = .{ .reified = .{
|
||||
.zir_index = tracked_inst,
|
||||
.type_hash = hasher.final(),
|
||||
@@ -21148,22 +21077,136 @@ fn reifyEnum(
|
||||
return Air.internedToRef(ty);
|
||||
},
|
||||
};
|
||||
var done = false;
|
||||
errdefer if (!done) wip_ty.cancel(ip, pt.tid);
|
||||
|
||||
if (tag_ty.zigTypeTag(zcu) != .int) {
|
||||
return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
|
||||
}
|
||||
errdefer wip_ty.cancel(ip, pt.tid);
|
||||
|
||||
const type_name = try sema.createTypeName(
|
||||
block,
|
||||
name_strategy,
|
||||
"enum",
|
||||
"struct",
|
||||
inst,
|
||||
wip_ty.index,
|
||||
);
|
||||
wip_ty.setName(ip, type_name.name, type_name.nav);
|
||||
|
||||
const wip_struct_type = ip.loadStructType(wip_ty.index);
|
||||
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_name_val = try field_names_arr.elemValue(pt, field_idx);
|
||||
const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
|
||||
|
||||
const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
|
||||
|
||||
// Don't pass a reason; first loop acts as a check that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
|
||||
if (wip_struct_type.addFieldName(ip, field_name)) |prev_index| {
|
||||
_ = prev_index; // TODO: better source location
|
||||
return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
|
||||
}
|
||||
|
||||
const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
|
||||
std.builtin.Type.StructField.Attributes,
|
||||
"comptime",
|
||||
).?);
|
||||
const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
|
||||
std.builtin.Type.StructField.Attributes,
|
||||
"align",
|
||||
).?);
|
||||
const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
|
||||
std.builtin.Type.StructField.Attributes,
|
||||
"default_value_ptr",
|
||||
).?);
|
||||
|
||||
if (field_attr_align.optionalValue(zcu)) |field_align_val| {
|
||||
assert(layout != .@"packed");
|
||||
const bytes = try field_align_val.toUnsignedIntSema(pt);
|
||||
const a = try sema.validateAlign(block, field_attrs_src, bytes);
|
||||
wip_struct_type.field_aligns.get(ip)[field_idx] = a;
|
||||
} else if (any_aligned_fields) {
|
||||
assert(layout != .@"packed");
|
||||
wip_struct_type.field_aligns.get(ip)[field_idx] = .none;
|
||||
}
|
||||
|
||||
const field_default: InternPool.Index = d: {
|
||||
const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none;
|
||||
assert(any_default_inits);
|
||||
const ptr_ty = try pt.singleConstPtrType(field_ty);
|
||||
// The first loop checked that this is comptime-dereferencable.
|
||||
const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?;
|
||||
// ...but we've not checked this yet!
|
||||
if (deref_val.canMutateComptimeVarState(zcu)) {
|
||||
return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
|
||||
}
|
||||
break :d (try sema.resolveLazyValue(deref_val)).toIntern();
|
||||
};
|
||||
|
||||
if (field_attr_comptime.toBool()) {
|
||||
assert(layout == .auto);
|
||||
if (field_default == .none) {
|
||||
return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
|
||||
}
|
||||
wip_struct_type.setFieldComptime(ip, field_idx);
|
||||
}
|
||||
|
||||
wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern();
|
||||
if (field_default != .none) {
|
||||
wip_struct_type.field_inits.get(ip)[field_idx] = field_default;
|
||||
}
|
||||
|
||||
switch (field_ty.zigTypeTag(zcu)) {
|
||||
.@"opaque" => return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
}),
|
||||
.noreturn => return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(field_types_src, "struct fields cannot be 'noreturn'", .{});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
}),
|
||||
else => {},
|
||||
}
|
||||
|
||||
switch (layout) {
|
||||
.auto => {},
|
||||
.@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(field_types_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .struct_field);
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
},
|
||||
.@"packed" => if (!try sema.validatePackedType(field_ty)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (layout == .@"packed") {
|
||||
var fields_bit_sum: u64 = 0;
|
||||
for (0..wip_struct_type.field_types.len) |field_idx| {
|
||||
const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]);
|
||||
try field_ty.resolveLayout(pt);
|
||||
fields_bit_sum += field_ty.bitSize(zcu);
|
||||
}
|
||||
if (backing_int_ty) |ty| {
|
||||
try sema.checkBackingIntType(block, src, ty, fields_bit_sum);
|
||||
wip_struct_type.setBackingIntType(ip, ty.toIntern());
|
||||
} else {
|
||||
const ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
|
||||
wip_struct_type.setBackingIntType(ip, ty.toIntern());
|
||||
}
|
||||
}
|
||||
|
||||
const new_namespace_index = try pt.createNamespace(.{
|
||||
.parent = block.namespace.toOptional(),
|
||||
.owner_type = wip_ty.index,
|
||||
@@ -21171,56 +21214,7 @@ fn reifyEnum(
|
||||
.generation = zcu.generation,
|
||||
});
|
||||
|
||||
try sema.declareDependency(.{ .interned = wip_ty.index });
|
||||
try sema.addTypeReferenceEntry(src, wip_ty.index);
|
||||
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
|
||||
wip_ty.prepare(ip, new_namespace_index);
|
||||
wip_ty.setTagTy(ip, tag_ty.toIntern());
|
||||
done = true;
|
||||
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 1));
|
||||
|
||||
// Don't pass a reason; first loop acts as an assertion that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
|
||||
|
||||
if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
|
||||
// TODO: better source location
|
||||
return sema.fail(block, src, "field '{f}' with enumeration value '{f}' is too large for backing int type '{f}'", .{
|
||||
field_name.fmt(ip),
|
||||
field_value_val.fmtValueSema(pt, sema),
|
||||
tag_ty.fmt(pt),
|
||||
});
|
||||
}
|
||||
|
||||
const coerced_field_val = try pt.getCoerced(field_value_val, tag_ty);
|
||||
if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| {
|
||||
return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
|
||||
.name => msg: {
|
||||
const msg = try sema.errMsg(src, "duplicate enum field '{f}'", .{field_name.fmt(ip)});
|
||||
errdefer msg.destroy(gpa);
|
||||
_ = conflict.prev_field_idx; // TODO: this note is incorrect
|
||||
try sema.errNote(src, msg, "other field here", .{});
|
||||
break :msg msg;
|
||||
},
|
||||
.value => msg: {
|
||||
const msg = try sema.errMsg(src, "enum tag value {f} already taken", .{field_value_val.fmtValueSema(pt, sema)});
|
||||
errdefer msg.destroy(gpa);
|
||||
_ = conflict.prev_field_idx; // TODO: this note is incorrect
|
||||
try sema.errNote(src, msg, "other enum tag value here", .{});
|
||||
break :msg msg;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_exhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {
|
||||
return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
|
||||
}
|
||||
|
||||
try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
|
||||
codegen_type: {
|
||||
if (zcu.comp.config.use_llvm) break :codegen_type;
|
||||
if (block.ownerModule().strip) break :codegen_type;
|
||||
@@ -21228,75 +21222,177 @@ fn reifyEnum(
|
||||
zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
|
||||
try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
|
||||
}
|
||||
return Air.internedToRef(wip_ty.index);
|
||||
try sema.declareDependency(.{ .interned = wip_ty.index });
|
||||
try sema.addTypeReferenceEntry(src, wip_ty.index);
|
||||
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
|
||||
return .fromIntern(wip_ty.finish(ip, new_namespace_index));
|
||||
}
|
||||
|
||||
fn reifyUnion(
|
||||
fn zirReifyUnion(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
inst: Zir.Inst.Index,
|
||||
src: LazySrcLoc,
|
||||
layout: std.builtin.Type.ContainerLayout,
|
||||
opt_tag_type_val: Value,
|
||||
fields_val: Value,
|
||||
name_strategy: Zir.Inst.NameStrategy,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = sema.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
// This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`.
|
||||
const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
|
||||
const extra = sema.code.extraData(Zir.Inst.ReifyUnion, extended.operand).data;
|
||||
const tracked_inst = try block.trackZir(inst);
|
||||
const src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .nodeOffset(.zero),
|
||||
};
|
||||
|
||||
const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
|
||||
const layout_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 0,
|
||||
} },
|
||||
};
|
||||
const arg_ty_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 1,
|
||||
} },
|
||||
};
|
||||
const field_names_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 2,
|
||||
} },
|
||||
};
|
||||
const field_types_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 3,
|
||||
} },
|
||||
};
|
||||
const field_attrs_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 4,
|
||||
} },
|
||||
};
|
||||
|
||||
const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout");
|
||||
const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.UnionField.Attributes");
|
||||
|
||||
const layout_uncoerced = try sema.resolveInst(extra.layout);
|
||||
const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src);
|
||||
const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .union_layout });
|
||||
const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout);
|
||||
|
||||
const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty);
|
||||
const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src);
|
||||
const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, .{ .simple = .type });
|
||||
|
||||
const field_names_uncoerced = try sema.resolveInst(extra.field_names);
|
||||
const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
|
||||
const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .union_field_names });
|
||||
const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .union_field_names });
|
||||
|
||||
const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu));
|
||||
|
||||
const field_types_ty = try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = fields_len,
|
||||
.child = .type_type,
|
||||
}));
|
||||
const field_attrs_ty = try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = fields_len,
|
||||
.child = single_field_attrs_ty.toIntern(),
|
||||
}));
|
||||
|
||||
const field_types_uncoerced = try sema.resolveInst(extra.field_types);
|
||||
const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src);
|
||||
const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .union_field_types });
|
||||
const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .union_field_types });
|
||||
|
||||
const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs);
|
||||
const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src);
|
||||
const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .union_field_attrs });
|
||||
const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .union_field_attrs });
|
||||
|
||||
// Before we begin, check for undefs...
|
||||
if (try sema.anyUndef(block, field_attrs_src, field_attrs_arr)) {
|
||||
return sema.failWithUseOfUndef(block, field_attrs_src, null);
|
||||
}
|
||||
if (try sema.anyUndef(block, field_types_src, field_types_arr)) {
|
||||
return sema.failWithUseOfUndef(block, field_types_src, null);
|
||||
}
|
||||
// We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
|
||||
if (try sema.anyUndef(block, arg_ty_src, arg_ty_val)) {
|
||||
return sema.failWithUseOfUndef(block, arg_ty_src, null);
|
||||
}
|
||||
|
||||
// The validation work here is non-trivial, and it's possible the type already exists.
|
||||
// So in this first pass, let's just construct a hash to optimize for this case. If the
|
||||
// inputs turn out to be invalid, we can cancel the WIP type later.
|
||||
|
||||
var any_aligned_fields = false;
|
||||
|
||||
// For deduplication purposes, we must create a hash including all details of this type.
|
||||
// TODO: use a longer hash!
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
std.hash.autoHash(&hasher, layout);
|
||||
std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());
|
||||
std.hash.autoHash(&hasher, fields_len);
|
||||
|
||||
std.hash.autoHash(&hasher, arg_ty_val);
|
||||
// `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool!
|
||||
std.hash.autoHash(&hasher, field_types_arr);
|
||||
std.hash.autoHash(&hasher, field_attrs_arr);
|
||||
// However, for field names, we need to iterate the individual fields, because the pointers (the
|
||||
// names are slices) mean that distinct values could ultimately result in the same union type.
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
const field_name_val = try field_names_arr.elemValue(pt, field_idx);
|
||||
const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .union_field_names });
|
||||
std.hash.autoHash(&hasher, field_name);
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_type_val = try field_info.fieldValue(pt, 1);
|
||||
const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 2));
|
||||
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .union_field_name });
|
||||
std.hash.autoHash(&hasher, .{
|
||||
field_name,
|
||||
field_type_val.toIntern(),
|
||||
field_align_val.toIntern(),
|
||||
});
|
||||
const field_attrs = try sema.interpretBuiltinType(
|
||||
block,
|
||||
field_attrs_src,
|
||||
try field_attrs_arr.elemValue(pt, field_idx),
|
||||
std.builtin.Type.UnionField.Attributes,
|
||||
);
|
||||
if (field_attrs.@"align" != null) {
|
||||
any_aligned_fields = true;
|
||||
}
|
||||
}
|
||||
|
||||
const tracked_inst = try block.trackZir(inst);
|
||||
// Some basic validation to avoid a bogus `getUnionType` call...
|
||||
const explicit_tag_ty: ?Type = if (arg_ty_val.optionalValue(zcu)) |arg_ty| ty: {
|
||||
switch (layout) {
|
||||
.@"extern", .@"packed" => return sema.fail(block, arg_ty_src, "{t} union does not support enum tag type", .{layout}),
|
||||
.auto => {},
|
||||
}
|
||||
break :ty arg_ty.toType();
|
||||
} else null;
|
||||
if (any_aligned_fields and layout == .@"packed") {
|
||||
return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
|
||||
}
|
||||
|
||||
const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, .{
|
||||
.flags = .{
|
||||
.layout = layout,
|
||||
.status = .none,
|
||||
.runtime_tag = if (opt_tag_type_val.optionalValue(zcu) != null)
|
||||
.tagged
|
||||
else if (layout != .auto)
|
||||
.none
|
||||
else switch (block.wantSafeTypes()) {
|
||||
true => .safety,
|
||||
false => .none,
|
||||
.runtime_tag = rt: {
|
||||
if (explicit_tag_ty != null) break :rt .tagged;
|
||||
if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
|
||||
break :rt .none;
|
||||
},
|
||||
.any_aligned_fields = layout != .@"packed",
|
||||
.any_aligned_fields = any_aligned_fields,
|
||||
.requires_comptime = .unknown,
|
||||
.assumed_runtime_bits = false,
|
||||
.assumed_pointer_aligned = false,
|
||||
.alignment = .none,
|
||||
},
|
||||
.fields_len = fields_len,
|
||||
.fields_len = @intCast(fields_len),
|
||||
.enum_tag_ty = .none, // set later because not yet validated
|
||||
.field_types = &.{}, // set later
|
||||
.field_aligns = &.{}, // set later
|
||||
@@ -21325,128 +21421,117 @@ fn reifyUnion(
|
||||
|
||||
const loaded_union = ip.loadUnionType(wip_ty.index);
|
||||
|
||||
const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(zcu)) |tag_type_val| tag_ty: {
|
||||
switch (ip.indexToKey(tag_type_val.toIntern())) {
|
||||
.enum_type => {},
|
||||
else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
|
||||
const enum_tag_ty, const has_explicit_tag = if (explicit_tag_ty) |enum_tag_ty| tag: {
|
||||
if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") {
|
||||
return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{});
|
||||
}
|
||||
const enum_tag_ty = tag_type_val.toType();
|
||||
|
||||
// We simply track which fields of the tag type have been seen.
|
||||
const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu);
|
||||
var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
|
||||
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
const field_name_val = try field_names_arr.elemValue(pt, field_idx);
|
||||
// Don't pass a reason; first loop acts as a check that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_type_val = try field_info.fieldValue(pt, 1);
|
||||
const field_alignment_val = try field_info.fieldValue(pt, 2);
|
||||
|
||||
// Don't pass a reason; first loop acts as an assertion that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
|
||||
|
||||
const enum_index = enum_tag_ty.enumFieldIndex(field_name, zcu) orelse {
|
||||
// TODO: better source location
|
||||
return sema.fail(block, src, "no field named '{f}' in enum '{f}'", .{
|
||||
if (field_idx >= tag_ty_fields_len) {
|
||||
return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{
|
||||
field_name.fmt(ip), enum_tag_ty.fmt(pt),
|
||||
});
|
||||
};
|
||||
if (seen_tags.isSet(enum_index)) {
|
||||
// TODO: better source location
|
||||
return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
|
||||
}
|
||||
seen_tags.set(enum_index);
|
||||
|
||||
loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
|
||||
const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
|
||||
if (layout == .@"packed") {
|
||||
if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
|
||||
} else {
|
||||
loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
|
||||
const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu);
|
||||
if (enum_field_name != field_name) {
|
||||
return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{
|
||||
field_name.fmt(ip), enum_field_name.fmt(ip),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "enum fields missing in union", .{});
|
||||
const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{
|
||||
tag_ty_fields_len - fields_len,
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
var it = seen_tags.iterator(.{ .kind = .unset });
|
||||
while (it.next()) |enum_index| {
|
||||
const field_name = enum_tag_ty.enumFieldName(enum_index, zcu);
|
||||
try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{f}' missing, declared here", .{
|
||||
field_name.fmt(ip),
|
||||
for (fields_len..tag_ty_fields_len) |enum_field_idx| {
|
||||
try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{
|
||||
enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip),
|
||||
});
|
||||
}
|
||||
try sema.addDeclaredHereNote(msg, enum_tag_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
|
||||
break :tag_ty .{ enum_tag_ty.toIntern(), true };
|
||||
} else tag_ty: {
|
||||
break :tag .{ enum_tag_ty.toIntern(), true };
|
||||
} else tag: {
|
||||
// We must track field names and set up the tag type ourselves.
|
||||
var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
|
||||
try field_names.ensureTotalCapacity(sema.arena, fields_len);
|
||||
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_type_val = try field_info.fieldValue(pt, 1);
|
||||
const field_alignment_val = try field_info.fieldValue(pt, 2);
|
||||
|
||||
// Don't pass a reason; first loop acts as an assertion that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
|
||||
const field_name_val = try field_names_arr.elemValue(pt, field_idx);
|
||||
// Don't pass a reason; first loop acts as a check that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
|
||||
const gop = field_names.getOrPutAssumeCapacity(field_name);
|
||||
if (gop.found_existing) {
|
||||
// TODO: better source location
|
||||
return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
|
||||
}
|
||||
|
||||
loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
|
||||
const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
|
||||
if (layout == .@"packed") {
|
||||
if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
|
||||
} else {
|
||||
loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
|
||||
return sema.fail(block, field_names_src, "duplicate union field {f}", .{field_name.fmt(ip)});
|
||||
}
|
||||
}
|
||||
|
||||
const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name.name);
|
||||
break :tag_ty .{ enum_tag_ty, false };
|
||||
break :tag .{ enum_tag_ty, false };
|
||||
};
|
||||
errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error
|
||||
|
||||
for (loaded_union.field_types.get(ip)) |field_ty_ip| {
|
||||
const field_ty: Type = .fromInterned(field_ty_ip);
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
|
||||
const field_attrs = try sema.interpretBuiltinType(
|
||||
block,
|
||||
field_attrs_src,
|
||||
try field_attrs_arr.elemValue(pt, field_idx),
|
||||
std.builtin.Type.UnionField.Attributes,
|
||||
);
|
||||
|
||||
if (field_ty.zigTypeTag(zcu) == .@"opaque") {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
|
||||
const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
if (layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .union_field);
|
||||
switch (layout) {
|
||||
.auto => {},
|
||||
.@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(field_types_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
} else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .union_field);
|
||||
|
||||
try sema.explainWhyTypeIsNotPacked(msg, src, field_ty);
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
},
|
||||
.@"packed" => if (!try sema.validatePackedType(field_ty)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
loaded_union.field_types.get(ip)[field_idx] = field_ty.toIntern();
|
||||
if (field_attrs.@"align") |bytes| {
|
||||
assert(layout != .@"packed");
|
||||
const a = try sema.validateAlign(block, field_attrs_src, bytes);
|
||||
loaded_union.field_aligns.get(ip)[field_idx] = a;
|
||||
} else if (any_aligned_fields) {
|
||||
assert(layout != .@"packed");
|
||||
loaded_union.field_aligns.get(ip)[field_idx] = .none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21471,116 +21556,94 @@ fn reifyUnion(
|
||||
try sema.declareDependency(.{ .interned = wip_ty.index });
|
||||
try sema.addTypeReferenceEntry(src, wip_ty.index);
|
||||
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
|
||||
return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
|
||||
return .fromIntern(wip_ty.finish(ip, new_namespace_index));
|
||||
}
|
||||
|
||||
fn reifyTuple(
|
||||
fn zirReifyEnum(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
fields_val: Value,
|
||||
extended: Zir.Inst.Extended.InstData,
|
||||
inst: Zir.Inst.Index,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = sema.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
|
||||
const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
|
||||
const extra = sema.code.extraData(Zir.Inst.ReifyEnum, extended.operand).data;
|
||||
const tracked_inst = try block.trackZir(inst);
|
||||
const src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .nodeOffset(.zero),
|
||||
};
|
||||
|
||||
const types = try sema.arena.alloc(InternPool.Index, fields_len);
|
||||
const inits = try sema.arena.alloc(InternPool.Index, fields_len);
|
||||
const tag_ty_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 0,
|
||||
} },
|
||||
};
|
||||
const mode_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 1,
|
||||
} },
|
||||
};
|
||||
const field_names_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 2,
|
||||
} },
|
||||
};
|
||||
const field_values_src: LazySrcLoc = .{
|
||||
.base_node_inst = tracked_inst,
|
||||
.offset = .{ .node_offset_builtin_call_arg = .{
|
||||
.builtin_call_node = .zero,
|
||||
.arg_index = 3,
|
||||
} },
|
||||
};
|
||||
|
||||
for (types, inits, 0..) |*field_ty, *field_init, field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode");
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_type_val = try field_info.fieldValue(pt, 1);
|
||||
const field_default_value_val = try field_info.fieldValue(pt, 2);
|
||||
const field_is_comptime_val = try field_info.fieldValue(pt, 3);
|
||||
const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4));
|
||||
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .tuple_field_name });
|
||||
const field_type = field_type_val.toType();
|
||||
const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: {
|
||||
const ptr_ty = try pt.singleConstPtrType(field_type_val.toType());
|
||||
// We need to do this deref here, so we won't check for this error case later on.
|
||||
const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
|
||||
block,
|
||||
src,
|
||||
.{ .simple = .tuple_field_default_value },
|
||||
);
|
||||
if (val.canMutateComptimeVarState(zcu)) {
|
||||
return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val);
|
||||
}
|
||||
// Resolve the value so that lazy values do not create distinct types.
|
||||
break :d (try sema.resolveLazyValue(val)).toIntern();
|
||||
} else .none;
|
||||
|
||||
const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
|
||||
block,
|
||||
src,
|
||||
"tuple cannot have non-numeric field '{f}'",
|
||||
.{field_name.fmt(ip)},
|
||||
);
|
||||
if (field_name_index != field_idx) {
|
||||
return sema.fail(
|
||||
block,
|
||||
src,
|
||||
"tuple field name '{d}' does not match field index {d}",
|
||||
.{ field_name_index, field_idx },
|
||||
);
|
||||
}
|
||||
|
||||
try sema.validateTupleFieldType(block, field_type, src);
|
||||
|
||||
{
|
||||
const alignment_ok = ok: {
|
||||
if (field_alignment_val.toIntern() == .zero) break :ok true;
|
||||
const given_align = try field_alignment_val.getUnsignedIntSema(pt) orelse break :ok false;
|
||||
const abi_align = (try field_type.abiAlignmentSema(pt)).toByteUnits() orelse 0;
|
||||
break :ok abi_align == given_align;
|
||||
};
|
||||
if (!alignment_ok) {
|
||||
return sema.fail(block, src, "tuple fields cannot specify alignment", .{});
|
||||
}
|
||||
}
|
||||
|
||||
if (field_is_comptime_val.toBool() and field_default_value == .none) {
|
||||
return sema.fail(block, src, "comptime field without default initialization value", .{});
|
||||
}
|
||||
|
||||
if (!field_is_comptime_val.toBool() and field_default_value != .none) {
|
||||
return sema.fail(block, src, "non-comptime tuple fields cannot specify default initialization value", .{});
|
||||
}
|
||||
|
||||
field_ty.* = field_type.toIntern();
|
||||
field_init.* = field_default_value;
|
||||
const tag_ty = try sema.resolveType(block, tag_ty_src, extra.tag_ty);
|
||||
if (tag_ty.zigTypeTag(zcu) != .int) {
|
||||
return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{});
|
||||
}
|
||||
|
||||
return Air.internedToRef(try zcu.intern_pool.getTupleType(gpa, pt.tid, .{
|
||||
.types = types,
|
||||
.values = inits,
|
||||
const mode_uncoerced = try sema.resolveInst(extra.mode);
|
||||
const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src);
|
||||
const mode_val = try sema.resolveConstDefinedValue(block, mode_src, mode_coerced, .{ .simple = .type });
|
||||
const nonexhaustive = switch (try sema.interpretBuiltinType(block, mode_src, mode_val, std.builtin.Type.Enum.Mode)) {
|
||||
.exhaustive => false,
|
||||
.nonexhaustive => true,
|
||||
};
|
||||
|
||||
const field_names_uncoerced = try sema.resolveInst(extra.field_names);
|
||||
const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
|
||||
const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .enum_field_names });
|
||||
const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .enum_field_names });
|
||||
|
||||
const fields_len = try sema.usizeCast(block, src, field_names_arr.typeOf(zcu).arrayLen(zcu));
|
||||
|
||||
const field_values_ty = try pt.singleConstPtrType(try pt.arrayType(.{
|
||||
.len = fields_len,
|
||||
.child = tag_ty.toIntern(),
|
||||
}));
|
||||
}
|
||||
|
||||
fn reifyStruct(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
inst: Zir.Inst.Index,
|
||||
src: LazySrcLoc,
|
||||
layout: std.builtin.Type.ContainerLayout,
|
||||
opt_backing_int_val: Value,
|
||||
fields_val: Value,
|
||||
name_strategy: Zir.Inst.NameStrategy,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const gpa = sema.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
const field_values_uncoerced = try sema.resolveInst(extra.field_values);
|
||||
const field_values_coerced = try sema.coerce(block, field_values_ty, field_values_uncoerced, field_values_src);
|
||||
const field_values_slice = try sema.resolveConstDefinedValue(block, field_values_src, field_values_coerced, .{ .simple = .enum_field_values });
|
||||
const field_values_arr = try sema.derefSliceAsArray(block, field_values_src, field_values_slice, .{ .simple = .enum_field_values });
|
||||
|
||||
// This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`.
|
||||
|
||||
const fields_len: u32 = @intCast(fields_val.typeOf(zcu).arrayLen(zcu));
|
||||
// Before we begin, check for undefs...
|
||||
if (try sema.anyUndef(block, field_values_src, field_values_arr)) {
|
||||
return sema.failWithUseOfUndef(block, field_values_src, null);
|
||||
}
|
||||
// We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
|
||||
|
||||
// The validation work here is non-trivial, and it's possible the type already exists.
|
||||
// So in this first pass, let's just construct a hash to optimize for this case. If the
|
||||
@@ -21589,62 +21652,23 @@ fn reifyStruct(
|
||||
// For deduplication purposes, we must create a hash including all details of this type.
|
||||
// TODO: use a longer hash!
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
std.hash.autoHash(&hasher, layout);
|
||||
std.hash.autoHash(&hasher, opt_backing_int_val.toIntern());
|
||||
std.hash.autoHash(&hasher, tag_ty.toIntern());
|
||||
std.hash.autoHash(&hasher, nonexhaustive);
|
||||
std.hash.autoHash(&hasher, fields_len);
|
||||
|
||||
var any_comptime_fields = false;
|
||||
var any_default_inits = false;
|
||||
|
||||
// `field_values_arr` is already deduplicated by the InternPool!
|
||||
std.hash.autoHash(&hasher, field_values_arr);
|
||||
// However, for field names, we need to iterate the individual fields, because the pointers (the
|
||||
// names are slices) mean that distinct values could ultimately result in the same enum type.
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_type_val = try field_info.fieldValue(pt, 1);
|
||||
const field_default_value_val = try field_info.fieldValue(pt, 2);
|
||||
const field_is_comptime_val = try field_info.fieldValue(pt, 3);
|
||||
const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 4));
|
||||
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .struct_field_name });
|
||||
const field_is_comptime = field_is_comptime_val.toBool();
|
||||
const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(zcu)) |ptr_val| d: {
|
||||
const ptr_ty = try pt.singleConstPtrType(field_type_val.toType());
|
||||
// We need to do this deref here, so we won't check for this error case later on.
|
||||
const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
|
||||
block,
|
||||
src,
|
||||
.{ .simple = .struct_field_default_value },
|
||||
);
|
||||
if (val.canMutateComptimeVarState(zcu)) {
|
||||
return sema.failWithContainsReferenceToComptimeVar(block, src, field_name, "field default value", val);
|
||||
}
|
||||
// Resolve the value so that lazy values do not create distinct types.
|
||||
break :d (try sema.resolveLazyValue(val)).toIntern();
|
||||
} else .none;
|
||||
|
||||
std.hash.autoHash(&hasher, .{
|
||||
field_name,
|
||||
field_type_val.toIntern(),
|
||||
field_default_value,
|
||||
field_is_comptime,
|
||||
field_alignment_val.toIntern(),
|
||||
});
|
||||
|
||||
if (field_is_comptime) any_comptime_fields = true;
|
||||
if (field_default_value != .none) any_default_inits = true;
|
||||
const field_name_val = try field_names_arr.elemValue(pt, field_idx);
|
||||
const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, .{ .simple = .enum_field_names });
|
||||
std.hash.autoHash(&hasher, field_name);
|
||||
}
|
||||
|
||||
const tracked_inst = try block.trackZir(inst);
|
||||
|
||||
const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
|
||||
.layout = layout,
|
||||
.fields_len = fields_len,
|
||||
.known_non_opv = false,
|
||||
.requires_comptime = .unknown,
|
||||
.any_comptime_fields = any_comptime_fields,
|
||||
.any_default_inits = any_default_inits,
|
||||
.any_aligned_fields = layout != .@"packed",
|
||||
.inits_resolved = true,
|
||||
const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, .{
|
||||
.has_values = true,
|
||||
.tag_mode = if (nonexhaustive) .nonexhaustive else .explicit,
|
||||
.fields_len = @intCast(fields_len),
|
||||
.key = .{ .reified = .{
|
||||
.zir_index = tracked_inst,
|
||||
.type_hash = hasher.final(),
|
||||
@@ -21654,144 +21678,21 @@ fn reifyStruct(
|
||||
.existing => |ty| {
|
||||
try sema.declareDependency(.{ .interned = ty });
|
||||
try sema.addTypeReferenceEntry(src, ty);
|
||||
return Air.internedToRef(ty);
|
||||
return .fromIntern(ty);
|
||||
},
|
||||
};
|
||||
errdefer wip_ty.cancel(ip, pt.tid);
|
||||
var done = false;
|
||||
errdefer if (!done) wip_ty.cancel(ip, pt.tid);
|
||||
|
||||
const type_name = try sema.createTypeName(
|
||||
block,
|
||||
name_strategy,
|
||||
"struct",
|
||||
"enum",
|
||||
inst,
|
||||
wip_ty.index,
|
||||
);
|
||||
wip_ty.setName(ip, type_name.name, type_name.nav);
|
||||
|
||||
const struct_type = ip.loadStructType(wip_ty.index);
|
||||
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_info = try fields_val.elemValue(pt, field_idx);
|
||||
|
||||
const field_name_val = try field_info.fieldValue(pt, 0);
|
||||
const field_type_val = try field_info.fieldValue(pt, 1);
|
||||
const field_default_value_val = try field_info.fieldValue(pt, 2);
|
||||
const field_is_comptime_val = try field_info.fieldValue(pt, 3);
|
||||
const field_alignment_val = try field_info.fieldValue(pt, 4);
|
||||
|
||||
const field_ty = field_type_val.toType();
|
||||
// Don't pass a reason; first loop acts as an assertion that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
|
||||
if (struct_type.addFieldName(ip, field_name)) |prev_index| {
|
||||
_ = prev_index; // TODO: better source location
|
||||
return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
|
||||
}
|
||||
|
||||
if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) {
|
||||
return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
|
||||
}
|
||||
const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
|
||||
if (layout == .@"packed") {
|
||||
if (byte_align != 0) return sema.fail(block, src, "alignment of a packed struct field must be set to 0", .{});
|
||||
} else {
|
||||
struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
|
||||
}
|
||||
|
||||
const field_is_comptime = field_is_comptime_val.toBool();
|
||||
if (field_is_comptime) {
|
||||
assert(any_comptime_fields);
|
||||
switch (layout) {
|
||||
.@"extern" => return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}),
|
||||
.@"packed" => return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}),
|
||||
.auto => struct_type.setFieldComptime(ip, field_idx),
|
||||
}
|
||||
}
|
||||
|
||||
const field_default: InternPool.Index = d: {
|
||||
if (!any_default_inits) break :d .none;
|
||||
const ptr_val = field_default_value_val.optionalValue(zcu) orelse break :d .none;
|
||||
const ptr_ty = try pt.singleConstPtrType(field_ty);
|
||||
// Asserted comptime-dereferencable above.
|
||||
const val = (try sema.pointerDeref(block, src, ptr_val, ptr_ty)).?;
|
||||
// We already resolved this for deduplication, so we may as well do it now.
|
||||
break :d (try sema.resolveLazyValue(val)).toIntern();
|
||||
};
|
||||
|
||||
if (field_is_comptime and field_default == .none) {
|
||||
return sema.fail(block, src, "comptime field without default initialization value", .{});
|
||||
}
|
||||
|
||||
struct_type.field_types.get(ip)[field_idx] = field_type_val.toIntern();
|
||||
if (field_default != .none) {
|
||||
struct_type.field_inits.get(ip)[field_idx] = field_default;
|
||||
}
|
||||
|
||||
if (field_ty.zigTypeTag(zcu) == .@"opaque") {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
if (field_ty.zigTypeTag(zcu) == .noreturn) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "struct fields cannot be 'noreturn'", .{});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
if (layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .struct_field);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
} else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
try sema.explainWhyTypeIsNotPacked(msg, src, field_ty);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, field_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (layout == .@"packed") {
|
||||
var fields_bit_sum: u64 = 0;
|
||||
for (0..struct_type.field_types.len) |field_idx| {
|
||||
const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_idx]);
|
||||
field_ty.resolveLayout(pt) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
const msg = sema.err orelse return err;
|
||||
try sema.errNote(src, msg, "while checking a field of this struct", .{});
|
||||
return err;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
fields_bit_sum += field_ty.bitSize(zcu);
|
||||
}
|
||||
|
||||
if (opt_backing_int_val.optionalValue(zcu)) |backing_int_val| {
|
||||
const backing_int_ty = backing_int_val.toType();
|
||||
try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
|
||||
struct_type.setBackingIntType(ip, backing_int_ty.toIntern());
|
||||
} else {
|
||||
const backing_int_ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
|
||||
struct_type.setBackingIntType(ip, backing_int_ty.toIntern());
|
||||
}
|
||||
}
|
||||
|
||||
const new_namespace_index = try pt.createNamespace(.{
|
||||
.parent = block.namespace.toOptional(),
|
||||
.owner_type = wip_ty.index,
|
||||
@@ -21799,7 +21700,44 @@ fn reifyStruct(
|
||||
.generation = zcu.generation,
|
||||
});
|
||||
|
||||
try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
|
||||
try sema.declareDependency(.{ .interned = wip_ty.index });
|
||||
try sema.addTypeReferenceEntry(src, wip_ty.index);
|
||||
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
|
||||
wip_ty.prepare(ip, new_namespace_index);
|
||||
wip_ty.setTagTy(ip, tag_ty.toIntern());
|
||||
done = true;
|
||||
|
||||
for (0..fields_len) |field_idx| {
|
||||
const field_name_val = try field_names_arr.elemValue(pt, field_idx);
|
||||
// Don't pass a reason; first loop acts as a check that this is valid.
|
||||
const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
|
||||
|
||||
const field_val = try field_values_arr.elemValue(pt, field_idx);
|
||||
|
||||
if (wip_ty.nextField(ip, field_name, field_val.toIntern())) |conflict| {
|
||||
return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
|
||||
.name => msg: {
|
||||
const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}'", .{field_name.fmt(ip)});
|
||||
errdefer msg.destroy(gpa);
|
||||
_ = conflict.prev_field_idx; // TODO: this note is incorrect
|
||||
try sema.errNote(field_names_src, msg, "other field here", .{});
|
||||
break :msg msg;
|
||||
},
|
||||
.value => msg: {
|
||||
const msg = try sema.errMsg(field_values_src, "enum tag value {f} already taken", .{field_val.fmtValueSema(pt, sema)});
|
||||
errdefer msg.destroy(gpa);
|
||||
_ = conflict.prev_field_idx; // TODO: this note is incorrect
|
||||
try sema.errNote(field_values_src, msg, "other enum tag value here", .{});
|
||||
break :msg msg;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {
|
||||
return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
|
||||
}
|
||||
|
||||
codegen_type: {
|
||||
if (zcu.comp.config.use_llvm) break :codegen_type;
|
||||
if (block.ownerModule().strip) break :codegen_type;
|
||||
@@ -21807,10 +21745,7 @@ fn reifyStruct(
|
||||
zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
|
||||
try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
|
||||
}
|
||||
try sema.declareDependency(.{ .interned = wip_ty.index });
|
||||
try sema.addTypeReferenceEntry(src, wip_ty.index);
|
||||
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
|
||||
return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
|
||||
return Air.internedToRef(wip_ty.index);
|
||||
}
|
||||
|
||||
fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
|
||||
@@ -23969,7 +23904,7 @@ fn analyzeShuffle(
|
||||
const b_src = block.builtinCallArgSrc(src_node, 2);
|
||||
const mask_src = block.builtinCallArgSrc(src_node, 3);
|
||||
|
||||
// If the type of `a` is `@Type(.undefined)`, i.e. the argument is untyped,
|
||||
// If the type of `a` is `@TypeOf(undefined)`, i.e. the argument is untyped,
|
||||
// this is 0, because it is an error to index into this vector.
|
||||
const a_len: u32 = switch (sema.typeOf(a_uncoerced).zigTypeTag(zcu)) {
|
||||
.array, .vector => @intCast(sema.typeOf(a_uncoerced).arrayLen(zcu)),
|
||||
@@ -23981,7 +23916,7 @@ fn analyzeShuffle(
|
||||
const a_ty = try pt.vectorType(.{ .len = a_len, .child = elem_ty.toIntern() });
|
||||
const a_coerced = try sema.coerce(block, a_ty, a_uncoerced, a_src);
|
||||
|
||||
// If the type of `b` is `@Type(.undefined)`, i.e. the argument is untyped, this is 0, because it is an error to index into this vector.
|
||||
// If the type of `b` is `@TypeOf(undefined)`, i.e. the argument is untyped, this is 0, because it is an error to index into this vector.
|
||||
const b_len: u32 = switch (sema.typeOf(b_uncoerced).zigTypeTag(zcu)) {
|
||||
.array, .vector => @intCast(sema.typeOf(b_uncoerced).arrayLen(zcu)),
|
||||
.undefined => 0,
|
||||
@@ -25541,7 +25476,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
extra_index += body.len;
|
||||
if (extra.data.bits.ret_ty_is_generic) break :blk .generic_poison;
|
||||
|
||||
const val = try sema.resolveGenericBody(block, ret_src, body, inst, .type, .{ .simple = .function_ret_ty });
|
||||
const val = try sema.resolveGenericBody(block, ret_src, body, inst, .type, .{ .simple = .fn_ret_ty });
|
||||
const ty = val.toType();
|
||||
break :blk ty;
|
||||
} else if (extra.data.bits.has_ret_ty_ref) blk: {
|
||||
@@ -25968,21 +25903,26 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
|
||||
const src = block.nodeOffset(src_node);
|
||||
const value: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
|
||||
|
||||
const ty = switch (value) {
|
||||
const builtin_type: Zcu.BuiltinDecl = switch (value) {
|
||||
// zig fmt: off
|
||||
.atomic_order => try sema.getBuiltinType(src, .AtomicOrder),
|
||||
.atomic_rmw_op => try sema.getBuiltinType(src, .AtomicRmwOp),
|
||||
.calling_convention => try sema.getBuiltinType(src, .CallingConvention),
|
||||
.address_space => try sema.getBuiltinType(src, .AddressSpace),
|
||||
.float_mode => try sema.getBuiltinType(src, .FloatMode),
|
||||
.reduce_op => try sema.getBuiltinType(src, .ReduceOp),
|
||||
.call_modifier => try sema.getBuiltinType(src, .CallModifier),
|
||||
.prefetch_options => try sema.getBuiltinType(src, .PrefetchOptions),
|
||||
.export_options => try sema.getBuiltinType(src, .ExportOptions),
|
||||
.extern_options => try sema.getBuiltinType(src, .ExternOptions),
|
||||
.type_info => try sema.getBuiltinType(src, .Type),
|
||||
.branch_hint => try sema.getBuiltinType(src, .BranchHint),
|
||||
.clobbers => try sema.getBuiltinType(src, .@"assembly.Clobbers"),
|
||||
.atomic_order => .AtomicOrder,
|
||||
.atomic_rmw_op => .AtomicRmwOp,
|
||||
.calling_convention => .CallingConvention,
|
||||
.address_space => .AddressSpace,
|
||||
.float_mode => .FloatMode,
|
||||
.signedness => .Signedness,
|
||||
.reduce_op => .ReduceOp,
|
||||
.call_modifier => .CallModifier,
|
||||
.prefetch_options => .PrefetchOptions,
|
||||
.export_options => .ExportOptions,
|
||||
.extern_options => .ExternOptions,
|
||||
.branch_hint => .BranchHint,
|
||||
.clobbers => .@"assembly.Clobbers",
|
||||
.pointer_size => .@"Type.Pointer.Size",
|
||||
.pointer_attributes => .@"Type.Pointer.Attributes",
|
||||
.fn_attributes, => .@"Type.Fn.Attributes",
|
||||
.container_layout => .@"Type.ContainerLayout",
|
||||
.enum_mode => .@"Type.Enum.Mode",
|
||||
// zig fmt: on
|
||||
|
||||
// Values are handled here.
|
||||
@@ -26009,7 +25949,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
|
||||
return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
|
||||
},
|
||||
};
|
||||
return Air.internedToRef(ty.toIntern());
|
||||
return .fromType(try sema.getBuiltinType(src, builtin_type));
|
||||
}
|
||||
|
||||
fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
|
||||
@@ -35259,7 +35199,7 @@ fn structFields(
|
||||
.base_node_inst = struct_type.zir_index,
|
||||
.offset = .nodeOffset(.zero),
|
||||
},
|
||||
.r = .{ .simple = .struct_fields },
|
||||
.r = .{ .simple = .type },
|
||||
} },
|
||||
.src_base_inst = struct_type.zir_index,
|
||||
.type_name_ctx = struct_type.name,
|
||||
@@ -35614,7 +35554,7 @@ fn unionFields(
|
||||
.inlining = null,
|
||||
.comptime_reason = .{ .reason = .{
|
||||
.src = src,
|
||||
.r = .{ .simple = .union_fields },
|
||||
.r = .{ .simple = .type },
|
||||
} },
|
||||
.src_base_inst = union_type.zir_index,
|
||||
.type_name_ctx = union_type.name,
|
||||
@@ -36077,8 +36017,13 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
.manyptr_u8_type,
|
||||
.manyptr_const_u8_type,
|
||||
.manyptr_const_u8_sentinel_0_type,
|
||||
.manyptr_const_slice_const_u8_type,
|
||||
.slice_const_u8_type,
|
||||
.slice_const_u8_sentinel_0_type,
|
||||
.slice_const_slice_const_u8_type,
|
||||
.optional_type_type,
|
||||
.manyptr_const_type_type,
|
||||
.slice_const_type_type,
|
||||
.vector_8_i8_type,
|
||||
.vector_16_i8_type,
|
||||
.vector_32_i8_type,
|
||||
@@ -37230,7 +37175,7 @@ fn sliceToIpString(
|
||||
|
||||
/// Given a slice value, attempts to dereference it into a comptime-known array.
|
||||
/// Emits a compile error if the contents of the slice are not comptime-known.
|
||||
/// Asserts that `slice_val` is a slice.
|
||||
/// Asserts that `slice_val` is a slice or a pointer to an array.
|
||||
fn derefSliceAsArray(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
@@ -37247,7 +37192,7 @@ fn derefSliceAsArray(
|
||||
|
||||
/// Given a slice value, attempts to dereference it into a comptime-known array.
|
||||
/// Returns `null` if the contents of the slice are not comptime-known.
|
||||
/// Asserts that `slice_val` is a slice.
|
||||
/// Asserts that `slice_val` is a slice or a pointer to an array.
|
||||
fn maybeDerefSliceAsArray(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
@@ -37257,7 +37202,13 @@ fn maybeDerefSliceAsArray(
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
assert(slice_val.typeOf(zcu).isSlice(zcu));
|
||||
const slice_ty = slice_val.typeOf(zcu);
|
||||
assert(slice_ty.zigTypeTag(zcu) == .pointer);
|
||||
switch (slice_ty.ptrInfo(zcu).flags.size) {
|
||||
.slice => {},
|
||||
.one => return sema.pointerDeref(block, src, slice_val, slice_ty),
|
||||
.many, .c => unreachable,
|
||||
}
|
||||
const slice = switch (ip.indexToKey(slice_val.toIntern())) {
|
||||
.undef => return sema.failWithUseOfUndef(block, src, null),
|
||||
.slice => |slice| slice,
|
||||
@@ -37393,7 +37344,7 @@ pub fn resolveDeclaredEnum(
|
||||
.inlining = null,
|
||||
.comptime_reason = .{ .reason = .{
|
||||
.src = src,
|
||||
.r = .{ .simple = .enum_fields },
|
||||
.r = .{ .simple = .enum_field_values },
|
||||
} },
|
||||
.src_base_inst = tracked_inst,
|
||||
.type_name_ctx = type_name,
|
||||
|
||||
+8
-2
@@ -317,7 +317,7 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
|
||||
.undefined,
|
||||
=> try writer.print("@TypeOf({s})", .{@tagName(s)}),
|
||||
|
||||
.enum_literal => try writer.writeAll("@Type(.enum_literal)"),
|
||||
.enum_literal => try writer.writeAll("@EnumLiteral()"),
|
||||
|
||||
.generic_poison => unreachable,
|
||||
},
|
||||
@@ -3509,7 +3509,9 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
|
||||
.union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,
|
||||
.enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,
|
||||
.opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,
|
||||
.reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.src_line,
|
||||
.reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.src_line,
|
||||
.reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.src_line,
|
||||
.reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.src_line,
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
@@ -4280,6 +4282,10 @@ pub const manyptr_const_u8: Type = .{ .ip_index = .manyptr_const_u8_type };
|
||||
pub const manyptr_const_u8_sentinel_0: Type = .{ .ip_index = .manyptr_const_u8_sentinel_0_type };
|
||||
pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type };
|
||||
pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type };
|
||||
pub const slice_const_slice_const_u8: Type = .{ .ip_index = .slice_const_slice_const_u8_type };
|
||||
pub const slice_const_type: Type = .{ .ip_index = .slice_const_type_type };
|
||||
pub const optional_type: Type = .{ .ip_index = .optional_type_type };
|
||||
pub const optional_noreturn: Type = .{ .ip_index = .optional_noreturn_type };
|
||||
|
||||
pub const vector_8_i8: Type = .{ .ip_index = .vector_8_i8_type };
|
||||
pub const vector_16_i8: Type = .{ .ip_index = .vector_16_i8_type };
|
||||
|
||||
@@ -2824,6 +2824,29 @@ pub fn resolveLazy(
|
||||
.val = resolved_val,
|
||||
}));
|
||||
},
|
||||
.error_union => |eu| switch (eu.val) {
|
||||
.err_name => return val,
|
||||
.payload => |payload| {
|
||||
const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
|
||||
if (resolved_payload.toIntern() == payload) return val;
|
||||
return .fromInterned(try pt.intern(.{ .error_union = .{
|
||||
.ty = eu.ty,
|
||||
.val = .{ .payload = resolved_payload.toIntern() },
|
||||
} }));
|
||||
},
|
||||
},
|
||||
.opt => |opt| switch (opt.val) {
|
||||
.none => return val,
|
||||
else => |payload| {
|
||||
const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
|
||||
if (resolved_payload.toIntern() == payload) return val;
|
||||
return .fromInterned(try pt.intern(.{ .opt = .{
|
||||
.ty = opt.ty,
|
||||
.val = resolved_payload.toIntern(),
|
||||
} }));
|
||||
},
|
||||
},
|
||||
|
||||
else => return val,
|
||||
}
|
||||
}
|
||||
|
||||
+19
-5
@@ -416,10 +416,13 @@ pub const BuiltinDecl = enum {
|
||||
Type,
|
||||
@"Type.Fn",
|
||||
@"Type.Fn.Param",
|
||||
@"Type.Fn.Param.Attributes",
|
||||
@"Type.Fn.Attributes",
|
||||
@"Type.Int",
|
||||
@"Type.Float",
|
||||
@"Type.Pointer",
|
||||
@"Type.Pointer.Size",
|
||||
@"Type.Pointer.Attributes",
|
||||
@"Type.Array",
|
||||
@"Type.Vector",
|
||||
@"Type.Optional",
|
||||
@@ -427,10 +430,13 @@ pub const BuiltinDecl = enum {
|
||||
@"Type.ErrorUnion",
|
||||
@"Type.EnumField",
|
||||
@"Type.Enum",
|
||||
@"Type.Enum.Mode",
|
||||
@"Type.Union",
|
||||
@"Type.UnionField",
|
||||
@"Type.UnionField.Attributes",
|
||||
@"Type.Struct",
|
||||
@"Type.StructField",
|
||||
@"Type.StructField.Attributes",
|
||||
@"Type.ContainerLayout",
|
||||
@"Type.Opaque",
|
||||
@"Type.Declaration",
|
||||
@@ -495,10 +501,13 @@ pub const BuiltinDecl = enum {
|
||||
.Type,
|
||||
.@"Type.Fn",
|
||||
.@"Type.Fn.Param",
|
||||
.@"Type.Fn.Param.Attributes",
|
||||
.@"Type.Fn.Attributes",
|
||||
.@"Type.Int",
|
||||
.@"Type.Float",
|
||||
.@"Type.Pointer",
|
||||
.@"Type.Pointer.Size",
|
||||
.@"Type.Pointer.Attributes",
|
||||
.@"Type.Array",
|
||||
.@"Type.Vector",
|
||||
.@"Type.Optional",
|
||||
@@ -506,10 +515,13 @@ pub const BuiltinDecl = enum {
|
||||
.@"Type.ErrorUnion",
|
||||
.@"Type.EnumField",
|
||||
.@"Type.Enum",
|
||||
.@"Type.Enum.Mode",
|
||||
.@"Type.Union",
|
||||
.@"Type.UnionField",
|
||||
.@"Type.UnionField.Attributes",
|
||||
.@"Type.Struct",
|
||||
.@"Type.StructField",
|
||||
.@"Type.StructField.Attributes",
|
||||
.@"Type.ContainerLayout",
|
||||
.@"Type.Opaque",
|
||||
.@"Type.Declaration",
|
||||
@@ -1745,28 +1757,28 @@ pub const SrcLoc = struct {
|
||||
const node = node_off.toAbsolute(src_loc.base_node);
|
||||
var buf: [1]Ast.Node.Index = undefined;
|
||||
const full = tree.fullFnProto(&buf, node).?;
|
||||
return tree.nodeToSpan(full.ast.align_expr.unwrap().?);
|
||||
return tree.nodeToSpan(full.ast.align_expr.unwrap() orelse node);
|
||||
},
|
||||
.node_offset_fn_type_addrspace => |node_off| {
|
||||
const tree = try src_loc.file_scope.getTree(zcu);
|
||||
const node = node_off.toAbsolute(src_loc.base_node);
|
||||
var buf: [1]Ast.Node.Index = undefined;
|
||||
const full = tree.fullFnProto(&buf, node).?;
|
||||
return tree.nodeToSpan(full.ast.addrspace_expr.unwrap().?);
|
||||
return tree.nodeToSpan(full.ast.addrspace_expr.unwrap() orelse node);
|
||||
},
|
||||
.node_offset_fn_type_section => |node_off| {
|
||||
const tree = try src_loc.file_scope.getTree(zcu);
|
||||
const node = node_off.toAbsolute(src_loc.base_node);
|
||||
var buf: [1]Ast.Node.Index = undefined;
|
||||
const full = tree.fullFnProto(&buf, node).?;
|
||||
return tree.nodeToSpan(full.ast.section_expr.unwrap().?);
|
||||
return tree.nodeToSpan(full.ast.section_expr.unwrap() orelse node);
|
||||
},
|
||||
.node_offset_fn_type_cc => |node_off| {
|
||||
const tree = try src_loc.file_scope.getTree(zcu);
|
||||
const node = node_off.toAbsolute(src_loc.base_node);
|
||||
var buf: [1]Ast.Node.Index = undefined;
|
||||
const full = tree.fullFnProto(&buf, node).?;
|
||||
return tree.nodeToSpan(full.ast.callconv_expr.unwrap().?);
|
||||
return tree.nodeToSpan(full.ast.callconv_expr.unwrap() orelse node);
|
||||
},
|
||||
|
||||
.node_offset_fn_type_ret_ty => |node_off| {
|
||||
@@ -2684,7 +2696,9 @@ pub const LazySrcLoc = struct {
|
||||
.union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node,
|
||||
.enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_node,
|
||||
.opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_node,
|
||||
.reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.node,
|
||||
.reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node,
|
||||
.reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node,
|
||||
.reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node,
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
|
||||
@@ -120,23 +120,13 @@ const matchers = matchers: {
|
||||
);
|
||||
var symbols: Symbols: {
|
||||
const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields;
|
||||
var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;
|
||||
for (&symbol_fields, symbols) |*symbol_field, symbol| {
|
||||
const Storage = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage();
|
||||
symbol_field.* = .{
|
||||
.name = symbol.name,
|
||||
.type = Storage,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(Storage),
|
||||
};
|
||||
var field_names: [symbols.len][]const u8 = undefined;
|
||||
var field_types: [symbols.len]type = undefined;
|
||||
for (symbols, &field_names, &field_types) |symbol, *field_name, *FieldType| {
|
||||
field_name.* = symbol.name;
|
||||
FieldType.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage();
|
||||
}
|
||||
break :Symbols @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &symbol_fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
break :Symbols @Struct(.auto, null, &field_names, &field_types, &@splat(.{}));
|
||||
} = undefined;
|
||||
const Symbol = std.meta.FieldEnum(@TypeOf(instruction.symbols));
|
||||
comptime var unused_symbols: std.enums.EnumSet(Symbol) = .initFull();
|
||||
@@ -334,7 +324,7 @@ const SymbolSpec = union(enum) {
|
||||
.reg => aarch64.encoding.Register,
|
||||
.arrangement => aarch64.encoding.Register.Arrangement,
|
||||
.systemreg => aarch64.encoding.Register.System,
|
||||
.imm => |imm_spec| @Type(.{ .int = imm_spec.type }),
|
||||
.imm => |imm_spec| @Int(imm_spec.type.signedness, imm_spec.type.bits),
|
||||
.fimm => f16,
|
||||
.extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,
|
||||
.shift => Instruction.DataProcessingRegister.Shift.Op,
|
||||
@@ -413,13 +403,13 @@ const SymbolSpec = union(enum) {
|
||||
return systemreg;
|
||||
},
|
||||
.imm => |imm_spec| {
|
||||
const imm = std.fmt.parseInt(@Type(.{ .int = .{
|
||||
.signedness = imm_spec.type.signedness,
|
||||
.bits = switch (imm_spec.adjust) {
|
||||
const imm = std.fmt.parseInt(@Int(
|
||||
imm_spec.type.signedness,
|
||||
switch (imm_spec.adjust) {
|
||||
.none, .neg_wrap => imm_spec.type.bits,
|
||||
.dec => imm_spec.type.bits + 1,
|
||||
},
|
||||
} }), token, 0) catch {
|
||||
), token, 0) catch {
|
||||
log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)});
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -8928,12 +8928,16 @@ pub const Value = struct {
|
||||
constant: Constant,
|
||||
|
||||
pub const Tag = @typeInfo(Parent).@"union".tag_type.?;
|
||||
pub const Payload = @Type(.{ .@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = null,
|
||||
.fields = @typeInfo(Parent).@"union".fields,
|
||||
.decls = &.{},
|
||||
} });
|
||||
pub const Payload = Payload: {
|
||||
const fields = @typeInfo(Parent).@"union".fields;
|
||||
var types: [fields.len]type = undefined;
|
||||
var names: [fields.len][]const u8 = undefined;
|
||||
for (fields, &types, &names) |f, *ty, *name| {
|
||||
ty.* = f.type;
|
||||
name.* = f.name;
|
||||
}
|
||||
break :Payload @Union(.auto, null, &names, &types, &@splat(.{}));
|
||||
};
|
||||
};
|
||||
|
||||
pub const Location = union(enum(u1)) {
|
||||
@@ -8949,12 +8953,16 @@ pub const Value = struct {
|
||||
},
|
||||
|
||||
pub const Tag = @typeInfo(Location).@"union".tag_type.?;
|
||||
pub const Payload = @Type(.{ .@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = null,
|
||||
.fields = @typeInfo(Location).@"union".fields,
|
||||
.decls = &.{},
|
||||
} });
|
||||
pub const Payload = Payload: {
|
||||
const fields = @typeInfo(Location).@"union".fields;
|
||||
var types: [fields.len]type = undefined;
|
||||
var names: [fields.len][]const u8 = undefined;
|
||||
for (fields, &types, &names) |f, *ty, *name| {
|
||||
ty.* = f.type;
|
||||
name.* = f.name;
|
||||
}
|
||||
break :Payload @Union(.auto, null, &names, &types, &@splat(.{}));
|
||||
};
|
||||
};
|
||||
|
||||
pub const Indirect = packed struct(u32) {
|
||||
@@ -11210,7 +11218,7 @@ pub const Value = struct {
|
||||
.storage = .{ .u64 = switch (size) {
|
||||
else => unreachable,
|
||||
inline 1...8 => |ct_size| std.mem.readInt(
|
||||
@Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * ct_size } }),
|
||||
@Int(.unsigned, 8 * ct_size),
|
||||
buffer[@intCast(offset)..][0..ct_size],
|
||||
isel.target.cpu.arch.endian(),
|
||||
),
|
||||
@@ -11438,7 +11446,7 @@ fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) e
|
||||
switch (buffer.len) {
|
||||
else => unreachable,
|
||||
inline 1...4 => |size| std.mem.writeInt(
|
||||
@Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * size } }),
|
||||
@Int(.unsigned, 8 * size),
|
||||
buffer[0..size],
|
||||
@intCast(error_int),
|
||||
isel.target.cpu.arch.endian(),
|
||||
|
||||
@@ -1416,6 +1416,9 @@ pub const Pool = struct {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.enum_literal_type,
|
||||
.optional_type_type,
|
||||
.manyptr_const_type_type,
|
||||
.slice_const_type_type,
|
||||
=> return .void,
|
||||
.u1_type, .u8_type => return .u8,
|
||||
.i8_type => return .i8,
|
||||
@@ -1525,6 +1528,73 @@ pub const Pool = struct {
|
||||
return pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
},
|
||||
|
||||
.manyptr_const_slice_const_u8_type => {
|
||||
const target = &mod.resolved_target.result;
|
||||
var fields: [2]Info.Field = .{
|
||||
.{
|
||||
.name = .{ .index = .ptr },
|
||||
.ctype = try pool.getPointer(allocator, .{
|
||||
.elem_ctype = .u8,
|
||||
.@"const" = true,
|
||||
.nonstring = true,
|
||||
}),
|
||||
.alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
|
||||
},
|
||||
.{
|
||||
.name = .{ .index = .len },
|
||||
.ctype = .usize,
|
||||
.alignas = AlignAs.fromAbiAlignment(
|
||||
.fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
|
||||
),
|
||||
},
|
||||
};
|
||||
const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
return pool.getPointer(allocator, .{
|
||||
.elem_ctype = slice_const_u8,
|
||||
.@"const" = true,
|
||||
});
|
||||
},
|
||||
.slice_const_slice_const_u8_type => {
|
||||
const target = &mod.resolved_target.result;
|
||||
var fields: [2]Info.Field = .{
|
||||
.{
|
||||
.name = .{ .index = .ptr },
|
||||
.ctype = try pool.getPointer(allocator, .{
|
||||
.elem_ctype = .u8,
|
||||
.@"const" = true,
|
||||
.nonstring = true,
|
||||
}),
|
||||
.alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
|
||||
},
|
||||
.{
|
||||
.name = .{ .index = .len },
|
||||
.ctype = .usize,
|
||||
.alignas = AlignAs.fromAbiAlignment(
|
||||
.fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
|
||||
),
|
||||
},
|
||||
};
|
||||
const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, .forward);
|
||||
fields = .{
|
||||
.{
|
||||
.name = .{ .index = .ptr },
|
||||
.ctype = try pool.getPointer(allocator, .{
|
||||
.elem_ctype = slice_const_u8,
|
||||
.@"const" = true,
|
||||
}),
|
||||
.alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
|
||||
},
|
||||
.{
|
||||
.name = .{ .index = .len },
|
||||
.ctype = .usize,
|
||||
.alignas = AlignAs.fromAbiAlignment(
|
||||
.fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
|
||||
),
|
||||
},
|
||||
};
|
||||
return pool.fromFields(allocator, .@"struct", &fields, kind);
|
||||
},
|
||||
|
||||
.vector_8_i8_type => {
|
||||
const vector_ctype = try pool.getVector(allocator, .{
|
||||
.elem_ctype = .i8,
|
||||
|
||||
@@ -189867,9 +189867,7 @@ const Select = struct {
|
||||
}
|
||||
|
||||
fn adjustedImm(op: Select.Operand, comptime SignedImm: type, s: *const Select) SignedImm {
|
||||
const UnsignedImm = @Type(.{
|
||||
.int = .{ .signedness = .unsigned, .bits = @typeInfo(SignedImm).int.bits },
|
||||
});
|
||||
const UnsignedImm = @Int(.unsigned, @typeInfo(SignedImm).int.bits);
|
||||
const lhs: SignedImm = lhs: switch (op.flags.adjust.lhs) {
|
||||
.none => 0,
|
||||
.ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8),
|
||||
@@ -189934,10 +189932,10 @@ const Select = struct {
|
||||
const RefImm = switch (size) {
|
||||
else => comptime unreachable,
|
||||
.none => Imm,
|
||||
.byte, .word, .dword, .qword => @Type(comptime .{ .int = .{
|
||||
.signedness = @typeInfo(Imm).int.signedness,
|
||||
.bits = size.bitSize(undefined),
|
||||
} }),
|
||||
.byte, .word, .dword, .qword => @Int(
|
||||
@typeInfo(Imm).int.signedness,
|
||||
size.bitSize(undefined),
|
||||
),
|
||||
};
|
||||
break :lhs @bitCast(@as(Imm, @intCast(@as(RefImm, switch (adjust) {
|
||||
else => comptime unreachable,
|
||||
|
||||
@@ -708,7 +708,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
switch (reloc.source_length) {
|
||||
else => unreachable,
|
||||
inline 1, 4 => |source_length| std.mem.writeInt(
|
||||
@Type(.{ .int = .{ .signedness = .signed, .bits = @as(u16, 8) * source_length } }),
|
||||
@Int(.signed, @as(u16, 8) * source_length),
|
||||
inst_bytes[reloc.source_offset..][0..source_length],
|
||||
@intCast(disp),
|
||||
.little,
|
||||
|
||||
+1
-4
@@ -51,10 +51,7 @@ pub const Diags = struct {
|
||||
|
||||
const Int = blk: {
|
||||
const bits = @typeInfo(@This()).@"struct".fields.len;
|
||||
break :blk @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = bits,
|
||||
} });
|
||||
break :blk @Int(.unsigned, bits);
|
||||
};
|
||||
|
||||
pub fn anySet(ef: Flags) bool {
|
||||
|
||||
+19
-14
@@ -4490,7 +4490,12 @@ fn updateContainerTypeWriterError(
|
||||
.enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
|
||||
.union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
|
||||
.opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
|
||||
.reify => @as(Zir.Inst.NameStrategy, @enumFromInt(decl_inst.data.extended.small)),
|
||||
|
||||
.reify_enum,
|
||||
.reify_struct,
|
||||
.reify_union,
|
||||
=> @enumFromInt(decl_inst.data.extended.small),
|
||||
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable,
|
||||
@@ -5125,25 +5130,23 @@ pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
|
||||
|
||||
fn DeclValEnum(comptime T: type) type {
|
||||
const decls = @typeInfo(T).@"struct".decls;
|
||||
@setEvalBranchQuota(7 * decls.len);
|
||||
var fields: [decls.len]std.builtin.Type.EnumField = undefined;
|
||||
@setEvalBranchQuota(10 * decls.len);
|
||||
var field_names: [decls.len][]const u8 = undefined;
|
||||
var fields_len = 0;
|
||||
var min_value: ?comptime_int = null;
|
||||
var max_value: ?comptime_int = null;
|
||||
for (decls) |decl| {
|
||||
if (std.mem.startsWith(u8, decl.name, "HP_") or std.mem.endsWith(u8, decl.name, "_user")) continue;
|
||||
const value = @field(T, decl.name);
|
||||
fields[fields_len] = .{ .name = decl.name, .value = value };
|
||||
field_names[fields_len] = decl.name;
|
||||
fields_len += 1;
|
||||
if (min_value == null or min_value.? > value) min_value = value;
|
||||
if (max_value == null or max_value.? < value) max_value = value;
|
||||
}
|
||||
return @Type(.{ .@"enum" = .{
|
||||
.tag_type = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0),
|
||||
.fields = fields[0..fields_len],
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
} });
|
||||
const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);
|
||||
var field_vals: [fields_len]TagInt = undefined;
|
||||
for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);
|
||||
return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals);
|
||||
}
|
||||
|
||||
const AbbrevCode = enum {
|
||||
@@ -6377,10 +6380,12 @@ fn freeCommonEntry(
|
||||
|
||||
fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
|
||||
switch (buf.len) {
|
||||
inline 0...8 => |len| std.mem.writeInt(@Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = len * 8,
|
||||
} }), buf[0..len], @intCast(int), dwarf.endian),
|
||||
inline 0...8 => |len| std.mem.writeInt(
|
||||
@Int(.unsigned, len * 8),
|
||||
buf[0..len],
|
||||
@intCast(int),
|
||||
dwarf.endian,
|
||||
),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
+6
-14
@@ -108,10 +108,7 @@ pub const Node = extern struct {
|
||||
has_content: bool,
|
||||
/// Whether a moved event on this node bubbles down to children.
|
||||
bubbles_moved: bool,
|
||||
unused: @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = 32 - @bitSizeOf(std.mem.Alignment) - 6,
|
||||
} }) = 0,
|
||||
unused: @Int(.unsigned, 32 - @bitSizeOf(std.mem.Alignment) - 6) = 0,
|
||||
};
|
||||
|
||||
pub const Location = union(enum(u1)) {
|
||||
@@ -122,19 +119,14 @@ pub const Node = extern struct {
|
||||
},
|
||||
large: extern struct {
|
||||
index: usize,
|
||||
unused: @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = 64 - @bitSizeOf(usize),
|
||||
} }) = 0,
|
||||
unused: @Int(.unsigned, 64 - @bitSizeOf(usize)) = 0,
|
||||
},
|
||||
|
||||
pub const Tag = @typeInfo(Location).@"union".tag_type.?;
|
||||
pub const Payload = @Type(.{ .@"union" = .{
|
||||
.layout = .@"extern",
|
||||
.tag_type = null,
|
||||
.fields = @typeInfo(Location).@"union".fields,
|
||||
.decls = &.{},
|
||||
} });
|
||||
pub const Payload = extern union {
|
||||
small: @FieldType(Location, "small"),
|
||||
large: @FieldType(Location, "large"),
|
||||
};
|
||||
|
||||
pub fn resolve(loc: Location, mf: *const MappedFile) [2]u64 {
|
||||
return switch (loc) {
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ var log_scopes: std.ArrayList([]const u8) = .empty;
|
||||
|
||||
pub fn log(
|
||||
comptime level: std.log.Level,
|
||||
comptime scope: @Type(.enum_literal),
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
|
||||
+93
-11
@@ -399,6 +399,7 @@ const Writer = struct {
|
||||
.splat,
|
||||
.reduce,
|
||||
.bitcast,
|
||||
.reify_int,
|
||||
.vector_type,
|
||||
.max,
|
||||
.min,
|
||||
@@ -568,6 +569,8 @@ const Writer = struct {
|
||||
.work_group_id,
|
||||
.branch_hint,
|
||||
.float_op_result_ty,
|
||||
.reify_tuple,
|
||||
.reify_pointer_sentinel_ty,
|
||||
=> {
|
||||
const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||
try self.writeInstRef(stream, inst_data.operand);
|
||||
@@ -575,23 +578,13 @@ const Writer = struct {
|
||||
try self.writeSrcNode(stream, inst_data.node);
|
||||
},
|
||||
|
||||
.reify => {
|
||||
const inst_data = self.code.extraData(Zir.Inst.Reify, extended.operand).data;
|
||||
try stream.print("line({d}), ", .{inst_data.src_line});
|
||||
try self.writeInstRef(stream, inst_data.operand);
|
||||
try stream.writeAll(")) ");
|
||||
const prev_parent_decl_node = self.parent_decl_node;
|
||||
self.parent_decl_node = inst_data.node;
|
||||
defer self.parent_decl_node = prev_parent_decl_node;
|
||||
try self.writeSrcNode(stream, .zero);
|
||||
},
|
||||
|
||||
.builtin_extern,
|
||||
.c_define,
|
||||
.error_cast,
|
||||
.wasm_memory_grow,
|
||||
.prefetch,
|
||||
.c_va_arg,
|
||||
.reify_enum_value_slice_ty,
|
||||
=> {
|
||||
const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
|
||||
try self.writeInstRef(stream, inst_data.lhs);
|
||||
@@ -601,6 +594,95 @@ const Writer = struct {
|
||||
try self.writeSrcNode(stream, inst_data.node);
|
||||
},
|
||||
|
||||
.reify_slice_arg_ty => {
|
||||
const reify_slice_arg_info: Zir.Inst.ReifySliceArgInfo = @enumFromInt(extended.operand);
|
||||
const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||
try stream.print("{t}, ", .{reify_slice_arg_info});
|
||||
try self.writeInstRef(stream, extra.operand);
|
||||
try stream.writeAll(")) ");
|
||||
try self.writeSrcNode(stream, extra.node);
|
||||
},
|
||||
|
||||
.reify_pointer => {
|
||||
const extra = self.code.extraData(Zir.Inst.ReifyPointer, extended.operand).data;
|
||||
try self.writeInstRef(stream, extra.size);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.attrs);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.elem_ty);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.sentinel);
|
||||
try stream.writeAll(")) ");
|
||||
try self.writeSrcNode(stream, extra.node);
|
||||
},
|
||||
.reify_fn => {
|
||||
const extra = self.code.extraData(Zir.Inst.ReifyFn, extended.operand).data;
|
||||
try self.writeInstRef(stream, extra.param_types);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.param_attrs);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.ret_ty);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.fn_attrs);
|
||||
try stream.writeAll(")) ");
|
||||
try self.writeSrcNode(stream, extra.node);
|
||||
},
|
||||
.reify_struct => {
|
||||
const extra = self.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
|
||||
const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
|
||||
try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
|
||||
try self.writeInstRef(stream, extra.layout);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.backing_ty);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_names);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_types);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_attrs);
|
||||
try stream.writeAll(")) ");
|
||||
const prev_parent_decl_node = self.parent_decl_node;
|
||||
self.parent_decl_node = extra.node;
|
||||
defer self.parent_decl_node = prev_parent_decl_node;
|
||||
try self.writeSrcNode(stream, .zero);
|
||||
},
|
||||
.reify_union => {
|
||||
const extra = self.code.extraData(Zir.Inst.ReifyUnion, extended.operand).data;
|
||||
const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
|
||||
try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
|
||||
try self.writeInstRef(stream, extra.layout);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.arg_ty);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_names);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_types);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_attrs);
|
||||
try stream.writeAll(")) ");
|
||||
const prev_parent_decl_node = self.parent_decl_node;
|
||||
self.parent_decl_node = extra.node;
|
||||
defer self.parent_decl_node = prev_parent_decl_node;
|
||||
try self.writeSrcNode(stream, .zero);
|
||||
},
|
||||
.reify_enum => {
|
||||
const extra = self.code.extraData(Zir.Inst.ReifyEnum, extended.operand).data;
|
||||
const name_strat: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
|
||||
try stream.print("line({d}), {t}, ", .{ extra.src_line, name_strat });
|
||||
try self.writeInstRef(stream, extra.tag_ty);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.mode);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_names);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_values);
|
||||
try stream.writeAll(")) ");
|
||||
const prev_parent_decl_node = self.parent_decl_node;
|
||||
self.parent_decl_node = extra.node;
|
||||
defer self.parent_decl_node = prev_parent_decl_node;
|
||||
try self.writeSrcNode(stream, .zero);
|
||||
},
|
||||
|
||||
.cmpxchg => try self.writeCmpxchg(stream, extended),
|
||||
.ptr_cast_full => try self.writePtrCastFull(stream, extended),
|
||||
.ptr_cast_no_dest => try self.writePtrCastNoDest(stream, extended),
|
||||
|
||||
Binary file not shown.
@@ -1264,12 +1264,9 @@ test "reference to inferred local variable works as expected" {
|
||||
try expect(crasher_local.lets_crash != a.lets_crash);
|
||||
}
|
||||
|
||||
test "@Type returned from block" {
|
||||
test "@Int returned from block" {
|
||||
const T = comptime b: {
|
||||
break :b @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = 8,
|
||||
} });
|
||||
break :b @Int(.unsigned, 8);
|
||||
};
|
||||
try std.testing.expect(T == u8);
|
||||
}
|
||||
|
||||
@@ -119,21 +119,12 @@ test "Saturating Shift Left where lhs is of a computed type" {
|
||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
fn getIntShiftType(comptime T: type) type {
|
||||
var unsigned_shift_type = @typeInfo(std.math.Log2Int(T)).int;
|
||||
unsigned_shift_type.signedness = .signed;
|
||||
|
||||
return @Type(.{
|
||||
.int = unsigned_shift_type,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn FixedPoint(comptime ValueType: type) type {
|
||||
return struct {
|
||||
value: ValueType,
|
||||
exponent: ShiftType,
|
||||
|
||||
const ShiftType: type = getIntShiftType(ValueType);
|
||||
const ShiftType = @Int(.signed, @typeInfo(std.math.Log2Int(ValueType)).int.bits);
|
||||
|
||||
pub fn shiftExponent(self: @This(), shift: ShiftType) @This() {
|
||||
const shiftAbs = @abs(shift);
|
||||
|
||||
@@ -355,7 +355,7 @@ test "inline call doesn't re-evaluate non generic struct" {
|
||||
try comptime @call(.always_inline, S.foo, ArgTuple{.{ .a = 123, .b = 45 }});
|
||||
}
|
||||
|
||||
test "Enum constructed by @Type passed as generic argument" {
|
||||
test "Enum constructed by @Enum passed as generic argument" {
|
||||
const S = struct {
|
||||
const E = std.meta.FieldEnum(struct {
|
||||
prev_pos: bool,
|
||||
|
||||
@@ -2446,9 +2446,14 @@ test "peer type resolution: pointer attributes are combined correctly" {
|
||||
};
|
||||
|
||||
const NonAllowZero = comptime blk: {
|
||||
var ti = @typeInfo(@TypeOf(r1, r2, r3, r4));
|
||||
ti.pointer.is_allowzero = false;
|
||||
break :blk @Type(ti);
|
||||
const ptr = @typeInfo(@TypeOf(r1, r2, r3, r4)).pointer;
|
||||
break :blk @Pointer(ptr.size, .{
|
||||
.@"const" = ptr.is_const,
|
||||
.@"volatile" = ptr.is_volatile,
|
||||
.@"allowzero" = false,
|
||||
.@"align" = ptr.alignment,
|
||||
.@"addrspace" = ptr.address_space,
|
||||
}, ptr.child, ptr.sentinel());
|
||||
};
|
||||
try expectEqualSlices(u8, std.mem.span(@volatileCast(@as(NonAllowZero, @ptrCast(r1)))), "foo");
|
||||
try expectEqualSlices(u8, std.mem.span(@volatileCast(@as(NonAllowZero, @ptrCast(r2)))), "bar");
|
||||
|
||||
@@ -1283,10 +1283,7 @@ test "Non-exhaustive enum backed by comptime_int" {
|
||||
test "matching captures causes enum equivalence" {
|
||||
const S = struct {
|
||||
fn Nonexhaustive(comptime I: type) type {
|
||||
const UTag = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = @typeInfo(I).int.bits,
|
||||
} });
|
||||
const UTag = @Int(.unsigned, @typeInfo(I).int.bits);
|
||||
return enum(UTag) { _ };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -556,10 +556,10 @@ test "lazy values passed to anytype parameter" {
|
||||
|
||||
test "pass and return comptime-only types" {
|
||||
const S = struct {
|
||||
fn returnNull(comptime x: @Type(.null)) @Type(.null) {
|
||||
fn returnNull(comptime x: @TypeOf(null)) @TypeOf(null) {
|
||||
return x;
|
||||
}
|
||||
fn returnUndefined(comptime x: @Type(.undefined)) @Type(.undefined) {
|
||||
fn returnUndefined(comptime x: @TypeOf(undefined)) @TypeOf(undefined) {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -263,15 +263,7 @@ test "generic function instantiation turns into comptime call" {
|
||||
|
||||
pub fn FieldEnum(comptime T: type) type {
|
||||
_ = T;
|
||||
var enumFields: [1]std.builtin.Type.EnumField = .{.{ .name = "A", .value = 0 }};
|
||||
return @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u0,
|
||||
.fields = &enumFields,
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
return @Enum(u0, .exhaustive, &.{"A"}, &.{0});
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
|
||||
@@ -338,14 +338,14 @@ test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {
|
||||
|
||||
test "@sizeOf reified union zero-size payload fields" {
|
||||
comptime {
|
||||
try std.testing.expect(0 == @sizeOf(@Type(@typeInfo(union {}))));
|
||||
try std.testing.expect(0 == @sizeOf(@Type(@typeInfo(union { a: void }))));
|
||||
try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{}, &.{}, &.{})));
|
||||
try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{"a"}, &.{void}, &.{.{}})));
|
||||
if (builtin.mode == .Debug or builtin.mode == .ReleaseSafe) {
|
||||
try std.testing.expect(1 == @sizeOf(@Type(@typeInfo(union { a: void, b: void }))));
|
||||
try std.testing.expect(1 == @sizeOf(@Type(@typeInfo(union { a: void, b: void, c: void }))));
|
||||
try std.testing.expect(1 == @sizeOf(@Union(.auto, null, &.{ "a", "b" }, &.{ void, void }, &.{ .{}, .{} })));
|
||||
try std.testing.expect(1 == @sizeOf(@Union(.auto, null, &.{ "a", "b", "c" }, &.{ void, void, void }, &.{ .{}, .{}, .{} })));
|
||||
} else {
|
||||
try std.testing.expect(0 == @sizeOf(@Type(@typeInfo(union { a: void, b: void }))));
|
||||
try std.testing.expect(0 == @sizeOf(@Type(@typeInfo(union { a: void, b: void, c: void }))));
|
||||
try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{ "a", "b" }, &.{ void, void }, &.{ .{}, .{} })));
|
||||
try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{ "a", "b", "c" }, &.{ void, void, void }, &.{ .{}, .{}, .{} })));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2034,10 +2034,7 @@ test "matching captures causes struct equivalence" {
|
||||
fn UnsignedWrapper(comptime I: type) type {
|
||||
const bits = @typeInfo(I).int.bits;
|
||||
return struct {
|
||||
x: @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = bits,
|
||||
} }),
|
||||
x: @Int(.unsigned, bits),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -843,7 +843,8 @@ test "switch capture peer type resolution for in-memory coercible payloads" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
const T1 = c_int;
|
||||
const T2 = @Type(@typeInfo(T1));
|
||||
const t1_info = @typeInfo(T1).int;
|
||||
const T2 = @Int(t1_info.signedness, t1_info.bits);
|
||||
|
||||
comptime assert(T1 != T2);
|
||||
|
||||
@@ -865,7 +866,8 @@ test "switch pointer capture peer type resolution" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
const T1 = c_int;
|
||||
const T2 = @Type(@typeInfo(T1));
|
||||
const t1_info = @typeInfo(T1).int;
|
||||
const T2 = @Int(t1_info.signedness, t1_info.bits);
|
||||
|
||||
comptime assert(T1 != T2);
|
||||
|
||||
|
||||
@@ -230,10 +230,7 @@ test "switch loop on larger than pointer integer" {
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
|
||||
|
||||
var entry: @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = @bitSizeOf(usize) + 1,
|
||||
} }) = undefined;
|
||||
var entry: @Int(.unsigned, @bitSizeOf(usize) + 1) = undefined;
|
||||
entry = 0;
|
||||
loop: switch (entry) {
|
||||
0 => {
|
||||
|
||||
+4
-55
@@ -130,29 +130,7 @@ test "array-like initializer for tuple types" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
|
||||
|
||||
const T = @Type(.{
|
||||
.@"struct" = .{
|
||||
.is_tuple = true,
|
||||
.layout = .auto,
|
||||
.decls = &.{},
|
||||
.fields = &.{
|
||||
.{
|
||||
.name = "0",
|
||||
.type = i32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(i32),
|
||||
},
|
||||
.{
|
||||
.name = "1",
|
||||
.type = u8,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(u8),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const T = @Tuple(&.{ i32, u8 });
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
var obj: T = .{ -1234, 128 };
|
||||
@@ -320,20 +298,7 @@ test "zero sized struct in tuple handled correctly" {
|
||||
const Self = @This();
|
||||
const Inner = struct {};
|
||||
|
||||
data: @Type(.{
|
||||
.@"struct" = .{
|
||||
.is_tuple = true,
|
||||
.layout = .auto,
|
||||
.decls = &.{},
|
||||
.fields = &.{.{
|
||||
.name = "0",
|
||||
.type = Inner,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(Inner),
|
||||
}},
|
||||
},
|
||||
}),
|
||||
data: @Tuple(&.{Inner}),
|
||||
|
||||
pub fn do(this: Self) usize {
|
||||
return @sizeOf(@TypeOf(this));
|
||||
@@ -470,12 +435,7 @@ test "coerce anon tuple to tuple" {
|
||||
}
|
||||
|
||||
test "empty tuple type" {
|
||||
const S = @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &.{},
|
||||
.decls = &.{},
|
||||
.is_tuple = true,
|
||||
} });
|
||||
const S = @Tuple(&.{});
|
||||
|
||||
const s: S = .{};
|
||||
try expect(s.len == 0);
|
||||
@@ -616,18 +576,7 @@ test "OPV tuple fields aren't comptime" {
|
||||
const t_info = @typeInfo(T);
|
||||
try expect(!t_info.@"struct".fields[0].is_comptime);
|
||||
|
||||
const T2 = @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &.{.{
|
||||
.name = "0",
|
||||
.type = void,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(void),
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = true,
|
||||
} });
|
||||
const T2 = @Tuple(&.{void});
|
||||
const t2_info = @typeInfo(T2);
|
||||
try expect(!t2_info.@"struct".fields[0].is_comptime);
|
||||
}
|
||||
|
||||
+91
-475
@@ -4,63 +4,17 @@ const Type = std.builtin.Type;
|
||||
const testing = std.testing;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
fn testTypes(comptime types: []const type) !void {
|
||||
inline for (types) |testType| {
|
||||
try testing.expect(testType == @Type(@typeInfo(testType)));
|
||||
}
|
||||
}
|
||||
|
||||
test "Type.MetaType" {
|
||||
try testing.expect(type == @Type(.{ .type = {} }));
|
||||
try testTypes(&[_]type{type});
|
||||
}
|
||||
|
||||
test "Type.Void" {
|
||||
try testing.expect(void == @Type(.{ .void = {} }));
|
||||
try testTypes(&[_]type{void});
|
||||
}
|
||||
|
||||
test "Type.Bool" {
|
||||
try testing.expect(bool == @Type(.{ .bool = {} }));
|
||||
try testTypes(&[_]type{bool});
|
||||
}
|
||||
|
||||
test "Type.NoReturn" {
|
||||
try testing.expect(noreturn == @Type(.{ .noreturn = {} }));
|
||||
try testTypes(&[_]type{noreturn});
|
||||
}
|
||||
|
||||
test "Type.Int" {
|
||||
try testing.expect(u1 == @Type(.{ .int = .{ .signedness = .unsigned, .bits = 1 } }));
|
||||
try testing.expect(i1 == @Type(.{ .int = .{ .signedness = .signed, .bits = 1 } }));
|
||||
try testing.expect(u8 == @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 } }));
|
||||
try testing.expect(i8 == @Type(.{ .int = .{ .signedness = .signed, .bits = 8 } }));
|
||||
try testing.expect(u64 == @Type(.{ .int = .{ .signedness = .unsigned, .bits = 64 } }));
|
||||
try testing.expect(i64 == @Type(.{ .int = .{ .signedness = .signed, .bits = 64 } }));
|
||||
try testTypes(&[_]type{ u8, u32, i64 });
|
||||
}
|
||||
|
||||
test "Type.ComptimeFloat" {
|
||||
try testTypes(&[_]type{comptime_float});
|
||||
}
|
||||
test "Type.ComptimeInt" {
|
||||
try testTypes(&[_]type{comptime_int});
|
||||
}
|
||||
test "Type.Undefined" {
|
||||
try testTypes(&[_]type{@TypeOf(undefined)});
|
||||
}
|
||||
test "Type.Null" {
|
||||
try testTypes(&[_]type{@TypeOf(null)});
|
||||
}
|
||||
|
||||
test "Type.EnumLiteral" {
|
||||
try testTypes(&[_]type{
|
||||
@TypeOf(.Dummy),
|
||||
});
|
||||
try testing.expect(u1 == @Int(.unsigned, 1));
|
||||
try testing.expect(i1 == @Int(.signed, 1));
|
||||
try testing.expect(u8 == @Int(.unsigned, 8));
|
||||
try testing.expect(i8 == @Int(.signed, 8));
|
||||
try testing.expect(u64 == @Int(.unsigned, 64));
|
||||
try testing.expect(i64 == @Int(.signed, 64));
|
||||
}
|
||||
|
||||
test "Type.Pointer" {
|
||||
try testTypes(&[_]type{
|
||||
inline for (&[_]type{
|
||||
// One Value Pointer Types
|
||||
*u8, *const u8,
|
||||
*volatile u8, *const volatile u8,
|
||||
@@ -101,62 +55,30 @@ test "Type.Pointer" {
|
||||
[*c]align(4) volatile u8, [*c]align(4) const volatile u8,
|
||||
[*c]align(8) u8, [*c]align(8) const u8,
|
||||
[*c]align(8) volatile u8, [*c]align(8) const volatile u8,
|
||||
});
|
||||
}) |testType| {
|
||||
const ptr = @typeInfo(testType).pointer;
|
||||
try testing.expect(testType == @Pointer(ptr.size, .{
|
||||
.@"const" = ptr.is_const,
|
||||
.@"volatile" = ptr.is_volatile,
|
||||
.@"allowzero" = ptr.is_allowzero,
|
||||
.@"align" = ptr.alignment,
|
||||
.@"addrspace" = ptr.address_space,
|
||||
}, ptr.child, ptr.sentinel()));
|
||||
}
|
||||
}
|
||||
|
||||
test "Type.Float" {
|
||||
try testing.expect(f16 == @Type(.{ .float = .{ .bits = 16 } }));
|
||||
try testing.expect(f32 == @Type(.{ .float = .{ .bits = 32 } }));
|
||||
try testing.expect(f64 == @Type(.{ .float = .{ .bits = 64 } }));
|
||||
try testing.expect(f80 == @Type(.{ .float = .{ .bits = 80 } }));
|
||||
try testing.expect(f128 == @Type(.{ .float = .{ .bits = 128 } }));
|
||||
try testTypes(&[_]type{ f16, f32, f64, f80, f128 });
|
||||
test "@Pointer create slice without sentinel" {
|
||||
const Slice = @Pointer(.slice, .{ .@"const" = true, .@"align" = 8 }, ?*i32, null);
|
||||
try testing.expect(Slice == []align(8) const ?*i32);
|
||||
}
|
||||
|
||||
test "Type.Array" {
|
||||
try testing.expect([123]u8 == @Type(.{
|
||||
.array = .{
|
||||
.len = 123,
|
||||
.child = u8,
|
||||
.sentinel_ptr = null,
|
||||
},
|
||||
}));
|
||||
try testing.expect([2]u32 == @Type(.{
|
||||
.array = .{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.sentinel_ptr = null,
|
||||
},
|
||||
}));
|
||||
try testing.expect([2:0]u32 == @Type(.{
|
||||
.array = .{
|
||||
.len = 2,
|
||||
.child = u32,
|
||||
.sentinel_ptr = &@as(u32, 0),
|
||||
},
|
||||
}));
|
||||
try testTypes(&[_]type{ [1]u8, [30]usize, [7]bool });
|
||||
test "@Pointer create slice with null sentinel" {
|
||||
const Slice = @Pointer(.slice, .{ .@"const" = true, .@"align" = 8 }, ?*i32, @as(?*i32, null));
|
||||
try testing.expect(Slice == [:null]align(8) const ?*i32);
|
||||
}
|
||||
|
||||
test "@Type create slice with null sentinel" {
|
||||
const Slice = @Type(.{
|
||||
.pointer = .{
|
||||
.size = .slice,
|
||||
.is_const = true,
|
||||
.is_volatile = false,
|
||||
.is_allowzero = false,
|
||||
.alignment = 8,
|
||||
.address_space = .generic,
|
||||
.child = *i32,
|
||||
.sentinel_ptr = null,
|
||||
},
|
||||
});
|
||||
try testing.expect(Slice == []align(8) const *i32);
|
||||
}
|
||||
|
||||
test "@Type picks up the sentinel value from Type" {
|
||||
try testTypes(&[_]type{
|
||||
[11:0]u8, [4:10]u8,
|
||||
test "@Pointer on @typeInfo round-trips sentinels" {
|
||||
inline for (&[_]type{
|
||||
[*:0]u8, [*:0]const u8,
|
||||
[*:0]volatile u8, [*:0]const volatile u8,
|
||||
[*:0]align(4) u8, [*:0]align(4) const u8,
|
||||
@@ -179,24 +101,16 @@ test "@Type picks up the sentinel value from Type" {
|
||||
[:0]allowzero align(4) u8, [:0]allowzero align(4) const u8,
|
||||
[:0]allowzero align(4) volatile u8, [:0]allowzero align(4) const volatile u8,
|
||||
[:4]allowzero align(4) volatile u8, [:4]allowzero align(4) const volatile u8,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.Optional" {
|
||||
try testTypes(&[_]type{
|
||||
?u8,
|
||||
?*u8,
|
||||
?[]u8,
|
||||
?[*]u8,
|
||||
?[*c]u8,
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.ErrorUnion" {
|
||||
try testTypes(&[_]type{
|
||||
error{}!void,
|
||||
error{Error}!void,
|
||||
});
|
||||
}) |TestType| {
|
||||
const ptr = @typeInfo(TestType).pointer;
|
||||
try testing.expect(TestType == @Pointer(ptr.size, .{
|
||||
.@"const" = ptr.is_const,
|
||||
.@"volatile" = ptr.is_volatile,
|
||||
.@"allowzero" = ptr.is_allowzero,
|
||||
.@"align" = ptr.alignment,
|
||||
.@"addrspace" = ptr.address_space,
|
||||
}, ptr.child, ptr.sentinel()));
|
||||
}
|
||||
}
|
||||
|
||||
test "Type.Opaque" {
|
||||
@@ -205,11 +119,7 @@ test "Type.Opaque" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
|
||||
|
||||
const Opaque = @Type(.{
|
||||
.@"opaque" = .{
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const Opaque = opaque {};
|
||||
try testing.expect(Opaque != opaque {});
|
||||
try testing.expectEqualSlices(
|
||||
Type.Declaration,
|
||||
@@ -218,52 +128,17 @@ test "Type.Opaque" {
|
||||
);
|
||||
}
|
||||
|
||||
test "Type.Vector" {
|
||||
try testTypes(&[_]type{
|
||||
@Vector(0, u8),
|
||||
@Vector(4, u8),
|
||||
@Vector(8, *u8),
|
||||
@Vector(0, u8),
|
||||
@Vector(4, u8),
|
||||
@Vector(8, *u8),
|
||||
});
|
||||
}
|
||||
|
||||
test "Type.AnyFrame" {
|
||||
if (true) {
|
||||
// https://github.com/ziglang/zig/issues/6025
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testTypes(&[_]type{
|
||||
anyframe,
|
||||
anyframe->u8,
|
||||
anyframe->anyframe->u8,
|
||||
});
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) i32 {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
test "Type.ErrorSet" {
|
||||
try testing.expect(@Type(.{ .error_set = null }) == anyerror);
|
||||
|
||||
// error sets don't compare equal so just check if they compile
|
||||
inline for (.{ error{}, error{A}, error{ A, B, C } }) |T| {
|
||||
const info = @typeInfo(T);
|
||||
const T2 = @Type(info);
|
||||
try testing.expect(T == T2);
|
||||
}
|
||||
}
|
||||
|
||||
test "Type.Struct" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
|
||||
|
||||
const A = @Type(@typeInfo(struct { x: u8, y: u32 }));
|
||||
const A = @Struct(.auto, null, &.{ "x", "y" }, &.{ u8, u32 }, &@splat(.{}));
|
||||
const infoA = @typeInfo(A).@"struct";
|
||||
try testing.expectEqual(Type.ContainerLayout.auto, infoA.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoA.fields[0].name);
|
||||
@@ -281,7 +156,13 @@ test "Type.Struct" {
|
||||
a.y += 1;
|
||||
try testing.expectEqual(@as(u32, 2), a.y);
|
||||
|
||||
const B = @Type(@typeInfo(extern struct { x: u8, y: u32 = 5 }));
|
||||
const B = @Struct(
|
||||
.@"extern",
|
||||
null,
|
||||
&.{ "x", "y" },
|
||||
&.{ u8, u32 },
|
||||
&.{ .{}, .{ .default_value_ptr = &@as(u32, 5) } },
|
||||
);
|
||||
const infoB = @typeInfo(B).@"struct";
|
||||
try testing.expectEqual(Type.ContainerLayout.@"extern", infoB.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoB.fields[0].name);
|
||||
@@ -293,7 +174,16 @@ test "Type.Struct" {
|
||||
try testing.expectEqual(@as(usize, 0), infoB.decls.len);
|
||||
try testing.expectEqual(@as(bool, false), infoB.is_tuple);
|
||||
|
||||
const C = @Type(@typeInfo(packed struct { x: u8 = 3, y: u32 = 5 }));
|
||||
const C = @Struct(
|
||||
.@"packed",
|
||||
null,
|
||||
&.{ "x", "y" },
|
||||
&.{ u8, u32 },
|
||||
&.{
|
||||
.{ .default_value_ptr = &@as(u8, 3) },
|
||||
.{ .default_value_ptr = &@as(u32, 5) },
|
||||
},
|
||||
);
|
||||
const infoC = @typeInfo(C).@"struct";
|
||||
try testing.expectEqual(Type.ContainerLayout.@"packed", infoC.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoC.fields[0].name);
|
||||
@@ -305,76 +195,23 @@ test "Type.Struct" {
|
||||
try testing.expectEqual(@as(usize, 0), infoC.decls.len);
|
||||
try testing.expectEqual(@as(bool, false), infoC.is_tuple);
|
||||
|
||||
// anon structs
|
||||
const D = @Type(@typeInfo(@TypeOf(.{ .x = 3, .y = 5 })));
|
||||
const infoD = @typeInfo(D).@"struct";
|
||||
try testing.expectEqual(Type.ContainerLayout.auto, infoD.layout);
|
||||
try testing.expectEqualSlices(u8, "x", infoD.fields[0].name);
|
||||
try testing.expectEqual(comptime_int, infoD.fields[0].type);
|
||||
try testing.expectEqual(@as(comptime_int, 3), infoD.fields[0].defaultValue().?);
|
||||
try testing.expectEqualSlices(u8, "y", infoD.fields[1].name);
|
||||
try testing.expectEqual(comptime_int, infoD.fields[1].type);
|
||||
try testing.expectEqual(@as(comptime_int, 5), infoD.fields[1].defaultValue().?);
|
||||
try testing.expectEqual(@as(usize, 0), infoD.decls.len);
|
||||
try testing.expectEqual(@as(bool, false), infoD.is_tuple);
|
||||
|
||||
// tuples
|
||||
const E = @Type(@typeInfo(@TypeOf(.{ 1, 2 })));
|
||||
const infoE = @typeInfo(E).@"struct";
|
||||
try testing.expectEqual(Type.ContainerLayout.auto, infoE.layout);
|
||||
try testing.expectEqualSlices(u8, "0", infoE.fields[0].name);
|
||||
try testing.expectEqual(comptime_int, infoE.fields[0].type);
|
||||
try testing.expectEqual(@as(comptime_int, 1), infoE.fields[0].defaultValue().?);
|
||||
try testing.expectEqualSlices(u8, "1", infoE.fields[1].name);
|
||||
try testing.expectEqual(comptime_int, infoE.fields[1].type);
|
||||
try testing.expectEqual(@as(comptime_int, 2), infoE.fields[1].defaultValue().?);
|
||||
try testing.expectEqual(@as(usize, 0), infoE.decls.len);
|
||||
try testing.expectEqual(@as(bool, true), infoE.is_tuple);
|
||||
|
||||
// empty struct
|
||||
const F = @Type(@typeInfo(struct {}));
|
||||
const F = @Struct(.auto, null, &.{}, &.{}, &.{});
|
||||
const infoF = @typeInfo(F).@"struct";
|
||||
try testing.expectEqual(Type.ContainerLayout.auto, infoF.layout);
|
||||
try testing.expect(infoF.fields.len == 0);
|
||||
try testing.expectEqual(@as(bool, false), infoF.is_tuple);
|
||||
|
||||
// empty tuple
|
||||
const G = @Type(@typeInfo(@TypeOf(.{})));
|
||||
const infoG = @typeInfo(G).@"struct";
|
||||
try testing.expectEqual(Type.ContainerLayout.auto, infoG.layout);
|
||||
try testing.expect(infoG.fields.len == 0);
|
||||
try testing.expectEqual(@as(bool, true), infoG.is_tuple);
|
||||
}
|
||||
|
||||
test "Type.Enum" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
|
||||
|
||||
const Foo = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u8,
|
||||
.fields = &.{
|
||||
.{ .name = "a", .value = 1 },
|
||||
.{ .name = "b", .value = 5 },
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
const Foo = @Enum(u8, .exhaustive, &.{ "a", "b" }, &.{ 1, 5 });
|
||||
try testing.expectEqual(true, @typeInfo(Foo).@"enum".is_exhaustive);
|
||||
try testing.expectEqual(@as(u8, 1), @intFromEnum(Foo.a));
|
||||
try testing.expectEqual(@as(u8, 5), @intFromEnum(Foo.b));
|
||||
const Bar = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u32,
|
||||
.fields = &.{
|
||||
.{ .name = "a", .value = 1 },
|
||||
.{ .name = "b", .value = 5 },
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = false,
|
||||
},
|
||||
});
|
||||
const Bar = @Enum(u32, .nonexhaustive, &.{ "a", "b" }, &.{ 1, 5 });
|
||||
try testing.expectEqual(false, @typeInfo(Bar).@"enum".is_exhaustive);
|
||||
try testing.expectEqual(@as(u32, 1), @intFromEnum(Bar.a));
|
||||
try testing.expectEqual(@as(u32, 5), @intFromEnum(Bar.b));
|
||||
@@ -382,12 +219,7 @@ test "Type.Enum" {
|
||||
|
||||
{ // from https://github.com/ziglang/zig/issues/19985
|
||||
{ // enum with single field can be initialized.
|
||||
const E = @Type(.{ .@"enum" = .{
|
||||
.tag_type = u0,
|
||||
.is_exhaustive = true,
|
||||
.fields = &.{.{ .name = "foo", .value = 0 }},
|
||||
.decls = &.{},
|
||||
} });
|
||||
const E = @Enum(u0, .exhaustive, &.{"foo"}, &.{0});
|
||||
const s: struct { E } = .{.foo};
|
||||
try testing.expectEqual(.foo, s[0]);
|
||||
}
|
||||
@@ -411,60 +243,20 @@ test "Type.Union" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
|
||||
|
||||
const Untagged = @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .@"extern",
|
||||
.tag_type = null,
|
||||
.fields = &.{
|
||||
.{ .name = "int", .type = i32, .alignment = @alignOf(f32) },
|
||||
.{ .name = "float", .type = f32, .alignment = @alignOf(f32) },
|
||||
},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const Untagged = @Union(.@"extern", null, &.{ "int", "float" }, &.{ i32, f32 }, &.{ .{}, .{} });
|
||||
var untagged = Untagged{ .int = 1 };
|
||||
untagged.float = 2.0;
|
||||
untagged.int = 3;
|
||||
try testing.expectEqual(@as(i32, 3), untagged.int);
|
||||
|
||||
const PackedUntagged = @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .@"packed",
|
||||
.tag_type = null,
|
||||
.fields = &.{
|
||||
.{ .name = "signed", .type = i32, .alignment = 0 },
|
||||
.{ .name = "unsigned", .type = u32, .alignment = 0 },
|
||||
},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const PackedUntagged = @Union(.@"packed", null, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &.{ .{}, .{} });
|
||||
var packed_untagged: PackedUntagged = .{ .signed = -1 };
|
||||
_ = &packed_untagged;
|
||||
try testing.expectEqual(@as(i32, -1), packed_untagged.signed);
|
||||
try testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned);
|
||||
|
||||
const Tag = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u1,
|
||||
.fields = &.{
|
||||
.{ .name = "signed", .value = 0 },
|
||||
.{ .name = "unsigned", .value = 1 },
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
const Tagged = @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = Tag,
|
||||
.fields = &.{
|
||||
.{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },
|
||||
.{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },
|
||||
},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const Tag = @Enum(u1, .exhaustive, &.{ "signed", "unsigned" }, &.{ 0, 1 });
|
||||
const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &.{ .{}, .{} });
|
||||
var tagged = Tagged{ .signed = -1 };
|
||||
try testing.expectEqual(Tag.signed, @as(Tag, tagged));
|
||||
tagged = .{ .unsigned = 1 };
|
||||
@@ -472,74 +264,26 @@ test "Type.Union" {
|
||||
}
|
||||
|
||||
test "Type.Union from Type.Enum" {
|
||||
const Tag = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u0,
|
||||
.fields = &.{
|
||||
.{ .name = "working_as_expected", .value = 0 },
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
const T = @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = Tag,
|
||||
.fields = &.{
|
||||
.{ .name = "working_as_expected", .type = u32, .alignment = @alignOf(u32) },
|
||||
},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const Tag = @Enum(u0, .exhaustive, &.{"working_as_expected"}, &.{0});
|
||||
const T = @Union(.auto, Tag, &.{"working_as_expected"}, &.{u32}, &.{.{}});
|
||||
_ = @typeInfo(T).@"union";
|
||||
}
|
||||
|
||||
test "Type.Union from regular enum" {
|
||||
const E = enum { working_as_expected };
|
||||
const T = @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = E,
|
||||
.fields = &.{
|
||||
.{ .name = "working_as_expected", .type = u32, .alignment = @alignOf(u32) },
|
||||
},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const T = @Union(.auto, E, &.{"working_as_expected"}, &.{u32}, &.{.{}});
|
||||
_ = @typeInfo(T).@"union";
|
||||
}
|
||||
|
||||
test "Type.Union from empty regular enum" {
|
||||
const E = enum {};
|
||||
const U = @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = E,
|
||||
.fields = &.{},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const U = @Union(.auto, E, &.{}, &.{}, &.{});
|
||||
try testing.expectEqual(@sizeOf(U), 0);
|
||||
}
|
||||
|
||||
test "Type.Union from empty Type.Enum" {
|
||||
const E = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u0,
|
||||
.fields = &.{},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
},
|
||||
});
|
||||
const U = @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = E,
|
||||
.fields = &.{},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
const E = @Enum(u0, .exhaustive, &.{}, &.{});
|
||||
const U = @Union(.auto, E, &.{}, &.{}, &.{});
|
||||
try testing.expectEqual(@sizeOf(U), 0);
|
||||
}
|
||||
|
||||
@@ -548,47 +292,22 @@ test "Type.Fn" {
|
||||
|
||||
const some_opaque = opaque {};
|
||||
const some_ptr = *some_opaque;
|
||||
const T = fn (c_int, some_ptr) callconv(.c) void;
|
||||
|
||||
{
|
||||
const fn_info = std.builtin.Type{ .@"fn" = .{
|
||||
.calling_convention = .c,
|
||||
.is_generic = false,
|
||||
.is_var_args = false,
|
||||
.return_type = void,
|
||||
.params = &.{
|
||||
.{ .is_generic = false, .is_noalias = false, .type = c_int },
|
||||
.{ .is_generic = false, .is_noalias = false, .type = some_ptr },
|
||||
},
|
||||
} };
|
||||
const A = @Fn(&.{ c_int, some_ptr }, &@splat(.{}), void, .{ .@"callconv" = .c });
|
||||
comptime assert(A == fn (c_int, some_ptr) callconv(.c) void);
|
||||
|
||||
const fn_type = @Type(fn_info);
|
||||
try std.testing.expectEqual(T, fn_type);
|
||||
}
|
||||
const B = @Fn(&.{ c_int, some_ptr, u32 }, &.{ .{}, .{ .@"noalias" = true }, .{} }, u64, .{});
|
||||
comptime assert(B == fn (c_int, noalias some_ptr, u32) u64);
|
||||
|
||||
{
|
||||
const fn_info = @typeInfo(T);
|
||||
const fn_type = @Type(fn_info);
|
||||
try std.testing.expectEqual(T, fn_type);
|
||||
}
|
||||
const C = @Fn(&.{?[*]u8}, &.{.{}}, *const anyopaque, .{ .@"callconv" = .c, .varargs = true });
|
||||
comptime assert(C == fn (?[*]u8, ...) callconv(.c) *const anyopaque);
|
||||
}
|
||||
|
||||
test "reified struct field name from optional payload" {
|
||||
comptime {
|
||||
const m_name: ?[1:0]u8 = "a".*;
|
||||
if (m_name) |*name| {
|
||||
const T = @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &.{.{
|
||||
.name = name,
|
||||
.type = u8,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = 1,
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
const T = @Struct(.auto, null, &.{name}, &.{u8}, &.{.{}});
|
||||
const t: T = .{ .a = 123 };
|
||||
try std.testing.expect(t.a == 123);
|
||||
}
|
||||
@@ -598,20 +317,7 @@ test "reified struct field name from optional payload" {
|
||||
test "reified union uses @alignOf" {
|
||||
const S = struct {
|
||||
fn CreateUnion(comptime T: type) type {
|
||||
return @Type(.{
|
||||
.@"union" = .{
|
||||
.layout = .auto,
|
||||
.tag_type = null,
|
||||
.fields = &[_]std.builtin.Type.UnionField{
|
||||
.{
|
||||
.name = "field",
|
||||
.type = T,
|
||||
.alignment = @alignOf(T),
|
||||
},
|
||||
},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
return @Union(.auto, null, &.{"field"}, &.{T}, &.{.{}});
|
||||
}
|
||||
};
|
||||
_ = S.CreateUnion(struct {});
|
||||
@@ -620,22 +326,13 @@ test "reified union uses @alignOf" {
|
||||
test "reified struct uses @alignOf" {
|
||||
const S = struct {
|
||||
fn NamespacedGlobals(comptime modules: anytype) type {
|
||||
return @Type(.{
|
||||
.@"struct" = .{
|
||||
.layout = .auto,
|
||||
.is_tuple = false,
|
||||
.fields = &.{
|
||||
.{
|
||||
.name = "globals",
|
||||
.type = modules.mach.globals,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(modules.mach.globals),
|
||||
},
|
||||
},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
return @Struct(
|
||||
.auto,
|
||||
null,
|
||||
&.{"globals"},
|
||||
&.{modules.mach.globals},
|
||||
&.{.{ .@"align" = @alignOf(modules.mach.globals) }},
|
||||
);
|
||||
}
|
||||
};
|
||||
_ = S.NamespacedGlobals(.{
|
||||
@@ -645,56 +342,10 @@ test "reified struct uses @alignOf" {
|
||||
});
|
||||
}
|
||||
|
||||
test "reified error set initialized with field pointer" {
|
||||
const S = struct {
|
||||
const info = .{
|
||||
.args = [_]Type.Error{
|
||||
.{ .name = "bar" },
|
||||
},
|
||||
};
|
||||
const Foo = @Type(.{
|
||||
.error_set = &info.args,
|
||||
});
|
||||
};
|
||||
try testing.expect(S.Foo == error{bar});
|
||||
}
|
||||
test "reified function type params initialized with field pointer" {
|
||||
const S = struct {
|
||||
const fn_info = .{
|
||||
.params = [_]Type.Fn.Param{
|
||||
.{ .is_generic = false, .is_noalias = false, .type = u8 },
|
||||
},
|
||||
};
|
||||
const Bar = @Type(.{
|
||||
.@"fn" = .{
|
||||
.calling_convention = .auto,
|
||||
.is_generic = false,
|
||||
.is_var_args = false,
|
||||
.return_type = void,
|
||||
.params = &fn_info.params,
|
||||
},
|
||||
});
|
||||
};
|
||||
try testing.expect(@typeInfo(S.Bar) == .@"fn");
|
||||
}
|
||||
|
||||
test "empty struct assigned to reified struct field" {
|
||||
const S = struct {
|
||||
fn NamespacedComponents(comptime modules: anytype) type {
|
||||
return @Type(.{
|
||||
.@"struct" = .{
|
||||
.layout = .auto,
|
||||
.is_tuple = false,
|
||||
.fields = &.{.{
|
||||
.name = "components",
|
||||
.type = @TypeOf(modules.components),
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(@TypeOf(modules.components)),
|
||||
}},
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
return @Struct(.auto, null, &.{"components"}, &.{@TypeOf(modules.components)}, &.{.{}});
|
||||
}
|
||||
|
||||
fn namespacedComponents(comptime modules: anytype) NamespacedComponents(modules) {
|
||||
@@ -710,16 +361,6 @@ test "empty struct assigned to reified struct field" {
|
||||
});
|
||||
}
|
||||
|
||||
test "@Type should resolve its children types" {
|
||||
const sparse = enum(u2) { a, b, c };
|
||||
const dense = enum(u2) { a, b, c, d };
|
||||
|
||||
comptime var sparse_info = @typeInfo(anyerror!sparse);
|
||||
sparse_info.error_union.payload = dense;
|
||||
const B = @Type(sparse_info);
|
||||
try testing.expectEqual(anyerror!dense, B);
|
||||
}
|
||||
|
||||
test "struct field names sliced at comptime from larger string" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
@@ -729,28 +370,14 @@ test "struct field names sliced at comptime from larger string" {
|
||||
\\f3
|
||||
;
|
||||
comptime {
|
||||
var fields: []const Type.StructField = &[0]Type.StructField{};
|
||||
var field_names: []const []const u8 = &.{};
|
||||
|
||||
var it = std.mem.tokenizeScalar(u8, text, '\n');
|
||||
while (it.next()) |name| {
|
||||
fields = fields ++ &[_]Type.StructField{.{
|
||||
.alignment = @alignOf(usize),
|
||||
.name = name ++ "",
|
||||
.type = usize,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
}};
|
||||
field_names = field_names ++ @as([]const []const u8, &.{name});
|
||||
}
|
||||
|
||||
const T = @Type(.{
|
||||
.@"struct" = .{
|
||||
.layout = .auto,
|
||||
.is_tuple = false,
|
||||
.fields = fields,
|
||||
.decls = &.{},
|
||||
},
|
||||
});
|
||||
|
||||
const T = @Struct(.auto, null, field_names, &@splat(usize), &@splat(.{}));
|
||||
const gen_fields = @typeInfo(T).@"struct".fields;
|
||||
try testing.expectEqual(3, gen_fields.len);
|
||||
try testing.expectEqualStrings("f1", gen_fields[0].name);
|
||||
@@ -762,10 +389,7 @@ test "struct field names sliced at comptime from larger string" {
|
||||
test "matching captures causes opaque equivalence" {
|
||||
const S = struct {
|
||||
fn UnsignedId(comptime I: type) type {
|
||||
const U = @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = @typeInfo(I).int.bits,
|
||||
} });
|
||||
const U = @Int(.unsigned, @typeInfo(I).int.bits);
|
||||
return opaque {
|
||||
fn id(x: U) U {
|
||||
return x;
|
||||
@@ -785,17 +409,9 @@ test "matching captures causes opaque equivalence" {
|
||||
}
|
||||
|
||||
test "reify enum where fields refers to part of array" {
|
||||
const fields: [3]std.builtin.Type.EnumField = .{
|
||||
.{ .name = "foo", .value = 0 },
|
||||
.{ .name = "bar", .value = 1 },
|
||||
undefined,
|
||||
};
|
||||
const E = @Type(.{ .@"enum" = .{
|
||||
.tag_type = u8,
|
||||
.fields = fields[0..2],
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
} });
|
||||
const field_names: [3][]const u8 = .{ "foo", "bar", undefined };
|
||||
const field_values: [3]u8 = .{ undefined, 0, 1 };
|
||||
const E = @Enum(u8, .exhaustive, field_names[0..2], field_values[1..3]);
|
||||
var a: E = undefined;
|
||||
var b: E = undefined;
|
||||
a = .foo;
|
||||
|
||||
@@ -2198,14 +2198,8 @@ test "matching captures causes union equivalence" {
|
||||
fn SignedUnsigned(comptime I: type) type {
|
||||
const bits = @typeInfo(I).int.bits;
|
||||
return union {
|
||||
u: @Type(.{ .int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = bits,
|
||||
} }),
|
||||
i: @Type(.{ .int = .{
|
||||
.signedness = .signed,
|
||||
.bits = bits,
|
||||
} }),
|
||||
u: @Int(.unsigned, bits),
|
||||
i: @Int(.signed, bits),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -36,34 +36,28 @@ pub fn ChangeScalar(comptime Type: type, comptime NewScalar: type) type {
|
||||
}
|
||||
pub fn AsSignedness(comptime Type: type, comptime signedness: std.builtin.Signedness) type {
|
||||
return switch (@typeInfo(Scalar(Type))) {
|
||||
.int => |int| ChangeScalar(Type, @Type(.{ .int = .{
|
||||
.signedness = signedness,
|
||||
.bits = int.bits,
|
||||
} })),
|
||||
.int => |int| ChangeScalar(Type, @Int(signedness, int.bits)),
|
||||
.float => Type,
|
||||
else => @compileError(@typeName(Type)),
|
||||
};
|
||||
}
|
||||
pub fn AddOneBit(comptime Type: type) type {
|
||||
return ChangeScalar(Type, switch (@typeInfo(Scalar(Type))) {
|
||||
.int => |int| @Type(.{ .int = .{ .signedness = int.signedness, .bits = 1 + int.bits } }),
|
||||
.int => |int| @Int(int.signedness, 1 + int.bits),
|
||||
.float => Scalar(Type),
|
||||
else => @compileError(@typeName(Type)),
|
||||
});
|
||||
}
|
||||
pub fn DoubleBits(comptime Type: type) type {
|
||||
return ChangeScalar(Type, switch (@typeInfo(Scalar(Type))) {
|
||||
.int => |int| @Type(.{ .int = .{ .signedness = int.signedness, .bits = int.bits * 2 } }),
|
||||
.int => |int| @Int(int.signedness, int.bits * 2),
|
||||
.float => Scalar(Type),
|
||||
else => @compileError(@typeName(Type)),
|
||||
});
|
||||
}
|
||||
pub fn RoundBitsUp(comptime Type: type, comptime multiple: u16) type {
|
||||
return ChangeScalar(Type, switch (@typeInfo(Scalar(Type))) {
|
||||
.int => |int| @Type(.{ .int = .{
|
||||
.signedness = int.signedness,
|
||||
.bits = std.mem.alignForward(u16, int.bits, multiple),
|
||||
} }),
|
||||
.int => |int| @Int(int.signedness, std.mem.alignForward(u16, int.bits, multiple)),
|
||||
.float => Scalar(Type),
|
||||
else => @compileError(@typeName(Type)),
|
||||
});
|
||||
@@ -83,10 +77,7 @@ pub fn splat(comptime Type: type, scalar: Scalar(Type)) Type {
|
||||
pub fn sign(rhs: anytype) ChangeScalar(@TypeOf(rhs), bool) {
|
||||
const Int = ChangeScalar(@TypeOf(rhs), switch (@typeInfo(Scalar(@TypeOf(rhs)))) {
|
||||
.int, .comptime_int => Scalar(@TypeOf(rhs)),
|
||||
.float => |float| @Type(.{ .int = .{
|
||||
.signedness = .signed,
|
||||
.bits = float.bits,
|
||||
} }),
|
||||
.float => |float| @Int(.signed, float.bits),
|
||||
else => @compileError(@typeName(@TypeOf(rhs))),
|
||||
});
|
||||
return @as(Int, @bitCast(rhs)) < splat(Int, 0);
|
||||
|
||||
@@ -116,7 +116,7 @@ export fn testMutablePointer() void {
|
||||
// tmp.zig:85:26: note: ZON does not allow nested optionals
|
||||
// tmp.zig:90:29: error: type '*i32' is not available in ZON
|
||||
// tmp.zig:90:29: note: ZON does not allow mutable pointers
|
||||
// neg_inf.zon:1:1: error: expected type '@Type(.enum_literal)'
|
||||
// neg_inf.zon:1:1: error: expected type '@EnumLiteral()'
|
||||
// tmp.zig:37:38: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type '?u8'
|
||||
// tmp.zig:57:28: note: imported here
|
||||
|
||||
@@ -70,7 +70,7 @@ export fn testVector() void {
|
||||
// tmp.zig:22:29: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?tmp.Enum'
|
||||
// tmp.zig:28:30: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?@Type(.enum_literal)'
|
||||
// vec2.zon:1:2: error: expected type '?@EnumLiteral()'
|
||||
// tmp.zig:33:39: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?[1]u8'
|
||||
// tmp.zig:38:31: note: imported here
|
||||
|
||||
@@ -38,31 +38,11 @@ export fn i() void {
|
||||
}
|
||||
|
||||
export fn j() void {
|
||||
_ = @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &.{.{
|
||||
.name = "test",
|
||||
.type = u32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
_ = @Struct(.auto, null, &.{"test"}, &.{u32}, &.{.{ .@"align" = 0 }});
|
||||
}
|
||||
|
||||
export fn k() void {
|
||||
_ = @Type(.{ .pointer = .{
|
||||
.size = .one,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = 0,
|
||||
.address_space = .generic,
|
||||
.child = u32,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = null,
|
||||
} });
|
||||
_ = @Pointer(.one, .{ .@"align" = 0 }, u32, null);
|
||||
}
|
||||
|
||||
// error
|
||||
@@ -76,5 +56,5 @@ export fn k() void {
|
||||
// :29:17: error: alignment must be >= 1
|
||||
// :33:35: error: alignment must be >= 1
|
||||
// :37:34: error: alignment must be >= 1
|
||||
// :41:9: error: alignment must be >= 1
|
||||
// :56:9: error: alignment must be >= 1
|
||||
// :41:51: error: alignment must be >= 1
|
||||
// :45:25: error: alignment must be >= 1
|
||||
|
||||
@@ -6,4 +6,4 @@ export fn entry() void {
|
||||
|
||||
// error
|
||||
//
|
||||
// :3:10: error: expected type 'error{Hi}', found '@Type(.enum_literal)'
|
||||
// :3:10: error: expected type 'error{Hi}', found '@EnumLiteral()'
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
const builtin = @import("std").builtin;
|
||||
comptime {
|
||||
_ = @Type(.{ .float = .{ .bits = 17 } });
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :3:9: error: 17-bit float unsupported
|
||||
@@ -1,10 +0,0 @@
|
||||
export fn entry() void {
|
||||
_ = @Type(@typeInfo(enum {
|
||||
foo,
|
||||
pub const bar = 1;
|
||||
}));
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :2:9: error: reified enums must have no decls
|
||||
@@ -6,4 +6,4 @@ export fn entry() void {
|
||||
|
||||
// error
|
||||
//
|
||||
// :3:19: error: expected type 'error{Foo}', found '@Type(.enum_literal)'
|
||||
// :3:19: error: expected type 'error{Foo}', found '@EnumLiteral()'
|
||||
|
||||
@@ -9,40 +9,13 @@ export fn c() void {
|
||||
}
|
||||
|
||||
export fn d() void {
|
||||
_ = @Type(.{ .pointer = .{
|
||||
.size = .slice,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = 1,
|
||||
.address_space = .generic,
|
||||
.child = anyopaque,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = null,
|
||||
} });
|
||||
_ = @Pointer(.slice, .{}, anyopaque, null);
|
||||
}
|
||||
export fn e() void {
|
||||
_ = @Type(.{ .pointer = .{
|
||||
.size = .many,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = 1,
|
||||
.address_space = .generic,
|
||||
.child = anyopaque,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = null,
|
||||
} });
|
||||
_ = @Pointer(.many, .{}, anyopaque, null);
|
||||
}
|
||||
export fn f() void {
|
||||
_ = @Type(.{ .pointer = .{
|
||||
.size = .c,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = 1,
|
||||
.address_space = .generic,
|
||||
.child = anyopaque,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = null,
|
||||
} });
|
||||
_ = @Pointer(.c, .{}, anyopaque, null);
|
||||
}
|
||||
|
||||
// error
|
||||
@@ -51,5 +24,5 @@ export fn f() void {
|
||||
// :5:12: error: indexable pointer to opaque type 'anyopaque' not allowed
|
||||
// :8:13: error: indexable pointer to opaque type 'anyopaque' not allowed
|
||||
// :12:9: error: indexable pointer to opaque type 'anyopaque' not allowed
|
||||
// :24:9: error: indexable pointer to opaque type 'anyopaque' not allowed
|
||||
// :36:9: error: indexable pointer to opaque type 'anyopaque' not allowed
|
||||
// :15:9: error: indexable pointer to opaque type 'anyopaque' not allowed
|
||||
// :18:9: error: indexable pointer to opaque type 'anyopaque' not allowed
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
export fn entry() void {
|
||||
_ = @Type(.{ .pointer = .{
|
||||
.size = .one,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = 1,
|
||||
.address_space = .generic,
|
||||
.child = u8,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = &@as(u8, 0),
|
||||
} });
|
||||
_ = @Pointer(.one, .{}, u8, 0);
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :2:9: error: sentinels are only allowed on slices and unknown-length pointers
|
||||
// :2:33: error: sentinels are only allowed on slices and unknown-length pointers
|
||||
|
||||
@@ -36,4 +36,4 @@ const Union = union { foo: void };
|
||||
// :13:29: error: expected number, found 'tmp.Union'
|
||||
// :19:15: note: union declared here
|
||||
// :14:61: error: expected number, found 'fn () u8'
|
||||
// :15:25: error: expected number, found '@Type(.enum_literal)'
|
||||
// :15:25: error: expected number, found '@EnumLiteral()'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export fn entry() void {
|
||||
const V1 = @Vector(4, u8);
|
||||
const V2 = @Type(.{ .vector = .{ .len = 4, .child = V1 } });
|
||||
const V2 = @Vector(4, V1);
|
||||
const v: V2 = undefined;
|
||||
_ = v;
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :3:16: error: expected integer, float, bool, or pointer for the vector element type; found '@Vector(4, u8)'
|
||||
// :3:27: error: expected integer, float, bool, or pointer for the vector element type; found '@Vector(4, u8)'
|
||||
|
||||
@@ -14,4 +14,4 @@ export fn entry() usize {
|
||||
//
|
||||
// :6:12: error: unable to resolve comptime value
|
||||
// :2:12: note: called at comptime from here
|
||||
// :1:13: note: struct fields must be comptime-known
|
||||
// :1:13: note: types must be comptime-known
|
||||
|
||||
@@ -12,31 +12,10 @@ comptime {
|
||||
}
|
||||
|
||||
comptime {
|
||||
_ = @Type(.{ .array = .{ .child = S, .len = 0, .sentinel_ptr = &sentinel } });
|
||||
_ = @Pointer(.slice, .{}, S, sentinel);
|
||||
}
|
||||
comptime {
|
||||
_ = @Type(.{ .pointer = .{
|
||||
.size = .slice,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = @alignOf(S),
|
||||
.address_space = .generic,
|
||||
.child = S,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = &sentinel,
|
||||
} });
|
||||
}
|
||||
comptime {
|
||||
_ = @Type(.{ .pointer = .{
|
||||
.size = .many,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = @alignOf(S),
|
||||
.address_space = .generic,
|
||||
.child = S,
|
||||
.is_allowzero = false,
|
||||
.sentinel_ptr = &sentinel,
|
||||
} });
|
||||
_ = @Pointer(.many, .{}, S, sentinel);
|
||||
}
|
||||
|
||||
// error
|
||||
@@ -47,9 +26,7 @@ comptime {
|
||||
// :1:11: note: struct declared here
|
||||
// :11:12: error: non-scalar sentinel type 'tmp.S'
|
||||
// :1:11: note: struct declared here
|
||||
// :15:9: error: non-scalar sentinel type 'tmp.S'
|
||||
// :15:34: error: non-scalar sentinel type 'tmp.S'
|
||||
// :1:11: note: struct declared here
|
||||
// :18:9: error: non-scalar sentinel type 'tmp.S'
|
||||
// :1:11: note: struct declared here
|
||||
// :30:9: error: non-scalar sentinel type 'tmp.S'
|
||||
// :18:33: error: non-scalar sentinel type 'tmp.S'
|
||||
// :1:11: note: struct declared here
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
comptime {
|
||||
const E = @Type(.{ .@"enum" = .{
|
||||
.tag_type = u1,
|
||||
.fields = &.{
|
||||
.{ .name = "f0", .value = 0 },
|
||||
.{ .name = "f1", .value = 1 },
|
||||
.{ .name = "f2", .value = 2 },
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = true,
|
||||
} });
|
||||
const E = @Enum(u1, .exhaustive, &.{ "f0", "f1", "f2" }, &.{ 0, 1, 2 });
|
||||
_ = E;
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :2:15: error: field 'f2' with enumeration value '2' is too large for backing int type 'u1'
|
||||
// :2:72: error: type 'u1' cannot represent integer value '2'
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
export fn entry() void {
|
||||
_ = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u32,
|
||||
.fields = &.{
|
||||
.{ .name = "A", .value = 0 },
|
||||
.{ .name = "A", .value = 1 },
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = false,
|
||||
},
|
||||
});
|
||||
_ = @Enum(u32, .nonexhaustive, &.{ "A", "A" }, &.{ 0, 1 });
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :2:9: error: duplicate enum field 'A'
|
||||
// :2:9: note: other field here
|
||||
// :2:36: error: duplicate enum field 'A'
|
||||
// :2:36: note: other field here
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
export fn entry() void {
|
||||
_ = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = u32,
|
||||
.fields = &.{
|
||||
.{ .name = "A", .value = 10 },
|
||||
.{ .name = "B", .value = 10 },
|
||||
},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = false,
|
||||
},
|
||||
});
|
||||
_ = @Enum(u32, .nonexhaustive, &.{ "A", "B" }, &.{ 10, 10 });
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :2:9: error: enum tag value 10 already taken
|
||||
// :2:9: note: other enum tag value here
|
||||
// :2:52: error: enum tag value 10 already taken
|
||||
// :2:52: note: other enum tag value here
|
||||
|
||||
@@ -1,79 +1,16 @@
|
||||
comptime {
|
||||
@Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &.{.{
|
||||
.name = "foo",
|
||||
.type = u32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = 4,
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = true,
|
||||
} });
|
||||
@Struct(.auto, null, &.{"foo"}, &.{u32}, &.{.{ .@"comptime" = true }});
|
||||
}
|
||||
comptime {
|
||||
@Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &.{.{
|
||||
.name = "3",
|
||||
.type = u32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = 4,
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = true,
|
||||
} });
|
||||
@Struct(.@"extern", null, &.{"foo"}, &.{u32}, &.{.{ .@"comptime" = true, .default_value_ptr = &@as(u32, 10) }});
|
||||
}
|
||||
comptime {
|
||||
@Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &.{.{
|
||||
.name = "0",
|
||||
.type = u32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = true,
|
||||
.alignment = 4,
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = true,
|
||||
} });
|
||||
}
|
||||
comptime {
|
||||
@Type(.{ .@"struct" = .{
|
||||
.layout = .@"extern",
|
||||
.fields = &.{.{
|
||||
.name = "0",
|
||||
.type = u32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = true,
|
||||
.alignment = 4,
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
}
|
||||
comptime {
|
||||
@Type(.{ .@"struct" = .{
|
||||
.layout = .@"packed",
|
||||
.fields = &.{.{
|
||||
.name = "0",
|
||||
.type = u32,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = true,
|
||||
.alignment = 4,
|
||||
}},
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
@Struct(.@"packed", null, &.{"foo"}, &.{u32}, &.{.{ .@"align" = 4 }});
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :2:5: error: tuple cannot have non-numeric field 'foo'
|
||||
// :16:5: error: tuple field name '3' does not match field index 0
|
||||
// :30:5: error: comptime field without default initialization value
|
||||
// :44:5: error: extern struct fields cannot be marked comptime
|
||||
// :58:5: error: alignment of a packed struct field must be set to 0
|
||||
// :2:46: error: comptime field without default initialization value
|
||||
// :5:51: error: extern struct fields cannot be marked comptime
|
||||
// :8:51: error: packed struct fields cannot be aligned
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
const Foo = @Type(.{
|
||||
.@"fn" = .{
|
||||
.calling_convention = .auto,
|
||||
.is_generic = true,
|
||||
.is_var_args = false,
|
||||
.return_type = u0,
|
||||
.params = &.{},
|
||||
},
|
||||
});
|
||||
comptime {
|
||||
_ = Foo;
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :1:13: error: Type.Fn.is_generic must be false for @Type
|
||||
+3
-12
@@ -1,18 +1,9 @@
|
||||
const Foo = @Type(.{
|
||||
.@"fn" = .{
|
||||
.calling_convention = .auto,
|
||||
.is_generic = false,
|
||||
.is_var_args = true,
|
||||
.return_type = u0,
|
||||
.params = &.{},
|
||||
},
|
||||
});
|
||||
comptime {
|
||||
_ = Foo;
|
||||
_ = @Fn(&.{u32}, &.{.{}}, u8, .{ .varargs = true });
|
||||
}
|
||||
|
||||
// error
|
||||
// target=x86_64-linux
|
||||
//
|
||||
// :1:13: error: variadic function does not support 'auto' calling convention
|
||||
// :1:13: note: supported calling conventions: 'x86_64_sysv', 'x86_64_x32', 'x86_64_win'
|
||||
// :2:36: error: variadic function does not support 'auto' calling convention
|
||||
// :2:36: note: supported calling conventions: 'x86_64_sysv', 'x86_64_x32', 'x86_64_win'
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
const Foo = @Type(.{
|
||||
.@"fn" = .{
|
||||
.calling_convention = .auto,
|
||||
.is_generic = false,
|
||||
.is_var_args = false,
|
||||
.return_type = null,
|
||||
.params = &.{},
|
||||
},
|
||||
});
|
||||
comptime {
|
||||
_ = Foo;
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :1:13: error: Type.Fn.return_type must be non-null for @Type
|
||||
+2
-9
@@ -1,15 +1,8 @@
|
||||
const Tag = @Type(.{
|
||||
.@"enum" = .{
|
||||
.tag_type = bool,
|
||||
.fields = &.{},
|
||||
.decls = &.{},
|
||||
.is_exhaustive = false,
|
||||
},
|
||||
});
|
||||
const Tag = @Enum(bool, .nonexhaustive, &.{}, &.{});
|
||||
export fn entry() void {
|
||||
_ = @as(Tag, @enumFromInt(0));
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :1:13: error: Type.Enum.tag_type must be an integer type
|
||||
// :1:19: error: tag type must be an integer type
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user