mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
stage2: implement @typeName
* stage1: change the `@typeName` of `@TypeOf(undefined)`, `@TypeOf(null)`, and `@TypeOf(.foo)` to match stage2. * move passing behavior tests to the passing-for-stage2 section.
This commit is contained in:
parent
f0deef1d79
commit
17f057c556
34
src/Sema.zig
34
src/Sema.zig
@ -2771,20 +2771,16 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
|
||||
// expression of a variable declaration. We need the memory to be in the new
|
||||
// anonymous Decl's arena.
|
||||
|
||||
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
|
||||
errdefer new_decl_arena.deinit();
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
|
||||
const bytes = try new_decl_arena.allocator.dupeZ(u8, zir_bytes);
|
||||
const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);
|
||||
|
||||
const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
|
||||
const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes[0 .. bytes.len + 1]);
|
||||
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]),
|
||||
);
|
||||
|
||||
const new_decl = try sema.mod.createAnonymousDecl(block, .{
|
||||
.ty = decl_ty,
|
||||
.val = decl_val,
|
||||
});
|
||||
errdefer sema.mod.abortAnonDecl(new_decl);
|
||||
try new_decl.finalizeNewArena(&new_decl_arena);
|
||||
return sema.analyzeDeclRef(new_decl);
|
||||
}
|
||||
|
||||
@ -9741,8 +9737,20 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
|
||||
|
||||
fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src = inst_data.src();
|
||||
return sema.fail(block, src, "TODO: Sema.zirTypeName", .{});
|
||||
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
||||
const ty = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
|
||||
const bytes = try ty.nameAlloc(anon_decl.arena());
|
||||
|
||||
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]),
|
||||
);
|
||||
|
||||
return sema.analyzeDeclRef(new_decl);
|
||||
}
|
||||
|
||||
fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
|
@ -8755,17 +8755,17 @@ static void define_builtin_types(CodeGen *g) {
|
||||
}
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral);
|
||||
buf_init_from_str(&entry->name, "(enum literal)");
|
||||
buf_init_from_str(&entry->name, "@Type(.EnumLiteral)");
|
||||
g->builtin_types.entry_enum_literal = entry;
|
||||
}
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdUndefined);
|
||||
buf_init_from_str(&entry->name, "(undefined)");
|
||||
buf_init_from_str(&entry->name, "@Type(.Undefined)");
|
||||
g->builtin_types.entry_undef = entry;
|
||||
}
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdNull);
|
||||
buf_init_from_str(&entry->name, "(null)");
|
||||
buf_init_from_str(&entry->name, "@Type(.Null)");
|
||||
g->builtin_types.entry_null = entry;
|
||||
}
|
||||
{
|
||||
|
107
src/type.zig
107
src/type.zig
@ -1197,6 +1197,113 @@ pub const Type = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a name suitable for `@typeName`.
|
||||
pub fn nameAlloc(ty: Type, arena: *Allocator) Allocator.Error![:0]const u8 {
|
||||
const t = ty.tag();
|
||||
switch (t) {
|
||||
.inferred_alloc_const => unreachable,
|
||||
.inferred_alloc_mut => unreachable,
|
||||
.generic_poison => unreachable,
|
||||
|
||||
.u1,
|
||||
.u8,
|
||||
.i8,
|
||||
.u16,
|
||||
.i16,
|
||||
.u32,
|
||||
.i32,
|
||||
.u64,
|
||||
.i64,
|
||||
.u128,
|
||||
.i128,
|
||||
.usize,
|
||||
.isize,
|
||||
.c_short,
|
||||
.c_ushort,
|
||||
.c_int,
|
||||
.c_uint,
|
||||
.c_long,
|
||||
.c_ulong,
|
||||
.c_longlong,
|
||||
.c_ulonglong,
|
||||
.c_longdouble,
|
||||
.c_void,
|
||||
.f16,
|
||||
.f32,
|
||||
.f64,
|
||||
.f128,
|
||||
.bool,
|
||||
.void,
|
||||
.type,
|
||||
.anyerror,
|
||||
.@"anyframe",
|
||||
.comptime_int,
|
||||
.comptime_float,
|
||||
.noreturn,
|
||||
.var_args_param,
|
||||
.bound_fn,
|
||||
=> return @tagName(t),
|
||||
|
||||
.enum_literal => return "@Type(.EnumLiteral)",
|
||||
.@"null" => return "@Type(.Null)",
|
||||
.@"undefined" => return "@Type(.Undefined)",
|
||||
|
||||
.empty_struct, .empty_struct_literal => return "struct {}",
|
||||
|
||||
.@"struct" => {
|
||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
return try arena.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0));
|
||||
},
|
||||
.@"union", .union_tagged => {
|
||||
const union_obj = ty.cast(Payload.Union).?.data;
|
||||
return try arena.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0));
|
||||
},
|
||||
.enum_full, .enum_nonexhaustive => {
|
||||
const enum_full = ty.cast(Payload.EnumFull).?.data;
|
||||
return try arena.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0));
|
||||
},
|
||||
.enum_simple => {
|
||||
const enum_simple = ty.castTag(.enum_simple).?.data;
|
||||
return try arena.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0));
|
||||
},
|
||||
.enum_numbered => {
|
||||
const enum_numbered = ty.castTag(.enum_numbered).?.data;
|
||||
return try arena.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0));
|
||||
},
|
||||
.@"opaque" => {
|
||||
// TODO use declaration name
|
||||
return "opaque {}";
|
||||
},
|
||||
|
||||
.anyerror_void_error_union => return "anyerror!void",
|
||||
.const_slice_u8 => return "[]const u8",
|
||||
.fn_noreturn_no_args => return "fn() noreturn",
|
||||
.fn_void_no_args => return "fn() void",
|
||||
.fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn",
|
||||
.fn_ccc_void_no_args => return "fn() callconv(.C) void",
|
||||
.single_const_pointer_to_comptime_int => return "*const comptime_int",
|
||||
.manyptr_u8 => return "[*]u8",
|
||||
.manyptr_const_u8 => return "[*]const u8",
|
||||
.atomic_order => return "AtomicOrder",
|
||||
.atomic_rmw_op => return "AtomicRmwOp",
|
||||
.calling_convention => return "CallingConvention",
|
||||
.address_space => return "AddressSpace",
|
||||
.float_mode => return "FloatMode",
|
||||
.reduce_op => return "ReduceOp",
|
||||
.call_options => return "CallOptions",
|
||||
.export_options => return "ExportOptions",
|
||||
.extern_options => return "ExternOptions",
|
||||
.type_info => return "TypeInfo",
|
||||
|
||||
else => {
|
||||
// TODO this is wasteful and also an incorrect implementation of `@typeName`
|
||||
var buf = std.ArrayList(u8).init(arena);
|
||||
try buf.writer().print("{}", .{ty});
|
||||
return try buf.toOwnedSliceSentinel(0);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Anything that reports hasCodeGenBits() false returns false here as well.
|
||||
/// `generic_poison` will return false.
|
||||
pub fn requiresComptime(ty: Type) bool {
|
||||
|
@ -24,11 +24,11 @@ test {
|
||||
_ = @import("behavior/defer.zig");
|
||||
_ = @import("behavior/enum.zig");
|
||||
_ = @import("behavior/error.zig");
|
||||
_ = @import("behavior/error.zig");
|
||||
_ = @import("behavior/generics.zig");
|
||||
_ = @import("behavior/hasdecl.zig");
|
||||
_ = @import("behavior/hasfield.zig");
|
||||
_ = @import("behavior/if.zig");
|
||||
_ = @import("behavior/import.zig");
|
||||
_ = @import("behavior/int128.zig");
|
||||
_ = @import("behavior/member_func.zig");
|
||||
_ = @import("behavior/null.zig");
|
||||
@ -73,7 +73,9 @@ test {
|
||||
_ = @import("behavior/slice.zig");
|
||||
_ = @import("behavior/struct_llvm.zig");
|
||||
_ = @import("behavior/switch.zig");
|
||||
_ = @import("behavior/undefined.zig");
|
||||
_ = @import("behavior/union.zig");
|
||||
_ = @import("behavior/void.zig");
|
||||
_ = @import("behavior/widening.zig");
|
||||
|
||||
if (builtin.zig_is_stage2) {
|
||||
@ -151,7 +153,6 @@ test {
|
||||
_ = @import("behavior/fn_in_struct_in_comptime.zig");
|
||||
_ = @import("behavior/for_stage1.zig");
|
||||
_ = @import("behavior/if_stage1.zig");
|
||||
_ = @import("behavior/import.zig");
|
||||
_ = @import("behavior/incomplete_struct_param_tld.zig");
|
||||
_ = @import("behavior/inttoptr.zig");
|
||||
_ = @import("behavior/ir_block_deps.zig");
|
||||
@ -183,13 +184,11 @@ test {
|
||||
_ = @import("behavior/type.zig");
|
||||
_ = @import("behavior/type_info.zig");
|
||||
_ = @import("behavior/typename.zig");
|
||||
_ = @import("behavior/undefined.zig");
|
||||
_ = @import("behavior/union_stage1.zig");
|
||||
_ = @import("behavior/union_with_members.zig");
|
||||
_ = @import("behavior/usingnamespace_stage1.zig");
|
||||
_ = @import("behavior/var_args.zig");
|
||||
_ = @import("behavior/vector.zig");
|
||||
_ = @import("behavior/void.zig");
|
||||
if (builtin.target.cpu.arch == .wasm32) {
|
||||
_ = @import("behavior/wasm.zig");
|
||||
}
|
||||
|
@ -583,3 +583,25 @@ test "peer type resolution with enum literal" {
|
||||
try expect(Items.two == .two);
|
||||
try expect(.two == Items.two);
|
||||
}
|
||||
|
||||
const MultipleChoice = enum(u32) {
|
||||
A = 20,
|
||||
B = 40,
|
||||
C = 60,
|
||||
D = 1000,
|
||||
};
|
||||
|
||||
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
|
||||
try expect(@enumToInt(x) == 60);
|
||||
try expect(1234 == switch (x) {
|
||||
MultipleChoice.A => 1,
|
||||
MultipleChoice.B => 2,
|
||||
MultipleChoice.C => @as(u32, 1234),
|
||||
MultipleChoice.D => 4,
|
||||
});
|
||||
}
|
||||
|
||||
test "enum with specified tag values" {
|
||||
try testEnumWithSpecifiedTagValues(MultipleChoice.C);
|
||||
comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
|
||||
}
|
||||
|
@ -2,28 +2,6 @@ const expect = @import("std").testing.expect;
|
||||
const mem = @import("std").mem;
|
||||
const Tag = @import("std").meta.Tag;
|
||||
|
||||
const MultipleChoice = enum(u32) {
|
||||
A = 20,
|
||||
B = 40,
|
||||
C = 60,
|
||||
D = 1000,
|
||||
};
|
||||
|
||||
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
|
||||
try expect(@enumToInt(x) == 60);
|
||||
try expect(1234 == switch (x) {
|
||||
MultipleChoice.A => 1,
|
||||
MultipleChoice.B => 2,
|
||||
MultipleChoice.C => @as(u32, 1234),
|
||||
MultipleChoice.D => 4,
|
||||
});
|
||||
}
|
||||
|
||||
test "enum with specified tag values" {
|
||||
try testEnumWithSpecifiedTagValues(MultipleChoice.C);
|
||||
comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C);
|
||||
}
|
||||
|
||||
test "non-exhaustive enum" {
|
||||
const S = struct {
|
||||
const E = enum(u8) {
|
||||
|
@ -163,3 +163,84 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {
|
||||
test "function with complex callconv and return type expressions" {
|
||||
try expect(fComplexCallconvRet(3).x == 9);
|
||||
}
|
||||
|
||||
test "pass by non-copying value" {
|
||||
try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
|
||||
}
|
||||
|
||||
const Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
|
||||
fn addPointCoords(pt: Point) i32 {
|
||||
return pt.x + pt.y;
|
||||
}
|
||||
|
||||
test "pass by non-copying value through var arg" {
|
||||
try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
|
||||
}
|
||||
|
||||
fn addPointCoordsVar(pt: anytype) !i32 {
|
||||
comptime try expect(@TypeOf(pt) == Point);
|
||||
return pt.x + pt.y;
|
||||
}
|
||||
|
||||
test "pass by non-copying value as method" {
|
||||
var pt = Point2{ .x = 1, .y = 2 };
|
||||
try expect(pt.addPointCoords() == 3);
|
||||
}
|
||||
|
||||
const Point2 = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
||||
fn addPointCoords(self: Point2) i32 {
|
||||
return self.x + self.y;
|
||||
}
|
||||
};
|
||||
|
||||
test "pass by non-copying value as method, which is generic" {
|
||||
var pt = Point3{ .x = 1, .y = 2 };
|
||||
try expect(pt.addPointCoords(i32) == 3);
|
||||
}
|
||||
|
||||
const Point3 = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
||||
fn addPointCoords(self: Point3, comptime T: type) i32 {
|
||||
_ = T;
|
||||
return self.x + self.y;
|
||||
}
|
||||
};
|
||||
|
||||
test "pass by non-copying value as method, at comptime" {
|
||||
comptime {
|
||||
var pt = Point2{ .x = 1, .y = 2 };
|
||||
try expect(pt.addPointCoords() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
test "implicit cast fn call result to optional in field result" {
|
||||
const S = struct {
|
||||
fn entry() !void {
|
||||
var x = Foo{
|
||||
.field = optionalPtr(),
|
||||
};
|
||||
try expect(x.field.?.* == 999);
|
||||
}
|
||||
|
||||
const glob: i32 = 999;
|
||||
|
||||
fn optionalPtr() *const i32 {
|
||||
return &glob;
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
field: ?*const i32,
|
||||
};
|
||||
};
|
||||
try S.entry();
|
||||
comptime try S.entry();
|
||||
}
|
||||
|
@ -56,87 +56,6 @@ fn numberLiteralArg(a: anytype) !void {
|
||||
try expect(a == 3);
|
||||
}
|
||||
|
||||
test "pass by non-copying value" {
|
||||
try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
|
||||
}
|
||||
|
||||
const Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
|
||||
fn addPointCoords(pt: Point) i32 {
|
||||
return pt.x + pt.y;
|
||||
}
|
||||
|
||||
test "pass by non-copying value through var arg" {
|
||||
try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3);
|
||||
}
|
||||
|
||||
fn addPointCoordsVar(pt: anytype) !i32 {
|
||||
comptime try expect(@TypeOf(pt) == Point);
|
||||
return pt.x + pt.y;
|
||||
}
|
||||
|
||||
test "pass by non-copying value as method" {
|
||||
var pt = Point2{ .x = 1, .y = 2 };
|
||||
try expect(pt.addPointCoords() == 3);
|
||||
}
|
||||
|
||||
const Point2 = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
||||
fn addPointCoords(self: Point2) i32 {
|
||||
return self.x + self.y;
|
||||
}
|
||||
};
|
||||
|
||||
test "pass by non-copying value as method, which is generic" {
|
||||
var pt = Point3{ .x = 1, .y = 2 };
|
||||
try expect(pt.addPointCoords(i32) == 3);
|
||||
}
|
||||
|
||||
const Point3 = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
|
||||
fn addPointCoords(self: Point3, comptime T: type) i32 {
|
||||
_ = T;
|
||||
return self.x + self.y;
|
||||
}
|
||||
};
|
||||
|
||||
test "pass by non-copying value as method, at comptime" {
|
||||
comptime {
|
||||
var pt = Point2{ .x = 1, .y = 2 };
|
||||
try expect(pt.addPointCoords() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
test "implicit cast fn call result to optional in field result" {
|
||||
const S = struct {
|
||||
fn entry() !void {
|
||||
var x = Foo{
|
||||
.field = optionalPtr(),
|
||||
};
|
||||
try expect(x.field.?.* == 999);
|
||||
}
|
||||
|
||||
const glob: i32 = 999;
|
||||
|
||||
fn optionalPtr() *const i32 {
|
||||
return &glob;
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
field: ?*const i32,
|
||||
};
|
||||
};
|
||||
try S.entry();
|
||||
comptime try S.entry();
|
||||
}
|
||||
|
||||
test "function call with anon list literal" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
|
@ -60,3 +60,59 @@ test "ignore lval with underscore (for loop)" {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
test "basic for loop" {
|
||||
const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
|
||||
|
||||
var buffer: [expected_result.len]u8 = undefined;
|
||||
var buf_index: usize = 0;
|
||||
|
||||
const array = [_]u8{ 9, 8, 7, 6 };
|
||||
for (array) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (array) |item, index| {
|
||||
_ = item;
|
||||
buffer[buf_index] = @intCast(u8, index);
|
||||
buf_index += 1;
|
||||
}
|
||||
const array_ptr = &array;
|
||||
for (array_ptr) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (array_ptr) |item, index| {
|
||||
_ = item;
|
||||
buffer[buf_index] = @intCast(u8, index);
|
||||
buf_index += 1;
|
||||
}
|
||||
const unknown_size: []const u8 = &array;
|
||||
for (unknown_size) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (unknown_size) |_, index| {
|
||||
buffer[buf_index] = @intCast(u8, index);
|
||||
buf_index += 1;
|
||||
}
|
||||
|
||||
try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
|
||||
}
|
||||
|
||||
test "for with null and T peer types and inferred result location type" {
|
||||
const S = struct {
|
||||
fn doTheTest(slice: []const u8) !void {
|
||||
if (for (slice) |item| {
|
||||
if (item == 10) {
|
||||
break item;
|
||||
}
|
||||
} else null) |v| {
|
||||
_ = v;
|
||||
@panic("fail");
|
||||
}
|
||||
}
|
||||
};
|
||||
try S.doTheTest(&[_]u8{ 1, 2 });
|
||||
comptime try S.doTheTest(&[_]u8{ 1, 2 });
|
||||
}
|
||||
|
@ -26,45 +26,6 @@ fn mangleString(s: []u8) void {
|
||||
}
|
||||
}
|
||||
|
||||
test "basic for loop" {
|
||||
const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
|
||||
|
||||
var buffer: [expected_result.len]u8 = undefined;
|
||||
var buf_index: usize = 0;
|
||||
|
||||
const array = [_]u8{ 9, 8, 7, 6 };
|
||||
for (array) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (array) |item, index| {
|
||||
_ = item;
|
||||
buffer[buf_index] = @intCast(u8, index);
|
||||
buf_index += 1;
|
||||
}
|
||||
const array_ptr = &array;
|
||||
for (array_ptr) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (array_ptr) |item, index| {
|
||||
_ = item;
|
||||
buffer[buf_index] = @intCast(u8, index);
|
||||
buf_index += 1;
|
||||
}
|
||||
const unknown_size: []const u8 = &array;
|
||||
for (unknown_size) |item| {
|
||||
buffer[buf_index] = item;
|
||||
buf_index += 1;
|
||||
}
|
||||
for (unknown_size) |_, index| {
|
||||
buffer[buf_index] = @intCast(u8, index);
|
||||
buf_index += 1;
|
||||
}
|
||||
|
||||
try expect(mem.eql(u8, buffer[0..buf_index], &expected_result));
|
||||
}
|
||||
|
||||
test "2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) !void {
|
||||
@ -82,23 +43,6 @@ test "2 break statements and an else" {
|
||||
comptime try S.entry(true, false);
|
||||
}
|
||||
|
||||
test "for with null and T peer types and inferred result location type" {
|
||||
const S = struct {
|
||||
fn doTheTest(slice: []const u8) !void {
|
||||
if (for (slice) |item| {
|
||||
if (item == 10) {
|
||||
break item;
|
||||
}
|
||||
} else null) |v| {
|
||||
_ = v;
|
||||
@panic("fail");
|
||||
}
|
||||
}
|
||||
};
|
||||
try S.doTheTest(&[_]u8{ 1, 2 });
|
||||
comptime try S.doTheTest(&[_]u8{ 1, 2 });
|
||||
}
|
||||
|
||||
test "for copies its payload" {
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
|
@ -3,7 +3,7 @@ const expectEqual = @import("std").testing.expectEqual;
|
||||
const a_namespace = @import("import/a_namespace.zig");
|
||||
|
||||
test "call fn via namespace lookup" {
|
||||
try expectEqual(@as(i32, 1234), a_namespace.foo());
|
||||
try expect(@as(i32, 1234) == a_namespace.foo());
|
||||
}
|
||||
|
||||
test "importing the same thing gives the same import" {
|
||||
@ -14,7 +14,7 @@ test "import in non-toplevel scope" {
|
||||
const S = struct {
|
||||
usingnamespace @import("import/a_namespace.zig");
|
||||
};
|
||||
try expectEqual(@as(i32, 1234), S.foo());
|
||||
try expect(@as(i32, 1234) == S.foo());
|
||||
}
|
||||
|
||||
test "import empty file" {
|
||||
|
@ -115,3 +115,28 @@ test "optional pointer to 0 bit type null value at runtime" {
|
||||
var x: ?*EmptyStruct = null;
|
||||
try expect(x == null);
|
||||
}
|
||||
|
||||
test "if var maybe pointer" {
|
||||
try expect(shouldBeAPlus1(Particle{
|
||||
.a = 14,
|
||||
.b = 1,
|
||||
.c = 1,
|
||||
.d = 1,
|
||||
}) == 15);
|
||||
}
|
||||
fn shouldBeAPlus1(p: Particle) u64 {
|
||||
var maybe_particle: ?Particle = p;
|
||||
if (maybe_particle) |*particle| {
|
||||
particle.a += 1;
|
||||
}
|
||||
if (maybe_particle) |particle| {
|
||||
return particle.a;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
const Particle = struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
};
|
||||
|
@ -65,5 +65,5 @@ test "assign undefined to struct with method" {
|
||||
|
||||
test "type name of undefined" {
|
||||
const x = undefined;
|
||||
try expect(mem.eql(u8, @typeName(@TypeOf(x)), "(undefined)"));
|
||||
try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)"));
|
||||
}
|
||||
|
@ -153,6 +153,20 @@ test "while with optional as condition with else" {
|
||||
try expect(got_else == 1);
|
||||
}
|
||||
|
||||
test "while with error union condition" {
|
||||
numbers_left = 10;
|
||||
var sum: i32 = 0;
|
||||
var got_else: i32 = 0;
|
||||
while (getNumberOrErr()) |value| {
|
||||
sum += value;
|
||||
} else |err| {
|
||||
try expect(err == error.OutOfNumbers);
|
||||
got_else += 1;
|
||||
}
|
||||
try expect(sum == 45);
|
||||
try expect(got_else == 1);
|
||||
}
|
||||
|
||||
test "while on bool with else result follow else prong" {
|
||||
const result = while (returnFalse()) {
|
||||
break @as(i32, 10);
|
||||
@ -199,3 +213,26 @@ fn returnFalse() bool {
|
||||
fn returnTrue() bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
test "return with implicit cast from while loop" {
|
||||
returnWithImplicitCastFromWhileLoopTest() catch unreachable;
|
||||
}
|
||||
fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
|
||||
while (true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
test "while on error union with else result follow else prong" {
|
||||
const result = while (returnError()) |value| {
|
||||
break value;
|
||||
} else |_| @as(i32, 2);
|
||||
try expect(result == 2);
|
||||
}
|
||||
|
||||
test "while on error union with else result follow break prong" {
|
||||
const result = while (returnSuccess(10)) |value| {
|
||||
break value;
|
||||
} else |_| @as(i32, 2);
|
||||
try expect(result == 10);
|
||||
}
|
||||
|
@ -1,76 +1,6 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "return with implicit cast from while loop" {
|
||||
returnWithImplicitCastFromWhileLoopTest() catch unreachable;
|
||||
}
|
||||
fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
|
||||
while (true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
test "while with error union condition" {
|
||||
numbers_left = 10;
|
||||
var sum: i32 = 0;
|
||||
var got_else: i32 = 0;
|
||||
while (getNumberOrErr()) |value| {
|
||||
sum += value;
|
||||
} else |err| {
|
||||
try expect(err == error.OutOfNumbers);
|
||||
got_else += 1;
|
||||
}
|
||||
try expect(sum == 45);
|
||||
try expect(got_else == 1);
|
||||
}
|
||||
|
||||
var numbers_left: i32 = undefined;
|
||||
fn getNumberOrErr() anyerror!i32 {
|
||||
return if (numbers_left == 0) error.OutOfNumbers else x: {
|
||||
numbers_left -= 1;
|
||||
break :x numbers_left;
|
||||
};
|
||||
}
|
||||
fn getNumberOrNull() ?i32 {
|
||||
return if (numbers_left == 0) null else x: {
|
||||
numbers_left -= 1;
|
||||
break :x numbers_left;
|
||||
};
|
||||
}
|
||||
|
||||
test "while on error union with else result follow else prong" {
|
||||
const result = while (returnError()) |value| {
|
||||
break value;
|
||||
} else |_| @as(i32, 2);
|
||||
try expect(result == 2);
|
||||
}
|
||||
|
||||
test "while on error union with else result follow break prong" {
|
||||
const result = while (returnSuccess(10)) |value| {
|
||||
break value;
|
||||
} else |_| @as(i32, 2);
|
||||
try expect(result == 10);
|
||||
}
|
||||
|
||||
fn returnNull() ?i32 {
|
||||
return null;
|
||||
}
|
||||
fn returnOptional(x: i32) ?i32 {
|
||||
return x;
|
||||
}
|
||||
fn returnError() anyerror!i32 {
|
||||
return error.YouWantedAnError;
|
||||
}
|
||||
fn returnSuccess(x: i32) anyerror!i32 {
|
||||
return x;
|
||||
}
|
||||
fn returnFalse() bool {
|
||||
return false;
|
||||
}
|
||||
fn returnTrue() bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
test "while bool 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) !void {
|
||||
|
@ -2674,7 +2674,7 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\ }
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:9: error: expected type 'error{Hi}', found '(enum literal)'",
|
||||
"tmp.zig:3:9: error: expected type 'error{Hi}', found '@Type(.EnumLiteral)'",
|
||||
});
|
||||
|
||||
ctx.objErrStage1("@sizeOf bad type",
|
||||
@ -2682,7 +2682,7 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\ return @sizeOf(@TypeOf(null));
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:2:20: error: no size available for type '(null)'",
|
||||
"tmp.zig:2:20: error: no size available for type '@Type(.Null)'",
|
||||
});
|
||||
|
||||
ctx.objErrStage1("generic function where return type is self-referenced",
|
||||
@ -5783,7 +5783,7 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\
|
||||
\\export fn entry() usize { return @sizeOf(@TypeOf(a)); }
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:1:16: error: expected type '*u8', found '(null)'",
|
||||
"tmp.zig:1:16: error: expected type '*u8', found '@Type(.Null)'",
|
||||
});
|
||||
|
||||
ctx.objErrStage1("indexing an array of size zero",
|
||||
@ -7506,12 +7506,12 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\};
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:2:4: error: variable of type '*const comptime_int' must be const or comptime",
|
||||
"tmp.zig:6:4: error: variable of type '(undefined)' must be const or comptime",
|
||||
"tmp.zig:6:4: error: variable of type '@Type(.Undefined)' must be const or comptime",
|
||||
"tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime",
|
||||
"tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
|
||||
"tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime",
|
||||
"tmp.zig:14:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type",
|
||||
"tmp.zig:18:4: error: variable of type '(null)' must be const or comptime",
|
||||
"tmp.zig:18:4: error: variable of type '@Type(.Null)' must be const or comptime",
|
||||
"tmp.zig:22:4: error: variable of type 'Opaque' not allowed",
|
||||
"tmp.zig:26:4: error: variable of type 'type' must be const or comptime",
|
||||
"tmp.zig:30:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
|
||||
@ -8278,8 +8278,8 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:2:18: error: Opaque return type 'FooType' not allowed",
|
||||
"tmp.zig:1:1: note: type declared here",
|
||||
"tmp.zig:5:18: error: Null return type '(null)' not allowed",
|
||||
"tmp.zig:8:18: error: Undefined return type '(undefined)' not allowed",
|
||||
"tmp.zig:5:18: error: Null return type '@Type(.Null)' not allowed",
|
||||
"tmp.zig:8:18: error: Undefined return type '@Type(.Undefined)' not allowed",
|
||||
});
|
||||
|
||||
ctx.objErrStage1("generic function returning opaque type",
|
||||
@ -8300,9 +8300,9 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
"tmp.zig:6:16: error: call to generic function with Opaque return type 'FooType' not allowed",
|
||||
"tmp.zig:2:1: note: function declared here",
|
||||
"tmp.zig:1:1: note: type declared here",
|
||||
"tmp.zig:9:16: error: call to generic function with Null return type '(null)' not allowed",
|
||||
"tmp.zig:9:16: error: call to generic function with Null return type '@Type(.Null)' not allowed",
|
||||
"tmp.zig:2:1: note: function declared here",
|
||||
"tmp.zig:12:16: error: call to generic function with Undefined return type '(undefined)' not allowed",
|
||||
"tmp.zig:12:16: error: call to generic function with Undefined return type '@Type(.Undefined)' not allowed",
|
||||
"tmp.zig:2:1: note: function declared here",
|
||||
});
|
||||
|
||||
@ -8329,9 +8329,9 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:3:28: error: parameter of opaque type 'FooType' not allowed",
|
||||
"tmp.zig:8:28: error: parameter of type '(null)' not allowed",
|
||||
"tmp.zig:8:28: error: parameter of type '@Type(.Null)' not allowed",
|
||||
"tmp.zig:12:11: error: parameter of opaque type 'FooType' not allowed",
|
||||
"tmp.zig:17:11: error: parameter of type '(null)' not allowed",
|
||||
"tmp.zig:17:11: error: parameter of type '@Type(.Null)' not allowed",
|
||||
});
|
||||
|
||||
ctx.objErrStage1( // fixed bug #2032
|
||||
|
Loading…
Reference in New Issue
Block a user