mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
stage2: LLVM backend: implement wrap_optional AIR
and move over some passing tests
This commit is contained in:
parent
55eea3b045
commit
cacd5366a6
@ -2341,10 +2341,33 @@ pub const FuncGen = struct {
|
||||
}
|
||||
|
||||
fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
|
||||
return self.todo("implement llvm codegen for 'airWrapOptional'", .{});
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const operand_ty = self.air.typeOf(ty_op.operand);
|
||||
const non_null_bit = self.context.intType(1).constAllOnes();
|
||||
if (!operand_ty.hasCodeGenBits()) return non_null_bit;
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
const optional_ty = self.air.typeOfIndex(inst);
|
||||
if (optional_ty.isPtrLikeOptional()) return operand;
|
||||
const llvm_optional_ty = try self.dg.llvmType(optional_ty);
|
||||
if (isByRef(optional_ty)) {
|
||||
const optional_ptr = self.buildAlloca(llvm_optional_ty);
|
||||
const payload_ptr = self.builder.buildStructGEP(optional_ptr, 0, "");
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
const payload_ty = operand_ty.optionalChild(&buf);
|
||||
var ptr_ty_payload: Type.Payload.ElemType = .{
|
||||
.base = .{ .tag = .single_mut_pointer },
|
||||
.data = payload_ty,
|
||||
};
|
||||
const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base);
|
||||
self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic);
|
||||
const non_null_ptr = self.builder.buildStructGEP(optional_ptr, 1, "");
|
||||
_ = self.builder.buildStore(non_null_bit, non_null_ptr);
|
||||
return optional_ptr;
|
||||
}
|
||||
const partial = self.builder.buildInsertValue(llvm_optional_ty.getUndef(), operand, 0, "");
|
||||
return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
|
||||
}
|
||||
|
||||
fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
|
||||
@ -28,6 +28,7 @@ test {
|
||||
_ = @import("behavior/member_func.zig");
|
||||
_ = @import("behavior/optional.zig");
|
||||
_ = @import("behavior/pointers.zig");
|
||||
_ = @import("behavior/pub_enum.zig");
|
||||
_ = @import("behavior/slice.zig");
|
||||
_ = @import("behavior/sizeof_and_typeof.zig");
|
||||
_ = @import("behavior/struct.zig");
|
||||
@ -140,7 +141,6 @@ test {
|
||||
_ = @import("behavior/pointers_stage1.zig");
|
||||
_ = @import("behavior/popcount.zig");
|
||||
_ = @import("behavior/ptrcast.zig");
|
||||
_ = @import("behavior/pub_enum.zig");
|
||||
_ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
|
||||
_ = @import("behavior/reflection.zig");
|
||||
{
|
||||
|
||||
@ -411,3 +411,38 @@ test "use of declaration with same name as primitive" {
|
||||
const c: @"u8" = 300;
|
||||
try expect(c == 300);
|
||||
}
|
||||
|
||||
fn emptyFn() void {}
|
||||
|
||||
test "constant equal function pointers" {
|
||||
const alias = emptyFn;
|
||||
try expect(comptime x: {
|
||||
break :x emptyFn == alias;
|
||||
});
|
||||
}
|
||||
|
||||
test "multiline string literal is null terminated" {
|
||||
const s1 =
|
||||
\\one
|
||||
\\two)
|
||||
\\three
|
||||
;
|
||||
const s2 = "one\ntwo)\nthree";
|
||||
try expect(std.cstr.cmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
test "self reference through fn ptr field" {
|
||||
const S = struct {
|
||||
const A = struct {
|
||||
f: fn (A) u8,
|
||||
};
|
||||
|
||||
fn foo(a: A) u8 {
|
||||
_ = a;
|
||||
return 12;
|
||||
}
|
||||
};
|
||||
var a: S.A = undefined;
|
||||
a.f = S.foo;
|
||||
try expect(a.f(a) == 12);
|
||||
}
|
||||
|
||||
@ -217,3 +217,154 @@ const vertices = [_]Vertex{
|
||||
.b = 1.0,
|
||||
},
|
||||
};
|
||||
|
||||
test "statically initialized list" {
|
||||
try expect(static_point_list[0].x == 1);
|
||||
try expect(static_point_list[0].y == 2);
|
||||
try expect(static_point_list[1].x == 3);
|
||||
try expect(static_point_list[1].y == 4);
|
||||
}
|
||||
const Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
const static_point_list = [_]Point{
|
||||
makePoint(1, 2),
|
||||
makePoint(3, 4),
|
||||
};
|
||||
fn makePoint(x: i32, y: i32) Point {
|
||||
return Point{
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
}
|
||||
|
||||
test "statically initialized array literal" {
|
||||
const y: [4]u8 = st_init_arr_lit_x;
|
||||
try expect(y[3] == 4);
|
||||
}
|
||||
const st_init_arr_lit_x = [_]u8{ 1, 2, 3, 4 };
|
||||
|
||||
const CmdFn = struct {
|
||||
name: []const u8,
|
||||
func: fn (i32) i32,
|
||||
};
|
||||
|
||||
const cmd_fns = [_]CmdFn{
|
||||
CmdFn{
|
||||
.name = "one",
|
||||
.func = one,
|
||||
},
|
||||
CmdFn{
|
||||
.name = "two",
|
||||
.func = two,
|
||||
},
|
||||
CmdFn{
|
||||
.name = "three",
|
||||
.func = three,
|
||||
},
|
||||
};
|
||||
fn one(value: i32) i32 {
|
||||
return value + 1;
|
||||
}
|
||||
fn two(value: i32) i32 {
|
||||
return value + 2;
|
||||
}
|
||||
fn three(value: i32) i32 {
|
||||
return value + 3;
|
||||
}
|
||||
|
||||
fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
|
||||
var result: i32 = start_value;
|
||||
comptime var i = 0;
|
||||
inline while (i < cmd_fns.len) : (i += 1) {
|
||||
if (cmd_fns[i].name[0] == prefix_char) {
|
||||
result = cmd_fns[i].func(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
test "comptime iterate over fn ptr list" {
|
||||
try expect(performFn('t', 1) == 6);
|
||||
try expect(performFn('o', 0) == 1);
|
||||
try expect(performFn('w', 99) == 99);
|
||||
}
|
||||
|
||||
test "create global array with for loop" {
|
||||
try expect(global_array[5] == 5 * 5);
|
||||
try expect(global_array[9] == 9 * 9);
|
||||
}
|
||||
|
||||
const global_array = x: {
|
||||
var result: [10]usize = undefined;
|
||||
for (result) |*item, index| {
|
||||
item.* = index * index;
|
||||
}
|
||||
break :x result;
|
||||
};
|
||||
|
||||
fn generateTable(comptime T: type) [1010]T {
|
||||
var res: [1010]T = undefined;
|
||||
var i: usize = 0;
|
||||
while (i < 1010) : (i += 1) {
|
||||
res[i] = @intCast(T, i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
fn doesAlotT(comptime T: type, value: usize) T {
|
||||
@setEvalBranchQuota(5000);
|
||||
const table = comptime blk: {
|
||||
break :blk generateTable(T);
|
||||
};
|
||||
return table[value];
|
||||
}
|
||||
|
||||
test "@setEvalBranchQuota at same scope as generic function call" {
|
||||
try expect(doesAlotT(u32, 2) == 2);
|
||||
}
|
||||
|
||||
pub const Info = struct {
|
||||
version: u8,
|
||||
};
|
||||
|
||||
pub const diamond_info = Info{ .version = 0 };
|
||||
|
||||
test "comptime modification of const struct field" {
|
||||
comptime {
|
||||
var res = diamond_info;
|
||||
res.version = 1;
|
||||
try expect(diamond_info.version == 0);
|
||||
try expect(res.version == 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "refer to the type of a generic function" {
|
||||
const Func = fn (type) void;
|
||||
const f: Func = doNothingWithType;
|
||||
f(i32);
|
||||
}
|
||||
|
||||
fn doNothingWithType(comptime T: type) void {
|
||||
_ = T;
|
||||
}
|
||||
|
||||
test "zero extend from u0 to u1" {
|
||||
var zero_u0: u0 = 0;
|
||||
var zero_u1: u1 = zero_u0;
|
||||
try expect(zero_u1 == 0);
|
||||
}
|
||||
|
||||
test "return 0 from function that has u0 return type" {
|
||||
const S = struct {
|
||||
fn foo_zero() u0 {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
comptime {
|
||||
if (S.foo_zero() != 0) {
|
||||
@compileError("test failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,27 +2,6 @@ const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
test "statically initialized list" {
|
||||
try expect(static_point_list[0].x == 1);
|
||||
try expect(static_point_list[0].y == 2);
|
||||
try expect(static_point_list[1].x == 3);
|
||||
try expect(static_point_list[1].y == 4);
|
||||
}
|
||||
const Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
const static_point_list = [_]Point{
|
||||
makePoint(1, 2),
|
||||
makePoint(3, 4),
|
||||
};
|
||||
fn makePoint(x: i32, y: i32) Point {
|
||||
return Point{
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
}
|
||||
|
||||
test "static eval list init" {
|
||||
try expect(static_vec3.data[2] == 1.0);
|
||||
try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
|
||||
@ -54,27 +33,6 @@ var st_init_str_foo = StInitStrFoo{
|
||||
.y = true,
|
||||
};
|
||||
|
||||
test "statically initialized array literal" {
|
||||
const y: [4]u8 = st_init_arr_lit_x;
|
||||
try expect(y[3] == 4);
|
||||
}
|
||||
const st_init_arr_lit_x = [_]u8{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
};
|
||||
|
||||
test "const slice" {
|
||||
comptime {
|
||||
const a = "1234567890";
|
||||
try expect(a.len == 10);
|
||||
const b = a[1..2];
|
||||
try expect(b.len == 1);
|
||||
try expect(b[0] == '2');
|
||||
}
|
||||
}
|
||||
|
||||
test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {
|
||||
var runtime = [1]i32{3};
|
||||
comptime var i: usize = 0;
|
||||
@ -87,52 +45,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
|
||||
}
|
||||
}
|
||||
|
||||
const CmdFn = struct {
|
||||
name: []const u8,
|
||||
func: fn (i32) i32,
|
||||
};
|
||||
|
||||
const cmd_fns = [_]CmdFn{
|
||||
CmdFn{
|
||||
.name = "one",
|
||||
.func = one,
|
||||
},
|
||||
CmdFn{
|
||||
.name = "two",
|
||||
.func = two,
|
||||
},
|
||||
CmdFn{
|
||||
.name = "three",
|
||||
.func = three,
|
||||
},
|
||||
};
|
||||
fn one(value: i32) i32 {
|
||||
return value + 1;
|
||||
}
|
||||
fn two(value: i32) i32 {
|
||||
return value + 2;
|
||||
}
|
||||
fn three(value: i32) i32 {
|
||||
return value + 3;
|
||||
}
|
||||
|
||||
fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
|
||||
var result: i32 = start_value;
|
||||
comptime var i = 0;
|
||||
inline while (i < cmd_fns.len) : (i += 1) {
|
||||
if (cmd_fns[i].name[0] == prefix_char) {
|
||||
result = cmd_fns[i].func(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
test "comptime iterate over fn ptr list" {
|
||||
try expect(performFn('t', 1) == 6);
|
||||
try expect(performFn('o', 0) == 1);
|
||||
try expect(performFn('w', 99) == 99);
|
||||
}
|
||||
|
||||
test "eval @setFloatMode at compile-time" {
|
||||
const result = comptime fnWithFloatMode();
|
||||
try expect(result == 1234.0);
|
||||
@ -204,19 +116,6 @@ const Foo = struct {
|
||||
var foo_contents = Foo{ .name = "a" };
|
||||
const foo_ref = &foo_contents;
|
||||
|
||||
test "create global array with for loop" {
|
||||
try expect(global_array[5] == 5 * 5);
|
||||
try expect(global_array[9] == 9 * 9);
|
||||
}
|
||||
|
||||
const global_array = x: {
|
||||
var result: [10]usize = undefined;
|
||||
for (result) |*item, index| {
|
||||
item.* = index * index;
|
||||
}
|
||||
break :x result;
|
||||
};
|
||||
|
||||
const hi1 = "hi";
|
||||
const hi2 = hi1;
|
||||
test "const global shares pointer with other same one" {
|
||||
@ -262,13 +161,6 @@ test "string literal used as comptime slice is memoized" {
|
||||
comptime try expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
|
||||
}
|
||||
|
||||
test "comptime slice of undefined pointer of length 0" {
|
||||
const slice1 = @as([*]i32, undefined)[0..0];
|
||||
try expect(slice1.len == 0);
|
||||
const slice2 = @as([*]i32, undefined)[100..100];
|
||||
try expect(slice2.len == 0);
|
||||
}
|
||||
|
||||
fn copyWithPartialInline(s: []u32, b: []u8) void {
|
||||
comptime var i: usize = 0;
|
||||
inline while (i < 4) : (i += 1) {
|
||||
@ -308,44 +200,6 @@ fn increment(value: *i32) void {
|
||||
value.* += 1;
|
||||
}
|
||||
|
||||
fn generateTable(comptime T: type) [1010]T {
|
||||
var res: [1010]T = undefined;
|
||||
var i: usize = 0;
|
||||
while (i < 1010) : (i += 1) {
|
||||
res[i] = @intCast(T, i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
fn doesAlotT(comptime T: type, value: usize) T {
|
||||
@setEvalBranchQuota(5000);
|
||||
const table = comptime blk: {
|
||||
break :blk generateTable(T);
|
||||
};
|
||||
return table[value];
|
||||
}
|
||||
|
||||
test "@setEvalBranchQuota at same scope as generic function call" {
|
||||
try expect(doesAlotT(u32, 2) == 2);
|
||||
}
|
||||
|
||||
test "comptime slice of slice preserves comptime var" {
|
||||
comptime {
|
||||
var buff: [10]u8 = undefined;
|
||||
buff[0..][0..][0] = 1;
|
||||
try expect(buff[0..][0..][0] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime slice of pointer preserves comptime var" {
|
||||
comptime {
|
||||
var buff: [10]u8 = undefined;
|
||||
var a = @ptrCast([*]u8, &buff);
|
||||
a[0..1][0] = 1;
|
||||
try expect(buff[0..][0..][0] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
const SingleFieldStruct = struct {
|
||||
x: i32,
|
||||
|
||||
@ -362,15 +216,6 @@ test "const ptr to comptime mutable data is not memoized" {
|
||||
}
|
||||
}
|
||||
|
||||
test "array concat of slices gives slice" {
|
||||
comptime {
|
||||
var a: []const u8 = "aoeu";
|
||||
var b: []const u8 = "asdf";
|
||||
const c = a ++ b;
|
||||
try expect(std.mem.eql(u8, c, "aoeuasdf"));
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime shlWithOverflow" {
|
||||
const ct_shifted: u64 = comptime amt: {
|
||||
var amt = @as(u64, 0);
|
||||
@ -401,43 +246,6 @@ test "runtime 128 bit integer division" {
|
||||
try expect(c == 15231399999);
|
||||
}
|
||||
|
||||
pub const Info = struct {
|
||||
version: u8,
|
||||
};
|
||||
|
||||
pub const diamond_info = Info{ .version = 0 };
|
||||
|
||||
test "comptime modification of const struct field" {
|
||||
comptime {
|
||||
var res = diamond_info;
|
||||
res.version = 1;
|
||||
try expect(diamond_info.version == 0);
|
||||
try expect(res.version == 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "slice of type" {
|
||||
comptime {
|
||||
var types_array = [_]type{ i32, f64, type };
|
||||
for (types_array) |T, i| {
|
||||
switch (i) {
|
||||
0 => try expect(T == i32),
|
||||
1 => try expect(T == f64),
|
||||
2 => try expect(T == type),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
for (types_array[0..]) |T, i| {
|
||||
switch (i) {
|
||||
0 => try expect(T == i32),
|
||||
1 => try expect(T == f64),
|
||||
2 => try expect(T == type),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Wrapper = struct {
|
||||
T: type,
|
||||
};
|
||||
@ -502,55 +310,12 @@ test "inline for with same type but different values" {
|
||||
try expect(res == 5);
|
||||
}
|
||||
|
||||
test "refer to the type of a generic function" {
|
||||
const Func = fn (type) void;
|
||||
const f: Func = doNothingWithType;
|
||||
f(i32);
|
||||
}
|
||||
|
||||
fn doNothingWithType(comptime T: type) void {
|
||||
_ = T;
|
||||
}
|
||||
|
||||
test "zero extend from u0 to u1" {
|
||||
var zero_u0: u0 = 0;
|
||||
var zero_u1: u1 = zero_u0;
|
||||
try expect(zero_u1 == 0);
|
||||
}
|
||||
|
||||
test "bit shift a u1" {
|
||||
var x: u1 = 1;
|
||||
var y = x << 0;
|
||||
try expect(y == 1);
|
||||
}
|
||||
|
||||
test "comptime pointer cast array and then slice" {
|
||||
const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
|
||||
const sliceA: []const u8 = ptrA[0..2];
|
||||
|
||||
const ptrB: [*]const u8 = &array;
|
||||
const sliceB: []const u8 = ptrB[0..2];
|
||||
|
||||
try expect(sliceA[1] == 2);
|
||||
try expect(sliceB[1] == 2);
|
||||
}
|
||||
|
||||
test "slice bounds in comptime concatenation" {
|
||||
const bs = comptime blk: {
|
||||
const b = "........1........";
|
||||
break :blk b[8..9];
|
||||
};
|
||||
const str = "" ++ bs;
|
||||
try expect(str.len == 1);
|
||||
try expect(std.mem.eql(u8, str, "1"));
|
||||
|
||||
const str2 = bs ++ "";
|
||||
try expect(str2.len == 1);
|
||||
try expect(std.mem.eql(u8, str2, "1"));
|
||||
}
|
||||
|
||||
test "comptime bitwise operators" {
|
||||
comptime {
|
||||
try expect(3 & 1 == 1);
|
||||
@ -602,19 +367,6 @@ test "comptime assign int to optional int" {
|
||||
}
|
||||
}
|
||||
|
||||
test "return 0 from function that has u0 return type" {
|
||||
const S = struct {
|
||||
fn foo_zero() u0 {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
comptime {
|
||||
if (S.foo_zero() != 0) {
|
||||
@compileError("test failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "two comptime calls with array default initialized to undefined" {
|
||||
const S = struct {
|
||||
const CrossTarget = struct {
|
||||
|
||||
@ -7,13 +7,6 @@ const builtin = @import("builtin");
|
||||
|
||||
fn emptyFn() void {}
|
||||
|
||||
test "constant equal function pointers" {
|
||||
const alias = emptyFn;
|
||||
try expect(comptime x: {
|
||||
break :x emptyFn == alias;
|
||||
});
|
||||
}
|
||||
|
||||
const addr1 = @ptrCast(*const u8, emptyFn);
|
||||
test "comptime cast fn to ptr" {
|
||||
const addr2 = @ptrCast(*const u8, emptyFn);
|
||||
@ -35,17 +28,7 @@ test "string escapes" {
|
||||
try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01");
|
||||
}
|
||||
|
||||
test "multiline string literal is null terminated" {
|
||||
const s1 =
|
||||
\\one
|
||||
\\two)
|
||||
\\three
|
||||
;
|
||||
const s2 = "one\ntwo)\nthree";
|
||||
try expect(std.cstr.cmp(s1, s2) == 0);
|
||||
}
|
||||
|
||||
test "explicit cast maybe pointers" {
|
||||
test "explicit cast optional pointers" {
|
||||
const a: ?*i32 = undefined;
|
||||
const b: ?*f32 = @ptrCast(?*f32, a);
|
||||
_ = b;
|
||||
@ -159,22 +142,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {
|
||||
}
|
||||
}
|
||||
|
||||
test "self reference through fn ptr field" {
|
||||
const S = struct {
|
||||
const A = struct {
|
||||
f: fn (A) u8,
|
||||
};
|
||||
|
||||
fn foo(a: A) u8 {
|
||||
_ = a;
|
||||
return 12;
|
||||
}
|
||||
};
|
||||
var a: S.A = undefined;
|
||||
a.f = S.foo;
|
||||
try expect(a.f(a) == 12);
|
||||
}
|
||||
|
||||
test "thread local variable" {
|
||||
const S = struct {
|
||||
threadlocal var t: i32 = 1234;
|
||||
@ -183,19 +150,6 @@ test "thread local variable" {
|
||||
try expect(S.t == 1235);
|
||||
}
|
||||
|
||||
test "nested optional field in struct" {
|
||||
const S2 = struct {
|
||||
y: u8,
|
||||
};
|
||||
const S1 = struct {
|
||||
x: ?S2,
|
||||
};
|
||||
var s = S1{
|
||||
.x = S2{ .y = 127 },
|
||||
};
|
||||
try expect(s.x.?.y == 127);
|
||||
}
|
||||
|
||||
fn maybe(x: bool) anyerror!?u32 {
|
||||
return switch (x) {
|
||||
true => @as(u32, 42),
|
||||
|
||||
@ -2,3 +2,37 @@ const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
|
||||
test "passing an optional integer as a parameter" {
|
||||
const S = struct {
|
||||
fn entry() bool {
|
||||
var x: i32 = 1234;
|
||||
return foo(x);
|
||||
}
|
||||
|
||||
fn foo(x: ?i32) bool {
|
||||
return x.? == 1234;
|
||||
}
|
||||
};
|
||||
try expect(S.entry());
|
||||
comptime try expect(S.entry());
|
||||
}
|
||||
|
||||
test "self-referential struct through a slice of optional" {
|
||||
const S = struct {
|
||||
const Node = struct {
|
||||
children: []?Node,
|
||||
data: ?u8,
|
||||
|
||||
fn new() Node {
|
||||
return Node{
|
||||
.children = undefined,
|
||||
.data = null,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var n = S.Node.new();
|
||||
try expect(n.data == null);
|
||||
}
|
||||
|
||||
@ -83,21 +83,6 @@ fn test_cmp_optional_non_optional() !void {
|
||||
};
|
||||
}
|
||||
|
||||
test "passing an optional integer as a parameter" {
|
||||
const S = struct {
|
||||
fn entry() bool {
|
||||
var x: i32 = 1234;
|
||||
return foo(x);
|
||||
}
|
||||
|
||||
fn foo(x: ?i32) bool {
|
||||
return x.? == 1234;
|
||||
}
|
||||
};
|
||||
try expect(S.entry());
|
||||
comptime try expect(S.entry());
|
||||
}
|
||||
|
||||
test "unwrap function call with optional pointer return value" {
|
||||
const S = struct {
|
||||
fn entry() !void {
|
||||
@ -139,25 +124,6 @@ test "nested orelse" {
|
||||
comptime try S.entry();
|
||||
}
|
||||
|
||||
test "self-referential struct through a slice of optional" {
|
||||
const S = struct {
|
||||
const Node = struct {
|
||||
children: []?Node,
|
||||
data: ?u8,
|
||||
|
||||
fn new() Node {
|
||||
return Node{
|
||||
.children = undefined,
|
||||
.data = null,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var n = S.Node.new();
|
||||
try expect(n.data == null);
|
||||
}
|
||||
|
||||
test "assigning to an unwrapped optional field in an inline loop" {
|
||||
comptime var maybe_pos_arg: ?comptime_int = null;
|
||||
inline for ("ab") |x| {
|
||||
|
||||
@ -20,6 +20,23 @@ test "slicing" {
|
||||
if (slice_rest.len != 10) unreachable;
|
||||
}
|
||||
|
||||
test "const slice" {
|
||||
comptime {
|
||||
const a = "1234567890";
|
||||
try expect(a.len == 10);
|
||||
const b = a[1..2];
|
||||
try expect(b.len == 1);
|
||||
try expect(b[0] == '2');
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime slice of undefined pointer of length 0" {
|
||||
const slice1 = @as([*]i32, undefined)[0..0];
|
||||
try expect(slice1.len == 0);
|
||||
const slice2 = @as([*]i32, undefined)[100..100];
|
||||
try expect(slice2.len == 0);
|
||||
}
|
||||
|
||||
test "slicing zero length array" {
|
||||
const s1 = ""[0..];
|
||||
const s2 = ([_]u32{})[0..];
|
||||
@ -389,3 +406,78 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
|
||||
// try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "comptime slice of slice preserves comptime var" {
|
||||
comptime {
|
||||
var buff: [10]u8 = undefined;
|
||||
buff[0..][0..][0] = 1;
|
||||
try expect(buff[0..][0..][0] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime slice of pointer preserves comptime var" {
|
||||
comptime {
|
||||
var buff: [10]u8 = undefined;
|
||||
var a = @ptrCast([*]u8, &buff);
|
||||
a[0..1][0] = 1;
|
||||
try expect(buff[0..][0..][0] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "array concat of slices gives slice" {
|
||||
comptime {
|
||||
var a: []const u8 = "aoeu";
|
||||
var b: []const u8 = "asdf";
|
||||
const c = a ++ b;
|
||||
try expect(std.mem.eql(u8, c, "aoeuasdf"));
|
||||
}
|
||||
}
|
||||
|
||||
test "slice of type" {
|
||||
comptime {
|
||||
var types_array = [_]type{ i32, f64, type };
|
||||
for (types_array) |T, i| {
|
||||
switch (i) {
|
||||
0 => try expect(T == i32),
|
||||
1 => try expect(T == f64),
|
||||
2 => try expect(T == type),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
for (types_array[0..]) |T, i| {
|
||||
switch (i) {
|
||||
0 => try expect(T == i32),
|
||||
1 => try expect(T == f64),
|
||||
2 => try expect(T == type),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime pointer cast array and then slice" {
|
||||
const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
|
||||
const sliceA: []const u8 = ptrA[0..2];
|
||||
|
||||
const ptrB: [*]const u8 = &array;
|
||||
const sliceB: []const u8 = ptrB[0..2];
|
||||
|
||||
try expect(sliceA[1] == 2);
|
||||
try expect(sliceB[1] == 2);
|
||||
}
|
||||
|
||||
test "slice bounds in comptime concatenation" {
|
||||
const bs = comptime blk: {
|
||||
const b = "........1........";
|
||||
break :blk b[8..9];
|
||||
};
|
||||
const str = "" ++ bs;
|
||||
try expect(str.len == 1);
|
||||
try expect(std.mem.eql(u8, str, "1"));
|
||||
|
||||
const str2 = bs ++ "";
|
||||
try expect(str2.len == 1);
|
||||
try expect(std.mem.eql(u8, str2, "1"));
|
||||
}
|
||||
|
||||
@ -111,3 +111,91 @@ test "while copies its payload" {
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "continue and break" {
|
||||
try runContinueAndBreakTest();
|
||||
try expect(continue_and_break_counter == 8);
|
||||
}
|
||||
var continue_and_break_counter: i32 = 0;
|
||||
fn runContinueAndBreakTest() !void {
|
||||
var i: i32 = 0;
|
||||
while (true) {
|
||||
continue_and_break_counter += 2;
|
||||
i += 1;
|
||||
if (i < 4) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
try expect(i == 4);
|
||||
}
|
||||
|
||||
test "while with optional as condition" {
|
||||
numbers_left = 10;
|
||||
var sum: i32 = 0;
|
||||
while (getNumberOrNull()) |value| {
|
||||
sum += value;
|
||||
}
|
||||
try expect(sum == 45);
|
||||
}
|
||||
|
||||
test "while with optional as condition with else" {
|
||||
numbers_left = 10;
|
||||
var sum: i32 = 0;
|
||||
var got_else: i32 = 0;
|
||||
while (getNumberOrNull()) |value| {
|
||||
sum += value;
|
||||
try expect(got_else == 0);
|
||||
} else {
|
||||
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);
|
||||
} else @as(i32, 2);
|
||||
try expect(result == 2);
|
||||
}
|
||||
|
||||
test "while on bool with else result follow break prong" {
|
||||
const result = while (returnTrue()) {
|
||||
break @as(i32, 10);
|
||||
} else @as(i32, 2);
|
||||
try expect(result == 10);
|
||||
}
|
||||
|
||||
test "while on optional with else result follow else prong" {
|
||||
const result = while (returnNull()) |value| {
|
||||
break value;
|
||||
} else @as(i32, 2);
|
||||
try expect(result == 2);
|
||||
}
|
||||
|
||||
test "while on optional with else result follow break prong" {
|
||||
const result = while (returnOptional(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;
|
||||
}
|
||||
|
||||
@ -1,24 +1,6 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "continue and break" {
|
||||
try runContinueAndBreakTest();
|
||||
try expect(continue_and_break_counter == 8);
|
||||
}
|
||||
var continue_and_break_counter: i32 = 0;
|
||||
fn runContinueAndBreakTest() !void {
|
||||
var i: i32 = 0;
|
||||
while (true) {
|
||||
continue_and_break_counter += 2;
|
||||
i += 1;
|
||||
if (i < 4) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
try expect(i == 4);
|
||||
}
|
||||
|
||||
test "return with implicit cast from while loop" {
|
||||
returnWithImplicitCastFromWhileLoopTest() catch unreachable;
|
||||
}
|
||||
@ -28,29 +10,6 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void {
|
||||
}
|
||||
}
|
||||
|
||||
test "while with optional as condition" {
|
||||
numbers_left = 10;
|
||||
var sum: i32 = 0;
|
||||
while (getNumberOrNull()) |value| {
|
||||
sum += value;
|
||||
}
|
||||
try expect(sum == 45);
|
||||
}
|
||||
|
||||
test "while with optional as condition with else" {
|
||||
numbers_left = 10;
|
||||
var sum: i32 = 0;
|
||||
var got_else: i32 = 0;
|
||||
while (getNumberOrNull()) |value| {
|
||||
sum += value;
|
||||
try expect(got_else == 0);
|
||||
} else {
|
||||
got_else += 1;
|
||||
}
|
||||
try expect(sum == 45);
|
||||
try expect(got_else == 1);
|
||||
}
|
||||
|
||||
test "while with error union condition" {
|
||||
numbers_left = 10;
|
||||
var sum: i32 = 0;
|
||||
@ -79,20 +38,6 @@ fn getNumberOrNull() ?i32 {
|
||||
};
|
||||
}
|
||||
|
||||
test "while on optional with else result follow else prong" {
|
||||
const result = while (returnNull()) |value| {
|
||||
break value;
|
||||
} else @as(i32, 2);
|
||||
try expect(result == 2);
|
||||
}
|
||||
|
||||
test "while on optional with else result follow break prong" {
|
||||
const result = while (returnOptional(10)) |value| {
|
||||
break value;
|
||||
} else @as(i32, 2);
|
||||
try expect(result == 10);
|
||||
}
|
||||
|
||||
test "while on error union with else result follow else prong" {
|
||||
const result = while (returnError()) |value| {
|
||||
break value;
|
||||
@ -107,20 +52,6 @@ test "while on error union with else result follow break prong" {
|
||||
try expect(result == 10);
|
||||
}
|
||||
|
||||
test "while on bool with else result follow else prong" {
|
||||
const result = while (returnFalse()) {
|
||||
break @as(i32, 10);
|
||||
} else @as(i32, 2);
|
||||
try expect(result == 2);
|
||||
}
|
||||
|
||||
test "while on bool with else result follow break prong" {
|
||||
const result = while (returnTrue()) {
|
||||
break @as(i32, 10);
|
||||
} else @as(i32, 2);
|
||||
try expect(result == 10);
|
||||
}
|
||||
|
||||
fn returnNull() ?i32 {
|
||||
return null;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user