Commit 8375b71f75
Changed files (5)
test
src/Sema.zig
@@ -9677,12 +9677,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
};
- if (ty.getNamespace()) |namespace| {
- if (namespace.decls.count() != 0) {
- return sema.fail(block, src, "TODO: implement zirTypeInfo for Enum which has declarations", .{});
- }
- }
- const decls_val = Value.initTag(.empty_array);
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace());
const field_values = try sema.arena.create([5]Value);
field_values.* = .{
@@ -9773,12 +9768,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
};
- if (ty.getNamespace()) |namespace| {
- if (namespace.decls.count() != 0) {
- return sema.fail(block, src, "TODO: implement zirTypeInfo for Union which has declarations", .{});
- }
- }
- const decls_val = Value.initTag(.empty_array);
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace());
const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: {
const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
@@ -9810,14 +9800,105 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
);
},
.Struct => return sema.fail(block, src, "TODO: implement zirTypeInfo for Struct", .{}),
+ .Opaque => {
+ // TODO: look into memoizing this result.
+
+ var fields_anon_decl = try block.startAnonDecl();
+ defer fields_anon_decl.deinit();
+
+ const opaque_ty = try sema.resolveTypeFields(block, src, ty);
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespace());
+
+ const field_values = try sema.arena.create([1]Value);
+ field_values.* = .{
+ // decls: []const Declaration,
+ decls_val,
+ };
+
+ return sema.addConstant(
+ type_info_ty,
+ try Value.Tag.@"union".create(sema.arena, .{
+ .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Opaque)),
+ .val = try Value.Tag.@"struct".create(sema.arena, field_values),
+ }),
+ );
+ },
.ErrorSet => return sema.fail(block, src, "TODO: implement zirTypeInfo for ErrorSet", .{}),
.BoundFn => @panic("TODO remove this type from the language and compiler"),
- .Opaque => return sema.fail(block, src, "TODO: implement zirTypeInfo for Opaque", .{}),
.Frame => return sema.fail(block, src, "TODO: implement zirTypeInfo for Frame", .{}),
.AnyFrame => return sema.fail(block, src, "TODO: implement zirTypeInfo for AnyFrame", .{}),
}
}
+fn typeInfoDecls(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ type_info_ty: Type,
+ opt_namespace: ?*Module.Namespace,
+) CompileError!Value {
+ const namespace = opt_namespace orelse return Value.initTag(.empty_array);
+ const decls_len = namespace.decls.count();
+ if (decls_len == 0) return Value.initTag(.empty_array);
+
+ var decls_anon_decl = try block.startAnonDecl();
+ defer decls_anon_decl.deinit();
+
+ const declaration_ty = t: {
+ const declaration_ty_decl = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespace().?,
+ "EnumField",
+ )).?;
+ try sema.mod.declareDeclDependency(sema.owner_decl, declaration_ty_decl);
+ try sema.ensureDeclAnalyzed(declaration_ty_decl);
+ var buffer: Value.ToTypeBuffer = undefined;
+ break :t try declaration_ty_decl.val.toType(&buffer).copy(decls_anon_decl.arena());
+ };
+
+ const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len);
+ for (decls_vals) |*decls_val, i| {
+ const decl = namespace.decls.values()[i];
+ const name = namespace.decls.keys()[i];
+ const name_val = v: {
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ const bytes = try anon_decl.arena().dupeZ(u8, name);
+ const new_decl = try anon_decl.finish(
+ try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
+ try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ );
+ break :v try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl);
+ };
+
+ const is_pub = if (decl.is_pub) Value.@"true" else Value.@"false";
+
+ const fields = try decls_anon_decl.arena().create([3]Value);
+ fields.* = .{
+ //name: []const u8,
+ name_val,
+ //is_pub: bool,
+ is_pub,
+ //data: Data,
+ Value.undef, // TODO
+ };
+ decls_val.* = try Value.Tag.@"struct".create(decls_anon_decl.arena(), fields);
+ }
+
+ const new_decl = try decls_anon_decl.finish(
+ try Type.Tag.array.create(decls_anon_decl.arena(), .{
+ .len = decls_vals.len,
+ .elem_type = declaration_ty,
+ }),
+ try Value.Tag.array.create(
+ decls_anon_decl.arena(),
+ try decls_anon_decl.arena().dupe(Value, decls_vals),
+ ),
+ );
+ return try Value.Tag.decl_ref.create(sema.arena, new_decl);
+}
+
fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
_ = block;
const zir_datas = sema.code.instructions.items(.data);
src/value.zig
@@ -768,7 +768,12 @@ pub const Value = extern union {
return allocator.dupe(u8, adjusted_bytes);
},
.enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data),
- .repeated => @panic("TODO implement toAllocatedBytes for this Value tag"),
+ .repeated => {
+ const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt());
+ const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen()));
+ std.mem.set(u8, result, byte);
+ return result;
+ },
.decl_ref => {
const decl = val.castTag(.decl_ref).?.data;
const decl_val = try decl.value();
@@ -776,7 +781,15 @@ pub const Value = extern union {
},
.the_only_possible_value => return &[_]u8{},
.slice => return toAllocatedBytes(val.castTag(.slice).?.data.ptr, ty, allocator),
- else => unreachable,
+ else => {
+ const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen()));
+ var elem_value_buf: ElemValueBuffer = undefined;
+ for (result) |*elem, i| {
+ const elem_val = val.elemValueBuffer(i, &elem_value_buf);
+ elem.* = @intCast(u8, elem_val.toUnsignedInt());
+ }
+ return result;
+ },
}
}
test/behavior/type_info.zig
@@ -57,3 +57,484 @@ test "type info: value is correctly copied" {
try expect(@typeInfo([]u32).Pointer.size == .Slice);
}
}
+
+test "type info: tag type, void info" {
+ try testBasic();
+ comptime try testBasic();
+}
+
+fn testBasic() !void {
+ try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId);
+ const void_info = @typeInfo(void);
+ try expect(void_info == TypeId.Void);
+ try expect(void_info.Void == {});
+}
+
+test "type info: pointer type info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testPointer();
+ comptime try testPointer();
+}
+
+fn testPointer() !void {
+ const u32_ptr_info = @typeInfo(*u32);
+ try expect(u32_ptr_info == .Pointer);
+ try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
+ try expect(u32_ptr_info.Pointer.is_const == false);
+ try expect(u32_ptr_info.Pointer.is_volatile == false);
+ try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
+ try expect(u32_ptr_info.Pointer.child == u32);
+ try expect(u32_ptr_info.Pointer.sentinel == null);
+}
+
+test "type info: unknown length pointer type info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testUnknownLenPtr();
+ comptime try testUnknownLenPtr();
+}
+
+fn testUnknownLenPtr() !void {
+ const u32_ptr_info = @typeInfo([*]const volatile f64);
+ try expect(u32_ptr_info == .Pointer);
+ try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
+ try expect(u32_ptr_info.Pointer.is_const == true);
+ try expect(u32_ptr_info.Pointer.is_volatile == true);
+ try expect(u32_ptr_info.Pointer.sentinel == null);
+ try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
+ try expect(u32_ptr_info.Pointer.child == f64);
+}
+
+test "type info: null terminated pointer type info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testNullTerminatedPtr();
+ comptime try testNullTerminatedPtr();
+}
+
+fn testNullTerminatedPtr() !void {
+ const ptr_info = @typeInfo([*:0]u8);
+ try expect(ptr_info == .Pointer);
+ try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
+ try expect(ptr_info.Pointer.is_const == false);
+ try expect(ptr_info.Pointer.is_volatile == false);
+ try expect(ptr_info.Pointer.sentinel.? == 0);
+
+ try expect(@typeInfo([:0]u8).Pointer.sentinel != null);
+}
+
+test "type info: slice type info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testSlice();
+ comptime try testSlice();
+}
+
+fn testSlice() !void {
+ const u32_slice_info = @typeInfo([]u32);
+ try expect(u32_slice_info == .Pointer);
+ try expect(u32_slice_info.Pointer.size == .Slice);
+ try expect(u32_slice_info.Pointer.is_const == false);
+ try expect(u32_slice_info.Pointer.is_volatile == false);
+ try expect(u32_slice_info.Pointer.alignment == 4);
+ try expect(u32_slice_info.Pointer.child == u32);
+}
+
+test "type info: array type info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testArray();
+ comptime try testArray();
+}
+
+fn testArray() !void {
+ {
+ const info = @typeInfo([42]u8);
+ try expect(info == .Array);
+ try expect(info.Array.len == 42);
+ try expect(info.Array.child == u8);
+ try expect(info.Array.sentinel == null);
+ }
+
+ {
+ const info = @typeInfo([10:0]u8);
+ try expect(info.Array.len == 10);
+ try expect(info.Array.child == u8);
+ try expect(info.Array.sentinel.? == @as(u8, 0));
+ try expect(@sizeOf([10:0]u8) == info.Array.len + 1);
+ }
+}
+
+test "type info: error set, error union info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testErrorSet();
+ comptime try testErrorSet();
+}
+
+fn testErrorSet() !void {
+ const TestErrorSet = error{
+ First,
+ Second,
+ Third,
+ };
+
+ const error_set_info = @typeInfo(TestErrorSet);
+ try expect(error_set_info == .ErrorSet);
+ try expect(error_set_info.ErrorSet.?.len == 3);
+ try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First"));
+
+ const error_union_info = @typeInfo(TestErrorSet!usize);
+ try expect(error_union_info == .ErrorUnion);
+ try expect(error_union_info.ErrorUnion.error_set == TestErrorSet);
+ try expect(error_union_info.ErrorUnion.payload == usize);
+
+ const global_info = @typeInfo(anyerror);
+ try expect(global_info == .ErrorSet);
+ try expect(global_info.ErrorSet == null);
+}
+
+test "type info: enum info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testEnum();
+ comptime try testEnum();
+}
+
+fn testEnum() !void {
+ const Os = enum {
+ Windows,
+ Macos,
+ Linux,
+ FreeBSD,
+ };
+
+ const os_info = @typeInfo(Os);
+ try expect(os_info == .Enum);
+ try expect(os_info.Enum.layout == .Auto);
+ try expect(os_info.Enum.fields.len == 4);
+ try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
+ try expect(os_info.Enum.fields[3].value == 3);
+ try expect(os_info.Enum.tag_type == u2);
+ try expect(os_info.Enum.decls.len == 0);
+}
+
+test "type info: union info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testUnion();
+ comptime try testUnion();
+}
+
+fn testUnion() !void {
+ const typeinfo_info = @typeInfo(TypeInfo);
+ try expect(typeinfo_info == .Union);
+ try expect(typeinfo_info.Union.layout == .Auto);
+ try expect(typeinfo_info.Union.tag_type.? == TypeId);
+ try expect(typeinfo_info.Union.fields.len == 25);
+ try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
+ try expect(typeinfo_info.Union.decls.len == 22);
+
+ const TestNoTagUnion = union {
+ Foo: void,
+ Bar: u32,
+ };
+
+ const notag_union_info = @typeInfo(TestNoTagUnion);
+ try expect(notag_union_info == .Union);
+ try expect(notag_union_info.Union.tag_type == null);
+ try expect(notag_union_info.Union.layout == .Auto);
+ try expect(notag_union_info.Union.fields.len == 2);
+ try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
+ try expect(notag_union_info.Union.fields[1].field_type == u32);
+ try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
+
+ const TestExternUnion = extern union {
+ foo: *anyopaque,
+ };
+
+ const extern_union_info = @typeInfo(TestExternUnion);
+ try expect(extern_union_info.Union.layout == .Extern);
+ try expect(extern_union_info.Union.tag_type == null);
+ try expect(extern_union_info.Union.fields[0].field_type == *anyopaque);
+}
+
+test "type info: struct info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testStruct();
+ comptime try testStruct();
+}
+
+fn testStruct() !void {
+ const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
+ try expect(unpacked_struct_info.Struct.is_tuple == false);
+ try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
+ try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4);
+ try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?);
+
+ const struct_info = @typeInfo(TestStruct);
+ try expect(struct_info == .Struct);
+ try expect(struct_info.Struct.is_tuple == false);
+ try expect(struct_info.Struct.layout == .Packed);
+ try expect(struct_info.Struct.fields.len == 4);
+ try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
+ try expect(struct_info.Struct.fields[2].field_type == *TestStruct);
+ try expect(struct_info.Struct.fields[2].default_value == null);
+ try expect(struct_info.Struct.fields[3].default_value.? == 4);
+ try expect(struct_info.Struct.fields[3].alignment == 1);
+ try expect(struct_info.Struct.decls.len == 2);
+ try expect(struct_info.Struct.decls[0].is_pub);
+ try expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
+ try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null);
+ try expect(struct_info.Struct.decls[0].data.Fn.return_type == void);
+ try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
+}
+
+const TestUnpackedStruct = struct {
+ fieldA: u32 = 4,
+ fieldB: *const [6:0]u8 = "foobar",
+};
+
+const TestStruct = packed struct {
+ fieldA: usize align(2 * @alignOf(usize)),
+ fieldB: void,
+ fieldC: *Self,
+ fieldD: u32 = 4,
+
+ pub fn foo(self: *const Self) void {
+ _ = self;
+ }
+ const Self = @This();
+};
+
+test "type info: opaque info" {
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+
+ try testOpaque();
+ comptime try testOpaque();
+}
+
+fn testOpaque() !void {
+ const Foo = opaque {
+ const A = 1;
+ fn b() void {}
+ };
+
+ const foo_info = @typeInfo(Foo);
+ try expect(foo_info.Opaque.decls.len == 2);
+}
+
+test "type info: function type info" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ // wasm doesn't support align attributes on functions
+ if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
+ try testFunction();
+ comptime try testFunction();
+}
+
+fn testFunction() !void {
+ const fn_info = @typeInfo(@TypeOf(foo));
+ try expect(fn_info == .Fn);
+ try expect(fn_info.Fn.alignment > 0);
+ try expect(fn_info.Fn.calling_convention == .C);
+ try expect(!fn_info.Fn.is_generic);
+ try expect(fn_info.Fn.args.len == 2);
+ try expect(fn_info.Fn.is_var_args);
+ try expect(fn_info.Fn.return_type.? == usize);
+ const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
+ try expect(fn_aligned_info.Fn.alignment == 4);
+
+ const test_instance: TestStruct = undefined;
+ const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
+ try expect(bound_fn_info == .BoundFn);
+ try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
+}
+
+extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
+extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
+
+test "typeInfo with comptime parameter in struct fn def" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ pub fn func(comptime x: f32) void {
+ _ = x;
+ }
+ };
+ comptime var info = @typeInfo(S);
+ _ = info;
+}
+
+test "type info: vectors" {
+ try testVector();
+ comptime try testVector();
+}
+
+fn testVector() !void {
+ const vec_info = @typeInfo(std.meta.Vector(4, i32));
+ try expect(vec_info == .Vector);
+ try expect(vec_info.Vector.len == 4);
+ try expect(vec_info.Vector.child == i32);
+}
+
+test "type info: anyframe and anyframe->T" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try testAnyFrame();
+ comptime try testAnyFrame();
+}
+
+fn testAnyFrame() !void {
+ {
+ const anyframe_info = @typeInfo(anyframe->i32);
+ try expect(anyframe_info == .AnyFrame);
+ try expect(anyframe_info.AnyFrame.child.? == i32);
+ }
+
+ {
+ const anyframe_info = @typeInfo(anyframe);
+ try expect(anyframe_info == .AnyFrame);
+ try expect(anyframe_info.AnyFrame.child == null);
+ }
+}
+
+test "type info: pass to function" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ _ = passTypeInfo(@typeInfo(void));
+ _ = comptime passTypeInfo(@typeInfo(void));
+}
+
+fn passTypeInfo(comptime info: TypeInfo) type {
+ _ = info;
+ return void;
+}
+
+test "type info: TypeId -> TypeInfo impl cast" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ _ = passTypeInfo(TypeId.Void);
+ _ = comptime passTypeInfo(TypeId.Void);
+}
+
+test "type info: extern fns with and without lib names" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ extern fn bar1() void;
+ extern "cool" fn bar2() void;
+ };
+ const info = @typeInfo(S);
+ comptime {
+ for (info.Struct.decls) |decl| {
+ if (std.mem.eql(u8, decl.name, "bar1")) {
+ try expect(decl.data.Fn.lib_name == null);
+ } else {
+ try expectEqualStrings("cool", decl.data.Fn.lib_name.?);
+ }
+ }
+ }
+}
+
+test "data field is a compile-time value" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const Bar = @as(isize, -1);
+ };
+ comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize);
+}
+
+test "sentinel of opaque pointer type" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const c_void_info = @typeInfo(*anyopaque);
+ try expect(c_void_info.Pointer.sentinel == null);
+}
+
+test "@typeInfo does not force declarations into existence" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ x: i32,
+
+ fn doNotReferenceMe() void {
+ @compileError("test failed");
+ }
+ };
+ comptime try expect(@typeInfo(S).Struct.fields.len == 1);
+}
+
+test "default value for a anytype field" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct { x: anytype };
+ try expect(@typeInfo(S).Struct.fields[0].default_value == null);
+}
+
+fn add(a: i32, b: i32) i32 {
+ return a + b;
+}
+
+test "type info for async frames" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ switch (@typeInfo(@Frame(add))) {
+ .Frame => |frame| {
+ try expect(frame.function == add);
+ },
+ else => unreachable,
+ }
+}
+
+test "Declarations are returned in declaration order" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ const a = 1;
+ const b = 2;
+ const c = 3;
+ const d = 4;
+ const e = 5;
+ };
+ const d = @typeInfo(S).Struct.decls;
+ try expect(std.mem.eql(u8, d[0].name, "a"));
+ try expect(std.mem.eql(u8, d[1].name, "b"));
+ try expect(std.mem.eql(u8, d[2].name, "c"));
+ try expect(std.mem.eql(u8, d[3].name, "d"));
+ try expect(std.mem.eql(u8, d[4].name, "e"));
+}
+
+test "Struct.is_tuple" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
+ try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple);
+}
+
+test "StructField.is_comptime" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct;
+ try expect(!info.fields[0].is_comptime);
+ try expect(info.fields[1].is_comptime);
+}
+
+test "typeInfo resolves usingnamespace declarations" {
+ if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+
+ const A = struct {
+ pub const f1 = 42;
+ };
+
+ const B = struct {
+ const f0 = 42;
+ usingnamespace A;
+ };
+
+ try expect(@typeInfo(B).Struct.decls.len == 2);
+ //a
+}
test/behavior/type_info_stage1.zig
@@ -1,440 +0,0 @@
-const std = @import("std");
-const builtin = @import("builtin");
-const mem = std.mem;
-
-const TypeInfo = std.builtin.TypeInfo;
-const TypeId = std.builtin.TypeId;
-
-const expect = std.testing.expect;
-const expectEqualStrings = std.testing.expectEqualStrings;
-
-test "type info: tag type, void info" {
- try testBasic();
- comptime try testBasic();
-}
-
-fn testBasic() !void {
- try expect(@typeInfo(TypeInfo).Union.tag_type == TypeId);
- const void_info = @typeInfo(void);
- try expect(void_info == TypeId.Void);
- try expect(void_info.Void == {});
-}
-
-test "type info: pointer type info" {
- try testPointer();
- comptime try testPointer();
-}
-
-fn testPointer() !void {
- const u32_ptr_info = @typeInfo(*u32);
- try expect(u32_ptr_info == .Pointer);
- try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
- try expect(u32_ptr_info.Pointer.is_const == false);
- try expect(u32_ptr_info.Pointer.is_volatile == false);
- try expect(u32_ptr_info.Pointer.alignment == @alignOf(u32));
- try expect(u32_ptr_info.Pointer.child == u32);
- try expect(u32_ptr_info.Pointer.sentinel == null);
-}
-
-test "type info: unknown length pointer type info" {
- try testUnknownLenPtr();
- comptime try testUnknownLenPtr();
-}
-
-fn testUnknownLenPtr() !void {
- const u32_ptr_info = @typeInfo([*]const volatile f64);
- try expect(u32_ptr_info == .Pointer);
- try expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
- try expect(u32_ptr_info.Pointer.is_const == true);
- try expect(u32_ptr_info.Pointer.is_volatile == true);
- try expect(u32_ptr_info.Pointer.sentinel == null);
- try expect(u32_ptr_info.Pointer.alignment == @alignOf(f64));
- try expect(u32_ptr_info.Pointer.child == f64);
-}
-
-test "type info: null terminated pointer type info" {
- try testNullTerminatedPtr();
- comptime try testNullTerminatedPtr();
-}
-
-fn testNullTerminatedPtr() !void {
- const ptr_info = @typeInfo([*:0]u8);
- try expect(ptr_info == .Pointer);
- try expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
- try expect(ptr_info.Pointer.is_const == false);
- try expect(ptr_info.Pointer.is_volatile == false);
- try expect(ptr_info.Pointer.sentinel.? == 0);
-
- try expect(@typeInfo([:0]u8).Pointer.sentinel != null);
-}
-
-test "type info: slice type info" {
- try testSlice();
- comptime try testSlice();
-}
-
-fn testSlice() !void {
- const u32_slice_info = @typeInfo([]u32);
- try expect(u32_slice_info == .Pointer);
- try expect(u32_slice_info.Pointer.size == .Slice);
- try expect(u32_slice_info.Pointer.is_const == false);
- try expect(u32_slice_info.Pointer.is_volatile == false);
- try expect(u32_slice_info.Pointer.alignment == 4);
- try expect(u32_slice_info.Pointer.child == u32);
-}
-
-test "type info: array type info" {
- try testArray();
- comptime try testArray();
-}
-
-fn testArray() !void {
- {
- const info = @typeInfo([42]u8);
- try expect(info == .Array);
- try expect(info.Array.len == 42);
- try expect(info.Array.child == u8);
- try expect(info.Array.sentinel == null);
- }
-
- {
- const info = @typeInfo([10:0]u8);
- try expect(info.Array.len == 10);
- try expect(info.Array.child == u8);
- try expect(info.Array.sentinel.? == @as(u8, 0));
- try expect(@sizeOf([10:0]u8) == info.Array.len + 1);
- }
-}
-
-test "type info: error set, error union info" {
- try testErrorSet();
- comptime try testErrorSet();
-}
-
-fn testErrorSet() !void {
- const TestErrorSet = error{
- First,
- Second,
- Third,
- };
-
- const error_set_info = @typeInfo(TestErrorSet);
- try expect(error_set_info == .ErrorSet);
- try expect(error_set_info.ErrorSet.?.len == 3);
- try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "First"));
-
- const error_union_info = @typeInfo(TestErrorSet!usize);
- try expect(error_union_info == .ErrorUnion);
- try expect(error_union_info.ErrorUnion.error_set == TestErrorSet);
- try expect(error_union_info.ErrorUnion.payload == usize);
-
- const global_info = @typeInfo(anyerror);
- try expect(global_info == .ErrorSet);
- try expect(global_info.ErrorSet == null);
-}
-
-test "type info: enum info" {
- try testEnum();
- comptime try testEnum();
-}
-
-fn testEnum() !void {
- const Os = enum {
- Windows,
- Macos,
- Linux,
- FreeBSD,
- };
-
- const os_info = @typeInfo(Os);
- try expect(os_info == .Enum);
- try expect(os_info.Enum.layout == .Auto);
- try expect(os_info.Enum.fields.len == 4);
- try expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
- try expect(os_info.Enum.fields[3].value == 3);
- try expect(os_info.Enum.tag_type == u2);
- try expect(os_info.Enum.decls.len == 0);
-}
-
-test "type info: union info" {
- try testUnion();
- comptime try testUnion();
-}
-
-fn testUnion() !void {
- const typeinfo_info = @typeInfo(TypeInfo);
- try expect(typeinfo_info == .Union);
- try expect(typeinfo_info.Union.layout == .Auto);
- try expect(typeinfo_info.Union.tag_type.? == TypeId);
- try expect(typeinfo_info.Union.fields.len == 25);
- try expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
- try expect(typeinfo_info.Union.decls.len == 22);
-
- const TestNoTagUnion = union {
- Foo: void,
- Bar: u32,
- };
-
- const notag_union_info = @typeInfo(TestNoTagUnion);
- try expect(notag_union_info == .Union);
- try expect(notag_union_info.Union.tag_type == null);
- try expect(notag_union_info.Union.layout == .Auto);
- try expect(notag_union_info.Union.fields.len == 2);
- try expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
- try expect(notag_union_info.Union.fields[1].field_type == u32);
- try expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
-
- const TestExternUnion = extern union {
- foo: *anyopaque,
- };
-
- const extern_union_info = @typeInfo(TestExternUnion);
- try expect(extern_union_info.Union.layout == .Extern);
- try expect(extern_union_info.Union.tag_type == null);
- try expect(extern_union_info.Union.fields[0].field_type == *anyopaque);
-}
-
-test "type info: struct info" {
- try testStruct();
- comptime try testStruct();
-}
-
-fn testStruct() !void {
- const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
- try expect(unpacked_struct_info.Struct.is_tuple == false);
- try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
- try expect(unpacked_struct_info.Struct.fields[0].default_value.? == 4);
- try expectEqualStrings("foobar", unpacked_struct_info.Struct.fields[1].default_value.?);
-
- const struct_info = @typeInfo(TestStruct);
- try expect(struct_info == .Struct);
- try expect(struct_info.Struct.is_tuple == false);
- try expect(struct_info.Struct.layout == .Packed);
- try expect(struct_info.Struct.fields.len == 4);
- try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
- try expect(struct_info.Struct.fields[2].field_type == *TestStruct);
- try expect(struct_info.Struct.fields[2].default_value == null);
- try expect(struct_info.Struct.fields[3].default_value.? == 4);
- try expect(struct_info.Struct.fields[3].alignment == 1);
- try expect(struct_info.Struct.decls.len == 2);
- try expect(struct_info.Struct.decls[0].is_pub);
- try expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
- try expect(struct_info.Struct.decls[0].data.Fn.lib_name == null);
- try expect(struct_info.Struct.decls[0].data.Fn.return_type == void);
- try expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
-}
-
-const TestUnpackedStruct = struct {
- fieldA: u32 = 4,
- fieldB: *const [6:0]u8 = "foobar",
-};
-
-const TestStruct = packed struct {
- fieldA: usize align(2 * @alignOf(usize)),
- fieldB: void,
- fieldC: *Self,
- fieldD: u32 = 4,
-
- pub fn foo(self: *const Self) void {
- _ = self;
- }
- const Self = @This();
-};
-
-test "type info: opaque info" {
- try testOpaque();
- comptime try testOpaque();
-}
-
-fn testOpaque() !void {
- const Foo = opaque {
- const A = 1;
- fn b() void {}
- };
-
- const foo_info = @typeInfo(Foo);
- try expect(foo_info.Opaque.decls.len == 2);
-}
-
-test "type info: function type info" {
- // wasm doesn't support align attributes on functions
- if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
- try testFunction();
- comptime try testFunction();
-}
-
-fn testFunction() !void {
- const fn_info = @typeInfo(@TypeOf(foo));
- try expect(fn_info == .Fn);
- try expect(fn_info.Fn.alignment > 0);
- try expect(fn_info.Fn.calling_convention == .C);
- try expect(!fn_info.Fn.is_generic);
- try expect(fn_info.Fn.args.len == 2);
- try expect(fn_info.Fn.is_var_args);
- try expect(fn_info.Fn.return_type.? == usize);
- const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
- try expect(fn_aligned_info.Fn.alignment == 4);
-
- const test_instance: TestStruct = undefined;
- const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
- try expect(bound_fn_info == .BoundFn);
- try expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
-}
-
-extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
-extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
-
-test "typeInfo with comptime parameter in struct fn def" {
- const S = struct {
- pub fn func(comptime x: f32) void {
- _ = x;
- }
- };
- comptime var info = @typeInfo(S);
- _ = info;
-}
-
-test "type info: vectors" {
- try testVector();
- comptime try testVector();
-}
-
-fn testVector() !void {
- const vec_info = @typeInfo(std.meta.Vector(4, i32));
- try expect(vec_info == .Vector);
- try expect(vec_info.Vector.len == 4);
- try expect(vec_info.Vector.child == i32);
-}
-
-test "type info: anyframe and anyframe->T" {
- try testAnyFrame();
- comptime try testAnyFrame();
-}
-
-fn testAnyFrame() !void {
- {
- const anyframe_info = @typeInfo(anyframe->i32);
- try expect(anyframe_info == .AnyFrame);
- try expect(anyframe_info.AnyFrame.child.? == i32);
- }
-
- {
- const anyframe_info = @typeInfo(anyframe);
- try expect(anyframe_info == .AnyFrame);
- try expect(anyframe_info.AnyFrame.child == null);
- }
-}
-
-test "type info: pass to function" {
- _ = passTypeInfo(@typeInfo(void));
- _ = comptime passTypeInfo(@typeInfo(void));
-}
-
-fn passTypeInfo(comptime info: TypeInfo) type {
- _ = info;
- return void;
-}
-
-test "type info: TypeId -> TypeInfo impl cast" {
- _ = passTypeInfo(TypeId.Void);
- _ = comptime passTypeInfo(TypeId.Void);
-}
-
-test "type info: extern fns with and without lib names" {
- const S = struct {
- extern fn bar1() void;
- extern "cool" fn bar2() void;
- };
- const info = @typeInfo(S);
- comptime {
- for (info.Struct.decls) |decl| {
- if (std.mem.eql(u8, decl.name, "bar1")) {
- try expect(decl.data.Fn.lib_name == null);
- } else {
- try expectEqualStrings("cool", decl.data.Fn.lib_name.?);
- }
- }
- }
-}
-
-test "data field is a compile-time value" {
- const S = struct {
- const Bar = @as(isize, -1);
- };
- comptime try expect(@typeInfo(S).Struct.decls[0].data.Var == isize);
-}
-
-test "sentinel of opaque pointer type" {
- const c_void_info = @typeInfo(*anyopaque);
- try expect(c_void_info.Pointer.sentinel == null);
-}
-
-test "@typeInfo does not force declarations into existence" {
- const S = struct {
- x: i32,
-
- fn doNotReferenceMe() void {
- @compileError("test failed");
- }
- };
- comptime try expect(@typeInfo(S).Struct.fields.len == 1);
-}
-
-test "default value for a var-typed field" {
- const S = struct { x: anytype };
- try expect(@typeInfo(S).Struct.fields[0].default_value == null);
-}
-
-fn add(a: i32, b: i32) i32 {
- return a + b;
-}
-
-test "type info for async frames" {
- switch (@typeInfo(@Frame(add))) {
- .Frame => |frame| {
- try expect(frame.function == add);
- },
- else => unreachable,
- }
-}
-
-test "Declarations are returned in declaration order" {
- const S = struct {
- const a = 1;
- const b = 2;
- const c = 3;
- const d = 4;
- const e = 5;
- };
- const d = @typeInfo(S).Struct.decls;
- try expect(std.mem.eql(u8, d[0].name, "a"));
- try expect(std.mem.eql(u8, d[1].name, "b"));
- try expect(std.mem.eql(u8, d[2].name, "c"));
- try expect(std.mem.eql(u8, d[3].name, "d"));
- try expect(std.mem.eql(u8, d[4].name, "e"));
-}
-
-test "Struct.is_tuple" {
- try expect(@typeInfo(@TypeOf(.{0})).Struct.is_tuple);
- try expect(!@typeInfo(@TypeOf(.{ .a = 0 })).Struct.is_tuple);
-}
-
-test "StructField.is_comptime" {
- const info = @typeInfo(struct { x: u8 = 3, comptime y: u32 = 5 }).Struct;
- try expect(!info.fields[0].is_comptime);
- try expect(info.fields[1].is_comptime);
-}
-
-test "typeInfo resolves usingnamespace declarations" {
- const A = struct {
- pub const f1 = 42;
- };
-
- const B = struct {
- const f0 = 42;
- usingnamespace A;
- };
-
- try expect(@typeInfo(B).Struct.decls.len == 2);
- //a
-}
test/behavior.zig
@@ -11,7 +11,6 @@ test {
_ = @import("behavior/hasdecl.zig");
_ = @import("behavior/hasfield.zig");
_ = @import("behavior/pub_enum.zig");
- _ = @import("behavior/type_info.zig");
_ = @import("behavior/type.zig");
_ = @import("behavior/bugs/655.zig");
_ = @import("behavior/bool.zig");
@@ -56,6 +55,7 @@ test {
_ = @import("behavior/this.zig");
_ = @import("behavior/truncate.zig");
_ = @import("behavior/try.zig");
+ _ = @import("behavior/type_info.zig");
_ = @import("behavior/undefined.zig");
_ = @import("behavior/underscore.zig");
_ = @import("behavior/usingnamespace.zig");
@@ -194,7 +194,6 @@ test {
_ = @import("behavior/truncate_stage1.zig");
_ = @import("behavior/tuple.zig");
_ = @import("behavior/type_stage1.zig");
- _ = @import("behavior/type_info_stage1.zig");
_ = @import("behavior/typename.zig");
_ = @import("behavior/union_stage1.zig");
_ = @import("behavior/union_with_members.zig");