diff --git a/doc/langref.html.in b/doc/langref.html.in index 5c6943c9f4..c0272124ca 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -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#}.
- {#see_also|Integers|Floats|void|Errors|@Type#} + {#see_also|Integers|Floats|void|Errors|@Int#} {#header_close#} {#header_open|Primitive Values#}{#syntax#}@Type(comptime info: std.builtin.Type) type{#endsyntax#}
- - This function is the inverse of {#link|@typeInfo#}. It reifies type information - into a {#syntax#}type{#endsyntax#}. -
-- It is available for the following types: -
-{#syntax#}@EnumLiteral() type{#endsyntax#}
+ 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.
{#header_close#} + + {#header_open|@Int#} +{#syntax#}@Int(comptime signedness: std.builtin.Signedness, comptime bits: u16) type{#endsyntax#}
+ Returns an integer type with the given signedness and bit width.
+For instance, {#syntax#}@Int(.unsigned, 18){#endsyntax#} returns the type {#syntax#}u18{#endsyntax#}.
+ {#header_close#} + + {#header_open|@Tuple#} +{#syntax#}@Tuple(comptime field_types: []const type) type{#endsyntax#}
+ Returns a {#link|tuple|Tuples#} type with the given field types.
+ {#header_close#} + + {#header_open|@Pointer#} +{#syntax#}@Pointer(
+ comptime size: std.builtin.Type.Pointer.Size,
+ comptime attrs: std.builtin.Type.Pointer.Attributes,
+ comptime Element: type,
+ comptime sentinel: ?Element,
+) type{#endsyntax#}
+ Returns a {#link|pointer|Pointers#} type with the properties specified by the arguments.
+ {#header_close#} + + {#header_open|@Fn#} +{#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#}
+ Returns a {#link|function|Functions#} type with the properties specified by the arguments.
+ {#header_close#} + + {#header_open|@Struct#} +{#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#}
+ Returns a {#link|struct#} type with the properties specified by the arguments.
+ {#header_close#} + + {#header_open|@Union#} +{#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#}
+ Returns a {#link|union#} type with the properties specified by the arguments.
+ {#header_close#} + + {#header_open|@Enum#} +{#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#}
+ Returns an {#link|enum#} type with the properties specified by the arguments.
+ {#header_close#} + {#header_open|@typeInfo#}{#syntax#}@typeInfo(comptime T: type) std.builtin.Type{#endsyntax#}
diff --git a/doc/langref/std_options.zig b/doc/langref/std_options.zig index b37d407fc8..f996e44de6 100644 --- a/doc/langref/std_options.zig +++ b/doc/langref/std_options.zig @@ -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 { diff --git a/doc/langref/test_coerce_unions_enums.zig b/doc/langref/test_coerce_unions_enums.zig index 9879b3dab7..0a782b4c54 100644 --- a/doc/langref/test_coerce_unions_enums.zig +++ b/doc/langref/test_coerce_unions_enums.zig @@ -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); } diff --git a/lib/build-web/main.zig b/lib/build-web/main.zig index 6a91b5325b..e71c47707b 100644 --- a/lib/build-web/main.zig +++ b/lib/build-web/main.zig @@ -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 { diff --git a/lib/compiler/aro/aro/Attribute.zig b/lib/compiler/aro/aro/Attribute.zig index db34a3eec1..7ff4f06ac1 100644 --- a/lib/compiler/aro/aro/Attribute.zig +++ b/lib/compiler/aro/aro/Attribute.zig @@ -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 { diff --git a/lib/compiler/aro/assembly_backend/x86_64.zig b/lib/compiler/aro/assembly_backend/x86_64.zig index 6a6ea9e0e7..ff106e9d8b 100644 --- a/lib/compiler/aro/assembly_backend/x86_64.zig +++ b/lib/compiler/aro/assembly_backend/x86_64.zig @@ -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); }, diff --git a/lib/compiler/resinator/code_pages.zig b/lib/compiler/resinator/code_pages.zig index 53cbdb768c..4f4544ff02 100644 --- a/lib/compiler/resinator/code_pages.zig +++ b/lib/compiler/resinator/code_pages.zig @@ -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 { diff --git a/lib/compiler/resinator/errors.zig b/lib/compiler/resinator/errors.zig index f9ccc43a7f..0060990ab6 100644 --- a/lib/compiler/resinator/errors.zig +++ b/lib/compiler/resinator/errors.zig @@ -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 { diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 682c4fda08..72ed3e7677 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -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 { diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index 8b66e7cc26..d74eab18d8 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -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); diff --git a/lib/compiler_rt/float_from_int.zig b/lib/compiler_rt/float_from_int.zig index 98659d275b..9ce43b4d70 100644 --- a/lib/compiler_rt/float_from_int.zig +++ b/lib/compiler_rt/float_from_int.zig @@ -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; diff --git a/lib/compiler_rt/int_from_float.zig b/lib/compiler_rt/int_from_float.zig index 83de968a2e..1f1cdb215f 100644 --- a/lib/compiler_rt/int_from_float.zig +++ b/lib/compiler_rt/int_from_float.zig @@ -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) + diff --git a/lib/compiler_rt/memcpy.zig b/lib/compiler_rt/memcpy.zig index 82a032d3e9..4dcd184d29 100644 --- a/lib/compiler_rt/memcpy.zig +++ b/lib/compiler_rt/memcpy.zig @@ -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)); diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index adf3f6b884..2a093886f5 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -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 { diff --git a/lib/fuzzer.zig b/lib/fuzzer.zig index caf1cbc6fb..3a48360bf8 100644 --- a/lib/fuzzer.zig +++ b/lib/fuzzer.zig @@ -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 { diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 3b78fc6f71..25d1ff6d95 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -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; diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 8c552ad8fe..114f748199 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -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, diff --git a/lib/std/Io/Reader.zig b/lib/std/Io/Reader.zig index 56a70f0781..78963dcdab 100644 --- a/lib/std/Io/Reader.zig +++ b/lib/std/Io/Reader.zig @@ -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) { diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index d44800cd60..1b80b5b4f7 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -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; diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 7b60289edf..1ef77de9a5 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -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, }; }; diff --git a/lib/std/crypto/phc_encoding.zig b/lib/std/crypto/phc_encoding.zig index 6812f3f8ae..44651464f1 100644 --- a/lib/std/crypto/phc_encoding.zig +++ b/lib/std/crypto/phc_encoding.zig @@ -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; diff --git a/lib/std/crypto/tls.zig b/lib/std/crypto/tls.zig index af548cf0fb..c24283469c 100644 --- a/lib/std/crypto/tls.zig +++ b/lib/std/crypto/tls.zig @@ -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, diff --git a/lib/std/enums.zig b/lib/std/enums.zig index e47af4aca3..ffc678d772 100644 --- a/lib/std/enums.zig +++ b/lib/std/enums.zig @@ -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)); diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 2dc7e13855..f9d8ffed5d 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -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 }; } diff --git a/lib/std/fmt/float.zig b/lib/std/fmt/float.zig index 16df95ad28..44a71f90f4 100644 --- a/lib/std/fmt/float.zig +++ b/lib/std/fmt/float.zig @@ -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); diff --git a/lib/std/hash.zig b/lib/std/hash.zig index 781971bd13..e8d2aa85b1 100644 --- a/lib/std/hash.zig +++ b/lib/std/hash.zig @@ -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 diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 59099c1a7d..a4fa8054e6 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -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) }); diff --git a/lib/std/log.zig b/lib/std/log.zig index 51b01fe47f..9568f9ba52 100644 --- a/lib/std/log.zig +++ b/lib/std/log.zig @@ -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 diff --git a/lib/std/math.zig b/lib/std/math.zig index c1b489a41d..21611799fd 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -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 diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index bb6deeb778..eee6a0c7ce 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -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))); } diff --git a/lib/std/math/float.zig b/lib/std/math/float.zig index 6ffbd85bd2..39ef854b5b 100644 --- a/lib/std/math/float.zig +++ b/lib/std/math/float.zig @@ -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); diff --git a/lib/std/math/log2.zig b/lib/std/math/log2.zig index f5f0cf771e..31b5e8283d 100644 --- a/lib/std/math/log2.zig +++ b/lib/std/math/log2.zig @@ -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)), diff --git a/lib/std/math/log_int.zig b/lib/std/math/log_int.zig index 96227639d0..6a4318e1da 100644 --- a/lib/std/math/log_int.zig +++ b/lib/std/math/log_int.zig @@ -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; diff --git a/lib/std/math/signbit.zig b/lib/std/math/signbit.zig index 2b50d0cbd9..7c0ea05d74 100644 --- a/lib/std/math/signbit.zig +++ b/lib/std/math/signbit.zig @@ -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; diff --git a/lib/std/math/sqrt.zig b/lib/std/math/sqrt.zig index 0753277bb7..b91e94987e 100644 --- a/lib/std/math/sqrt.zig +++ b/lib/std/math/sqrt.zig @@ -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, }; } diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 01dbac73a0..5c1c4f4394 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -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, diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 5d022ecffa..77e288ecaa 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -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 { diff --git a/lib/std/meta/trailer_flags.zig b/lib/std/meta/trailer_flags.zig index ddf3790c19..44a5258a14 100644 --- a/lib/std/meta/trailer_flags.zig +++ b/lib/std/meta/trailer_flags.zig @@ -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(); diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index ec4b0b72e1..958cca30a2 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -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 { diff --git a/lib/std/std.zig b/lib/std/std.zig index 1b8142ce4c..5c500d3f55 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -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, diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 4c0203b83d..c8a0dcde3b 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -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", diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index c7d7f24938..ac72d395cf 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -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, diff --git a/lib/std/zig/AstRlAnnotate.zig b/lib/std/zig/AstRlAnnotate.zig index 5beb6fec73..c7e9abf2bb 100644 --- a/lib/std/zig/AstRlAnnotate.zig +++ b/lib/std/zig/AstRlAnnotate.zig @@ -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); diff --git a/lib/std/zig/BuiltinFn.zig b/lib/std/zig/BuiltinFn.zig index 5ef28fdfaf..cdc63f9666 100644 --- a/lib/std/zig/BuiltinFn.zig +++ b/lib/std/zig/BuiltinFn.zig @@ -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", .{ diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 7a1069fe7d..08770def8d 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -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 }, diff --git a/lib/std/zig/c_translation/helpers.zig b/lib/std/zig/c_translation/helpers.zig index 5f6a5561df..7d3534bffe 100644 --- a/lib/std/zig/c_translation/helpers.zig +++ b/lib/std/zig/c_translation/helpers.zig @@ -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)))) diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 0f01748bbf..587ac82c70 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -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( diff --git a/src/Air.zig b/src/Air.zig index e210ab17b8..b5cb950d49 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -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), diff --git a/src/InternPool.zig b/src/InternPool.zig index e2912f2c69..302e71a2b1 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -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", diff --git a/src/Sema.zig b/src/Sema.zig index 51273d8812..2ca75e1574 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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, diff --git a/src/Type.zig b/src/Type.zig index 74a540298c..3d3b36640c 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -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 }; diff --git a/src/Value.zig b/src/Value.zig index 9ced6f1074..930f94a5a3 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -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, } } diff --git a/src/Zcu.zig b/src/Zcu.zig index f15b03dc1a..c170ef6d71 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -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, diff --git a/src/codegen/aarch64/Assemble.zig b/src/codegen/aarch64/Assemble.zig index 5cf9c2da3c..e6b2189b7b 100644 --- a/src/codegen/aarch64/Assemble.zig +++ b/src/codegen/aarch64/Assemble.zig @@ -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; }; diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 93cb987820..f390d83f03 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -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(), diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig index f575a40197..fb37b60580 100644 --- a/src/codegen/c/Type.zig +++ b/src/codegen/c/Type.zig @@ -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, diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index 80798969eb..99d768805f 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -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, diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig index 18846aaf99..15f142c4a7 100644 --- a/src/codegen/x86_64/Emit.zig +++ b/src/codegen/x86_64/Emit.zig @@ -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, diff --git a/src/link.zig b/src/link.zig index 31ba3aca7d..6be88490b0 100644 --- a/src/link.zig +++ b/src/link.zig @@ -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 { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 1fd1840da7..95f4ca8bbd 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -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, } } diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig index 09d940e85f..e189a1df94 100644 --- a/src/link/MappedFile.zig +++ b/src/link/MappedFile.zig @@ -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) { diff --git a/src/main.zig b/src/main.zig index 21bbecea4a..8199f2d405 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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 { diff --git a/src/print_zir.zig b/src/print_zir.zig index d263db9f33..316632f2d3 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -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), diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index 40c744b1fa..0c68522efc 100644 Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index d704151aa6..5bd7326460 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -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); } diff --git a/test/behavior/bit_shifting.zig b/test/behavior/bit_shifting.zig index 42d3e982d7..74bd8690b4 100644 --- a/test/behavior/bit_shifting.zig +++ b/test/behavior/bit_shifting.zig @@ -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); diff --git a/test/behavior/call.zig b/test/behavior/call.zig index e4d09c7fa1..3433cc5971 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -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, diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 2155c6eb27..4796c0c7ae 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -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"); diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 175449b566..6ec436b70d 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -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) { _ }; } }; diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 677a47a104..358ca7b629 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -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; } }; diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 962148e1b4..65a5a1b007 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -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(); diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig index 4ce2d3a24e..a6087787b5 100644 --- a/test/behavior/sizeof_and_typeof.zig +++ b/test/behavior/sizeof_and_typeof.zig @@ -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 }, &.{ .{}, .{}, .{} }))); } } } diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 03a49b70d1..6ac60c2251 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -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), }; } }; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 170e8d9778..d184bbc47d 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -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); diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 1d82957d39..8dfbf9775c 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -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 => { diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index cc9a711f20..a88a99171b 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -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); } diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 0bb3de6f97..411a77f9e5 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -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; diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 115c43fbd8..7771f57bea 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -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), }; } }; diff --git a/test/behavior/x86_64/math.zig b/test/behavior/x86_64/math.zig index 5f0473e0d5..5662a09c77 100644 --- a/test/behavior/x86_64/math.zig +++ b/test/behavior/x86_64/math.zig @@ -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); diff --git a/test/cases/compile_errors/@import_zon_bad_type.zig b/test/cases/compile_errors/@import_zon_bad_type.zig index 7f8f718a74..9fe3c88721 100644 --- a/test/cases/compile_errors/@import_zon_bad_type.zig +++ b/test/cases/compile_errors/@import_zon_bad_type.zig @@ -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 diff --git a/test/cases/compile_errors/@import_zon_opt_in_err.zig b/test/cases/compile_errors/@import_zon_opt_in_err.zig index b7322a43b4..29cf412eab 100644 --- a/test/cases/compile_errors/@import_zon_opt_in_err.zig +++ b/test/cases/compile_errors/@import_zon_opt_in_err.zig @@ -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 diff --git a/test/cases/compile_errors/align_zero.zig b/test/cases/compile_errors/align_zero.zig index e54a32ce31..632d146dc5 100644 --- a/test/cases/compile_errors/align_zero.zig +++ b/test/cases/compile_errors/align_zero.zig @@ -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 diff --git a/test/cases/compile_errors/attempt_to_cast_enum_literal_to_error.zig b/test/cases/compile_errors/attempt_to_cast_enum_literal_to_error.zig index fa71a420a6..31f41b57a4 100644 --- a/test/cases/compile_errors/attempt_to_cast_enum_literal_to_error.zig +++ b/test/cases/compile_errors/attempt_to_cast_enum_literal_to_error.zig @@ -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()' diff --git a/test/cases/compile_errors/attempt_to_create_17_bit_float_type.zig b/test/cases/compile_errors/attempt_to_create_17_bit_float_type.zig deleted file mode 100644 index cf9e5824c9..0000000000 --- a/test/cases/compile_errors/attempt_to_create_17_bit_float_type.zig +++ /dev/null @@ -1,8 +0,0 @@ -const builtin = @import("std").builtin; -comptime { - _ = @Type(.{ .float = .{ .bits = 17 } }); -} - -// error -// -// :3:9: error: 17-bit float unsupported diff --git a/test/cases/compile_errors/enum_with_declarations_unavailable_for_reify_type.zig b/test/cases/compile_errors/enum_with_declarations_unavailable_for_reify_type.zig deleted file mode 100644 index 8ac082349a..0000000000 --- a/test/cases/compile_errors/enum_with_declarations_unavailable_for_reify_type.zig +++ /dev/null @@ -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 diff --git a/test/cases/compile_errors/error_set_decl_literal.zig b/test/cases/compile_errors/error_set_decl_literal.zig index abb22f189f..067629feec 100644 --- a/test/cases/compile_errors/error_set_decl_literal.zig +++ b/test/cases/compile_errors/error_set_decl_literal.zig @@ -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()' diff --git a/test/cases/compile_errors/invalid_pointer_to_opaque.zig b/test/cases/compile_errors/invalid_pointer_to_opaque.zig index 8b80b2eb25..ed7bf69063 100644 --- a/test/cases/compile_errors/invalid_pointer_to_opaque.zig +++ b/test/cases/compile_errors/invalid_pointer_to_opaque.zig @@ -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 diff --git a/test/cases/compile_errors/invalid_pointer_with_reify_type.zig b/test/cases/compile_errors/invalid_pointer_with_reify_type.zig index c1f622c1a5..5b7c5834d2 100644 --- a/test/cases/compile_errors/invalid_pointer_with_reify_type.zig +++ b/test/cases/compile_errors/invalid_pointer_with_reify_type.zig @@ -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 diff --git a/test/cases/compile_errors/minmax_nonnumeric_operand.zig b/test/cases/compile_errors/minmax_nonnumeric_operand.zig index 57e939f134..cf8856a059 100644 --- a/test/cases/compile_errors/minmax_nonnumeric_operand.zig +++ b/test/cases/compile_errors/minmax_nonnumeric_operand.zig @@ -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()' diff --git a/test/cases/compile_errors/nested_vectors.zig b/test/cases/compile_errors/nested_vectors.zig index e59847e4e9..a43f60afe1 100644 --- a/test/cases/compile_errors/nested_vectors.zig +++ b/test/cases/compile_errors/nested_vectors.zig @@ -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)' diff --git a/test/cases/compile_errors/non_constant_expression_in_array_size.zig b/test/cases/compile_errors/non_constant_expression_in_array_size.zig index 72f5e5c1fd..0f64e1263b 100644 --- a/test/cases/compile_errors/non_constant_expression_in_array_size.zig +++ b/test/cases/compile_errors/non_constant_expression_in_array_size.zig @@ -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 diff --git a/test/cases/compile_errors/non_scalar_sentinel.zig b/test/cases/compile_errors/non_scalar_sentinel.zig index c2d8bced8d..5678053300 100644 --- a/test/cases/compile_errors/non_scalar_sentinel.zig +++ b/test/cases/compile_errors/non_scalar_sentinel.zig @@ -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 diff --git a/test/cases/compile_errors/reified_enum_field_value_overflow.zig b/test/cases/compile_errors/reified_enum_field_value_overflow.zig index c28ae3f5fc..ded9acd40d 100644 --- a/test/cases/compile_errors/reified_enum_field_value_overflow.zig +++ b/test/cases/compile_errors/reified_enum_field_value_overflow.zig @@ -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' diff --git a/test/cases/compile_errors/reify_enum_with_duplicate_field.zig b/test/cases/compile_errors/reify_enum_with_duplicate_field.zig index 77bfe56f17..73df5e1a86 100644 --- a/test/cases/compile_errors/reify_enum_with_duplicate_field.zig +++ b/test/cases/compile_errors/reify_enum_with_duplicate_field.zig @@ -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 diff --git a/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig b/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig index 8ab4c1d766..6343782ca7 100644 --- a/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig +++ b/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig @@ -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 diff --git a/test/cases/compile_errors/reify_struct.zig b/test/cases/compile_errors/reify_struct.zig index 60228061dd..690b724e12 100644 --- a/test/cases/compile_errors/reify_struct.zig +++ b/test/cases/compile_errors/reify_struct.zig @@ -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 diff --git a/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig deleted file mode 100644 index d34043390d..0000000000 --- a/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig +++ /dev/null @@ -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 diff --git a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig index f74b89ae87..a4d109b211 100644 --- a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig @@ -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' diff --git a/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig deleted file mode 100644 index 2438aa443c..0000000000 --- a/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig +++ /dev/null @@ -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 diff --git a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig index ad4cae5588..d74e0b2b53 100644 --- a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig @@ -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 diff --git a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig index 2bf144b52d..1fbdab25ea 100644 --- a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig +++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_undefined_tag_type.zig @@ -1,15 +1,8 @@ -const Tag = @Type(.{ - .@"enum" = .{ - .tag_type = undefined, - .fields = &.{}, - .decls = &.{}, - .is_exhaustive = false, - }, -}); +const Tag = @Enum(undefined, .exhaustive, &.{}, &.{}); export fn entry() void { _ = @as(Tag, @enumFromInt(0)); } // error // -// :1:20: error: use of undefined value here causes illegal behavior +// :1:19: error: use of undefined value here causes illegal behavior diff --git a/test/cases/compile_errors/reify_type_for_tagged_extern_union.zig b/test/cases/compile_errors/reify_type_for_tagged_extern_union.zig index a4ee133467..0313575bcd 100644 --- a/test/cases/compile_errors/reify_type_for_tagged_extern_union.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_extern_union.zig @@ -1,26 +1,5 @@ -const Tag = @Type(.{ - .@"enum" = .{ - .tag_type = u2, - .fields = &.{ - .{ .name = "signed", .value = 0 }, - .{ .name = "unsigned", .value = 1 }, - }, - .decls = &.{}, - .is_exhaustive = true, - }, -}); - -const Extern = @Type(.{ - .@"union" = .{ - .layout = .@"extern", - .tag_type = Tag, - .fields = &.{ - .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) }, - .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) }, - }, - .decls = &.{}, - }, -}); +const Tag = @Enum(u2, .exhaustive, &.{ "signed", "unsigned" }, &.{ 0, 1 }); +const Extern = @Union(.@"extern", Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{})); export fn entry() void { const tagged: Extern = .{ .signed = -1 }; @@ -29,4 +8,4 @@ export fn entry() void { // error // -// :13:16: error: extern union does not support enum tag type +// :2:35: error: extern union does not support enum tag type diff --git a/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig b/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig index 1a50418628..f602771bc6 100644 --- a/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig @@ -1,26 +1,5 @@ -const Tag = @Type(.{ - .@"enum" = .{ - .tag_type = u2, - .fields = &.{ - .{ .name = "signed", .value = 0 }, - .{ .name = "unsigned", .value = 1 }, - }, - .decls = &.{}, - .is_exhaustive = true, - }, -}); - -const Packed = @Type(.{ - .@"union" = .{ - .layout = .@"packed", - .tag_type = Tag, - .fields = &.{ - .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) }, - .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) }, - }, - .decls = &.{}, - }, -}); +const Tag = @Enum(u2, .exhaustive, &.{ "signed", "unsigned" }, &.{ 0, 1 }); +const Packed = @Union(.@"packed", Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{})); export fn entry() void { const tagged: Packed = .{ .signed = -1 }; @@ -29,4 +8,4 @@ export fn entry() void { // error // -// :13:16: error: packed union does not support enum tag type +// :2:35: error: packed union does not support enum tag type diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig index 4e78b5f217..5b56a98eb3 100644 --- a/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig @@ -1,26 +1,5 @@ -const Tag = @Type(.{ - .@"enum" = .{ - .tag_type = u2, - .fields = &.{ - .{ .name = "signed", .value = 0 }, - .{ .name = "unsigned", .value = 1 }, - .{ .name = "arst", .value = 2 }, - }, - .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(u2, .exhaustive, &.{ "signed", "unsigned", "arst" }, &.{ 0, 1, 2 }); +const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{})); export fn entry() void { var tagged = Tagged{ .signed = -1 }; tagged = .{ .unsigned = 1 }; @@ -28,6 +7,6 @@ export fn entry() void { // error // -// :13:16: error: enum fields missing in union +// :2:35: error: 1 enum fields missing in union // :1:13: note: field 'arst' missing, declared here // :1:13: note: enum declared here diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig index 212ff87e87..b3fbe9f747 100644 --- a/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig @@ -1,26 +1,5 @@ -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) }, - .{ .name = "arst", .type = f32, .alignment = @alignOf(f32) }, - }, - .decls = &.{}, - }, -}); +const Tag = @Enum(u1, .exhaustive, &.{ "signed", "unsigned" }, &.{ 0, 1 }); +const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned", "arst" }, &.{ i32, u32, f32 }, &@splat(.{})); export fn entry() void { var tagged = Tagged{ .signed = -1 }; tagged = .{ .unsigned = 1 }; @@ -28,5 +7,5 @@ export fn entry() void { // error // -// :12:16: error: no field named 'arst' in enum 'tmp.Tag' +// :2:35: error: no field named 'arst' in enum 'tmp.Tag' // :1:13: note: enum declared here diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig index 688a48fe53..e9c27b7eea 100644 --- a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig @@ -1,22 +1,5 @@ -const Tag = @Type(.{ - .@"enum" = .{ - .tag_type = u0, - .fields = &.{}, - .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(u0, .exhaustive, &.{}, &.{}); +const Tagged = @Union(.auto, Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{})); export fn entry() void { const tagged: Tagged = undefined; _ = tagged; @@ -24,5 +7,5 @@ export fn entry() void { // error // -// :9:16: error: no field named 'signed' in enum 'tmp.Tag' +// :2:35: error: no field named 'signed' in enum 'tmp.Tag' // :1:13: note: enum declared here diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig index ce721d39e3..245bd472cc 100644 --- a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig @@ -1,22 +1,5 @@ -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 = &.{}, - .decls = &.{}, - }, -}); +const Tag = @Enum(u1, .exhaustive, &.{ "signed", "unsigned" }, &.{ 0, 1 }); +const Tagged = @Union(.auto, Tag, &.{}, &.{}, &.{}); export fn entry() void { const tagged: Tagged = undefined; _ = tagged; @@ -24,7 +7,7 @@ export fn entry() void { // error // -// :12:16: error: enum fields missing in union +// :2:35: error: 2 enum fields missing in union // :1:13: note: field 'signed' missing, declared here // :1:13: note: field 'unsigned' missing, declared here // :1:13: note: enum declared here diff --git a/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig b/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig index d79bac4ba4..e2be15f1a4 100644 --- a/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig +++ b/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig @@ -1,18 +1,9 @@ -const Untagged = @Type(.{ - .@"union" = .{ - .layout = .auto, - .tag_type = null, - .fields = &.{ - .{ .name = "foo", .type = opaque {}, .alignment = 1 }, - }, - .decls = &.{}, - }, -}); +const Untagged = @Union(.auto, null, &.{"foo"}, &.{opaque {}}, &.{.{}}); export fn entry() usize { return @sizeOf(Untagged); } // error // -// :1:18: error: opaque types have unknown size and therefore cannot be directly embedded in unions -// :6:39: note: opaque declared here +// :1:49: error: opaque types have unknown size and therefore cannot be directly embedded in unions +// :1:52: note: opaque declared here diff --git a/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig b/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig deleted file mode 100644 index 8d80a3353d..0000000000 --- a/test/cases/compile_errors/reify_type_union_payload_is_undefined.zig +++ /dev/null @@ -1,10 +0,0 @@ -const Foo = @Type(.{ - .@"struct" = undefined, -}); -comptime { - _ = Foo; -} - -// error -// -// :1:20: error: use of undefined value here causes illegal behavior diff --git a/test/cases/compile_errors/reify_type_with_Type.Int.zig b/test/cases/compile_errors/reify_type_with_Type.Int.zig deleted file mode 100644 index 9673b24410..0000000000 --- a/test/cases/compile_errors/reify_type_with_Type.Int.zig +++ /dev/null @@ -1,13 +0,0 @@ -const builtin = @import("std").builtin; -export fn entry() void { - _ = @Type(builtin.Type.Int{ - .signedness = .signed, - .bits = 8, - }); -} - -// error -// -// :3:31: error: expected type 'builtin.Type', found 'builtin.Type.Int' -// :?:?: note: struct declared here -// :?:?: note: union declared here diff --git a/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig b/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig index a04f3e957c..e6b9e1435a 100644 --- a/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig +++ b/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig @@ -1,48 +1,15 @@ comptime { - _ = @Type(.{ - .@"union" = .{ - .layout = .auto, - .tag_type = null, - .fields = &.{ - .{ .name = "foo", .type = usize, .alignment = 3 }, - }, - .decls = &.{}, - }, - }); + _ = @Union(.auto, null, &.{"foo"}, &.{usize}, &.{.{ .@"align" = 3 }}); } comptime { - _ = @Type(.{ - .@"struct" = .{ - .layout = .auto, - .fields = &.{.{ - .name = "0", - .type = u32, - .default_value_ptr = null, - .is_comptime = true, - .alignment = 5, - }}, - .decls = &.{}, - .is_tuple = false, - }, - }); + _ = @Struct(.auto, null, &.{"a"}, &.{u32}, &.{.{ .@"comptime" = true, .@"align" = 5 }}); } comptime { - _ = @Type(.{ - .pointer = .{ - .size = .many, - .is_const = true, - .is_volatile = false, - .alignment = 7, - .address_space = .generic, - .child = u8, - .is_allowzero = false, - .sentinel_ptr = null, - }, - }); + _ = @Pointer(.many, .{ .@"align" = 7 }, u8, null); } // error // -// :2:9: error: alignment value '3' is not a power of two -// :14:9: error: alignment value '5' is not a power of two -// :30:9: error: alignment value '7' is not a power of two +// :2:51: error: alignment value '3' is not a power of two +// :5:48: error: alignment value '5' is not a power of two +// :8:26: error: alignment value '7' is not a power of two diff --git a/test/cases/compile_errors/reify_type_with_undefined.zig b/test/cases/compile_errors/reify_type_with_undefined.zig index 5c476c94aa..d489c3f604 100644 --- a/test/cases/compile_errors/reify_type_with_undefined.zig +++ b/test/cases/compile_errors/reify_type_with_undefined.zig @@ -1,31 +1,11 @@ comptime { - _ = @Type(.{ .array = .{ .len = 0, .child = u8, .sentinel_ptr = undefined } }); + _ = @Struct(.auto, null, &.{}, &.{}, undefined); } comptime { - _ = @Type(.{ - .@"struct" = .{ - .fields = undefined, - .decls = undefined, - .is_tuple = false, - .layout = .auto, - }, - }); -} -comptime { - const std = @import("std"); - const fields: [1]std.builtin.Type.StructField = undefined; - _ = @Type(.{ - .@"struct" = .{ - .layout = .auto, - .fields = &fields, - .decls = &.{}, - .is_tuple = false, - }, - }); + _ = @Struct(.auto, null, &.{"foo"}, &.{undefined}, &.{.{}}); } // error // -// :2:16: error: use of undefined value here causes illegal behavior -// :5:16: error: use of undefined value here causes illegal behavior -// :17:16: error: use of undefined value here causes illegal behavior +// :2:42: error: use of undefined value here causes illegal behavior +// :5:41: error: use of undefined value here causes illegal behavior diff --git a/test/cases/compile_errors/runtime_condition_comptime_type_in_destructure.zig b/test/cases/compile_errors/runtime_condition_comptime_type_in_destructure.zig index 27b13e2150..144cc18545 100644 --- a/test/cases/compile_errors/runtime_condition_comptime_type_in_destructure.zig +++ b/test/cases/compile_errors/runtime_condition_comptime_type_in_destructure.zig @@ -7,4 +7,4 @@ export fn foobar() void { // error // -// :4:5: error: value with comptime-only type '@Type(.enum_literal)' depends on runtime control flow +// :4:5: error: value with comptime-only type '@EnumLiteral()' depends on runtime control flow diff --git a/test/cases/compile_errors/struct_with_declarations_unavailable_for_reify_type.zig b/test/cases/compile_errors/struct_with_declarations_unavailable_for_reify_type.zig deleted file mode 100644 index 068211fdc4..0000000000 --- a/test/cases/compile_errors/struct_with_declarations_unavailable_for_reify_type.zig +++ /dev/null @@ -1,9 +0,0 @@ -export fn entry() void { - _ = @Type(@typeInfo(struct { - pub const foo = 1; - })); -} - -// error -// -// :2:9: error: reified structs must have no decls diff --git a/test/cases/compile_errors/tagName_on_undef_enum_literal.zig b/test/cases/compile_errors/tagName_on_undef_enum_literal.zig index 900aef9d7c..c003dc47fa 100644 --- a/test/cases/compile_errors/tagName_on_undef_enum_literal.zig +++ b/test/cases/compile_errors/tagName_on_undef_enum_literal.zig @@ -1,5 +1,5 @@ comptime { - const undef: @Type(.enum_literal) = undefined; + const undef: @EnumLiteral() = undefined; _ = @tagName(undef); } diff --git a/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig b/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig index 561b39a4e8..ba9de49ebc 100644 --- a/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig +++ b/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig @@ -42,4 +42,4 @@ pub export fn entry3() void { // :13:13: note: initializer of container-level variable must be comptime-known // :22:9: error: unable to evaluate comptime expression // :22:21: note: operation is runtime due to this operand -// :21:13: note: enum fields must be comptime-known +// :21:13: note: enum field values must be comptime-known diff --git a/test/cases/compile_errors/wrong_type_for_reify_type.zig b/test/cases/compile_errors/wrong_type_for_reify_type.zig index 45c9dfe9bd..cf93ff91b4 100644 --- a/test/cases/compile_errors/wrong_type_for_reify_type.zig +++ b/test/cases/compile_errors/wrong_type_for_reify_type.zig @@ -1,8 +1,25 @@ -export fn entry() void { - _ = @Type(0); +export fn entryI() void { + _ = @Int(0, 0); +} + +export fn entryE() void { + _ = @Enum(0, 0, 0, 0); +} + +export fn entryS() void { + _ = @Struct(0, 0, &.{}, &.{}, &.{}); +} + +export fn entryU() void { + _ = @Union(0, 0, &.{}, &.{}, &.{}); } // error // -// :2:15: error: expected type 'builtin.Type', found 'comptime_int' -// :?:?: note: union declared here +// :2:14: error: expected type 'builtin.Signedness', found 'comptime_int' +// :?:?: note: enum declared here +// :6:15: error: expected type 'type', found 'comptime_int' +// :10:17: error: expected type 'builtin.Type.ContainerLayout', found 'comptime_int' +// :?:?: enum declared here +// :14:16: error: expected type 'builtin.Type.ContainerLayout', found 'comptime_int' +// :?:?: enum declared here diff --git a/test/cases/default_value_references_comptime_var.zig b/test/cases/default_value_references_comptime_var.zig index e808f99738..479acdd900 100644 --- a/test/cases/default_value_references_comptime_var.zig +++ b/test/cases/default_value_references_comptime_var.zig @@ -2,49 +2,27 @@ export fn foo() void { comptime var a: u8 = 0; _ = struct { comptime *u8 = &a }; } -export fn bar() void { - comptime var a: u8 = 0; - _ = @Type(.{ .@"struct" = .{ - .layout = .auto, - .fields = &.{.{ - .name = "0", - .type = *u8, - .default_value_ptr = @ptrCast(&&a), - .is_comptime = true, - .alignment = @alignOf(*u8), - }}, - .decls = &.{}, - .is_tuple = true, - } }); -} -export fn baz() void { +export fn bar() void { comptime var a: u8 = 0; _ = struct { foo: *u8 = &a }; } -export fn qux() void { +export fn baz() void { comptime var a: u8 = 0; - _ = @Type(.{ .@"struct" = .{ - .layout = .auto, - .fields = &.{.{ - .name = "foo", - .type = *u8, - .default_value_ptr = @ptrCast(&&a), - .is_comptime = false, - .alignment = @alignOf(*u8), - }}, - .decls = &.{}, - .is_tuple = false, - } }); + _ = @Struct( + .auto, + null, + &.{"foo"}, + &.{*u8}, + &.{.{ .default_value_ptr = @ptrCast(&&a) }}, + ); } // error // // :3:33: error: field default value contains reference to comptime var // :2:14: note: '0' points to comptime var declared here -// :7:9: error: field default value contains reference to comptime var -// :6:14: note: '0' points to comptime var declared here -// :23:9: error: captured value contains reference to comptime var -// :22:14: note: 'a' points to comptime var declared here -// :27:9: error: field default value contains reference to comptime var -// :26:14: note: 'foo' points to comptime var declared here +// :8:9: error: captured value contains reference to comptime var +// :7:14: note: 'a' points to comptime var declared here +// :17:9: error: field default value contains reference to comptime var +// :11:14: note: 'foo' points to comptime var declared here diff --git a/test/cases/sentinel_references_comptime_var.zig b/test/cases/sentinel_references_comptime_var.zig index 74841385af..b8f5cb3979 100644 --- a/test/cases/sentinel_references_comptime_var.zig +++ b/test/cases/sentinel_references_comptime_var.zig @@ -2,14 +2,6 @@ export fn foo() void { comptime var a: u8 = 0; _ = [0:&a]*u8; } -export fn bar() void { - comptime var a: u8 = 0; - _ = @Type(.{ .array = .{ - .child = *u8, - .len = 0, - .sentinel_ptr = @ptrCast(&&a), - } }); -} export fn baz() void { comptime var a: u8 = 0; @@ -17,25 +9,14 @@ export fn baz() void { } export fn qux() void { comptime var a: u8 = 0; - _ = @Type(.{ .pointer = .{ - .size = .many, - .is_const = false, - .is_volatile = false, - .alignment = @alignOf(u8), - .address_space = .generic, - .child = *u8, - .is_allowzero = false, - .sentinel_ptr = @ptrCast(&&a), - } }); + _ = @Pointer(.many, .{}, *u8, &a); } // error // // :3:12: error: sentinel contains reference to comptime var // :2:14: note: 'sentinel' points to comptime var declared here -// :7:9: error: sentinel contains reference to comptime var -// :6:14: note: 'sentinel_ptr' points to comptime var declared here -// :16:11: error: sentinel contains reference to comptime var -// :15:14: note: 'sentinel' points to comptime var declared here -// :20:9: error: sentinel contains reference to comptime var -// :19:14: note: 'sentinel_ptr' points to comptime var declared here +// :8:11: error: sentinel contains reference to comptime var +// :7:14: note: 'sentinel' points to comptime var declared here +// :12:35: error: sentinel contains reference to comptime var +// :11:14: note: 'sentinel' points to comptime var declared here diff --git a/test/standalone/simple/issue_7030.zig b/test/standalone/simple/issue_7030.zig index eb7aa65387..0215677516 100644 --- a/test/standalone/simple/issue_7030.zig +++ b/test/standalone/simple/issue_7030.zig @@ -6,7 +6,7 @@ pub const std_options: std.Options = .{ pub fn log( comptime message_level: std.log.Level, - comptime scope: @Type(.enum_literal), + comptime scope: @EnumLiteral(), comptime format: []const u8, args: anytype, ) void { diff --git a/test/standalone/simple/std_enums_big_enums.zig b/test/standalone/simple/std_enums_big_enums.zig index de6cfe3ec7..1fcbc93275 100644 --- a/test/standalone/simple/std_enums_big_enums.zig +++ b/test/standalone/simple/std_enums_big_enums.zig @@ -3,20 +3,18 @@ const std = @import("std"); // big enums should not hit the eval branch quota pub fn main() void { const big = struct { - const Big = @Type(.{ .@"enum" = .{ - .tag_type = u16, - .fields = make_fields: { - @setEvalBranchQuota(500000); - var fields: [1001]std.builtin.Type.EnumField = undefined; - for (&fields, 0..) |*field, i| { - field.* = .{ .name = std.fmt.comptimePrint("field_{d}", .{i}), .value = i }; - } - fields[1000] = .{ .name = "field_9999", .value = 9999 }; - break :make_fields &fields; - }, - .decls = &.{}, - .is_exhaustive = true, - } }); + const Big = Big: { + @setEvalBranchQuota(500000); + var names: [1001][]const u8 = undefined; + var values: [1001]u16 = undefined; + for (values[0..1000], names[0..1000], 0..1000) |*val, *name, i| { + name.* = std.fmt.comptimePrint("field_{d}", .{i}); + val.* = i; + } + names[1000] = "field_9999"; + values[1000] = 9999; + break :Big @Enum(u16, .exhaustive, &names, &values); + }; }; var set = std.enums.EnumSet(big.Big).init(.{}); @@ -29,10 +27,11 @@ pub fn main() void { var multiset = std.enums.EnumMultiset(big.Big).init(.{}); _ = &multiset; + @setEvalBranchQuota(4000); + var bounded_multiset = std.enums.BoundedEnumMultiset(big.Big, u8).init(.{}); _ = &bounded_multiset; - @setEvalBranchQuota(3000); var array = std.enums.EnumArray(big.Big, u8).init(undefined); array = std.enums.EnumArray(big.Big, u8).initDefault(123, .{}); } diff --git a/tools/lldb_pretty_printers.py b/tools/lldb_pretty_printers.py index 6c32841cf9..48580243ec 100644 --- a/tools/lldb_pretty_printers.py +++ b/tools/lldb_pretty_printers.py @@ -559,7 +559,7 @@ type_tag_handlers = { 'extern_options': lambda payload: 'std.builtin.ExternOptions', 'type_info': lambda payload: 'std.builtin.Type', - 'enum_literal': lambda payload: '@TypeOf(.enum_literal)', + 'enum_literal': lambda payload: '@EnumLiteral()', 'null': lambda payload: '@TypeOf(null)', 'undefined': lambda payload: '@TypeOf(undefined)', 'empty_struct_literal': lambda payload: '@TypeOf(.{})',