mirror of
https://github.com/ziglang/zig.git
synced 2025-12-26 16:13:07 +00:00
* New AIR instruction: slice, which constructs a slice out of a pointer
and a length.
* AstGen: use `coerced_ty` for start and end expressions, use `none`
for the sentinel, and don't try to load the result of the slice
operation because it returns a by-value result.
* Sema: pointer arithmetic is extracted into analyzePointerArithmetic
and it is used by the implementation of slice.
- Also I implemented comptime pointer addition.
* Sema: extract logic into analyzeSlicePtr, analyzeSliceLen and use them
inside the slice semantic analysis.
- The approach in stage2 is much cleaner than stage1 because it uses
more granular analysis calls for obtaining the slice pointer, doing
arithmetic on it, and checking if the length is comptime-known.
* Sema: use the slice Value Tag for slices when doing coercion from
pointer-to-array.
* LLVM backend: detect when emitting a GEP instruction into a
pointer-to-array and add the extra index that is required.
* Type: ptrAlignment for c_void returns 0.
* Implement Value.hash and Value.eql for slices.
* Remove accidentally duplicated behavior test.
405 lines
8.6 KiB
Zig
405 lines
8.6 KiB
Zig
const std = @import("std");
|
|
const expect = std.testing.expect;
|
|
const expectEqual = std.testing.expectEqual;
|
|
|
|
test "compile time recursion" {
|
|
try expect(some_data.len == 21);
|
|
}
|
|
var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined;
|
|
fn fibonacci(x: i32) i32 {
|
|
if (x <= 1) return 1;
|
|
return fibonacci(x - 1) + fibonacci(x - 2);
|
|
}
|
|
|
|
fn unwrapAndAddOne(blah: ?i32) i32 {
|
|
return blah.? + 1;
|
|
}
|
|
const should_be_1235 = unwrapAndAddOne(1234);
|
|
test "static add one" {
|
|
try expect(should_be_1235 == 1235);
|
|
}
|
|
|
|
test "inlined loop" {
|
|
comptime var i = 0;
|
|
comptime var sum = 0;
|
|
inline while (i <= 5) : (i += 1)
|
|
sum += i;
|
|
try expect(sum == 15);
|
|
}
|
|
|
|
fn gimme1or2(comptime a: bool) i32 {
|
|
const x: i32 = 1;
|
|
const y: i32 = 2;
|
|
comptime var z: i32 = if (a) x else y;
|
|
return z;
|
|
}
|
|
test "inline variable gets result of const if" {
|
|
try expect(gimme1or2(true) == 1);
|
|
try expect(gimme1or2(false) == 2);
|
|
}
|
|
|
|
test "static function evaluation" {
|
|
try expect(statically_added_number == 3);
|
|
}
|
|
const statically_added_number = staticAdd(1, 2);
|
|
fn staticAdd(a: i32, b: i32) i32 {
|
|
return a + b;
|
|
}
|
|
|
|
test "const expr eval on single expr blocks" {
|
|
try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
|
|
comptime try expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
|
|
}
|
|
|
|
fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
|
|
const literal = 3;
|
|
|
|
const result = if (b) b: {
|
|
break :b literal;
|
|
} else b: {
|
|
break :b x;
|
|
};
|
|
|
|
return result;
|
|
}
|
|
|
|
test "constant expressions" {
|
|
var array: [array_size]u8 = undefined;
|
|
try expect(@sizeOf(@TypeOf(array)) == 20);
|
|
}
|
|
const array_size: u8 = 20;
|
|
|
|
fn max(comptime T: type, a: T, b: T) T {
|
|
if (T == bool) {
|
|
return a or b;
|
|
} else if (a > b) {
|
|
return a;
|
|
} else {
|
|
return b;
|
|
}
|
|
}
|
|
fn letsTryToCompareBools(a: bool, b: bool) bool {
|
|
return max(bool, a, b);
|
|
}
|
|
test "inlined block and runtime block phi" {
|
|
try expect(letsTryToCompareBools(true, true));
|
|
try expect(letsTryToCompareBools(true, false));
|
|
try expect(letsTryToCompareBools(false, true));
|
|
try expect(!letsTryToCompareBools(false, false));
|
|
|
|
comptime {
|
|
try expect(letsTryToCompareBools(true, true));
|
|
try expect(letsTryToCompareBools(true, false));
|
|
try expect(letsTryToCompareBools(false, true));
|
|
try expect(!letsTryToCompareBools(false, false));
|
|
}
|
|
}
|
|
|
|
test "eval @setRuntimeSafety at compile-time" {
|
|
const result = comptime fnWithSetRuntimeSafety();
|
|
try expect(result == 1234);
|
|
}
|
|
|
|
fn fnWithSetRuntimeSafety() i32 {
|
|
@setRuntimeSafety(true);
|
|
return 1234;
|
|
}
|
|
|
|
test "compile-time downcast when the bits fit" {
|
|
comptime {
|
|
const spartan_count: u16 = 255;
|
|
const byte = @intCast(u8, spartan_count);
|
|
try expect(byte == 255);
|
|
}
|
|
}
|
|
|
|
test "pointer to type" {
|
|
comptime {
|
|
var T: type = i32;
|
|
try expect(T == i32);
|
|
var ptr = &T;
|
|
try expect(@TypeOf(ptr) == *type);
|
|
ptr.* = f32;
|
|
try expect(T == f32);
|
|
try expect(*T == *f32);
|
|
}
|
|
}
|
|
|
|
test "a type constructed in a global expression" {
|
|
var l: List = undefined;
|
|
l.array[0] = 10;
|
|
l.array[1] = 11;
|
|
l.array[2] = 12;
|
|
const ptr = @ptrCast([*]u8, &l.array);
|
|
try expect(ptr[0] == 10);
|
|
try expect(ptr[1] == 11);
|
|
try expect(ptr[2] == 12);
|
|
}
|
|
|
|
const List = blk: {
|
|
const T = [10]u8;
|
|
break :blk struct {
|
|
array: T,
|
|
};
|
|
};
|
|
|
|
test "comptime function with the same args is memoized" {
|
|
comptime {
|
|
try expect(MakeType(i32) == MakeType(i32));
|
|
try expect(MakeType(i32) != MakeType(f64));
|
|
}
|
|
}
|
|
|
|
fn MakeType(comptime T: type) type {
|
|
return struct {
|
|
field: T,
|
|
};
|
|
}
|
|
|
|
test "try to trick eval with runtime if" {
|
|
try expect(testTryToTrickEvalWithRuntimeIf(true) == 10);
|
|
}
|
|
|
|
fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
|
|
comptime var i: usize = 0;
|
|
inline while (i < 10) : (i += 1) {
|
|
const result = if (b) false else true;
|
|
_ = result;
|
|
}
|
|
comptime {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
test "@setEvalBranchQuota" {
|
|
comptime {
|
|
// 1001 for the loop and then 1 more for the expect fn call
|
|
@setEvalBranchQuota(1002);
|
|
var i = 0;
|
|
var sum = 0;
|
|
while (i < 1001) : (i += 1) {
|
|
sum += i;
|
|
}
|
|
try expect(sum == 500500);
|
|
}
|
|
}
|
|
|
|
test "constant struct with negation" {
|
|
try expect(vertices[0].x == @as(f32, -0.6));
|
|
}
|
|
const Vertex = struct {
|
|
x: f32,
|
|
y: f32,
|
|
r: f32,
|
|
g: f32,
|
|
b: f32,
|
|
};
|
|
const vertices = [_]Vertex{
|
|
Vertex{
|
|
.x = -0.6,
|
|
.y = -0.4,
|
|
.r = 1.0,
|
|
.g = 0.0,
|
|
.b = 0.0,
|
|
},
|
|
Vertex{
|
|
.x = 0.6,
|
|
.y = -0.4,
|
|
.r = 0.0,
|
|
.g = 1.0,
|
|
.b = 0.0,
|
|
},
|
|
Vertex{
|
|
.x = 0.0,
|
|
.y = 0.6,
|
|
.r = 0.0,
|
|
.g = 0.0,
|
|
.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");
|
|
}
|
|
}
|
|
}
|
|
|
|
test "statically initialized struct" {
|
|
st_init_str_foo.x += 1;
|
|
try expect(st_init_str_foo.x == 14);
|
|
}
|
|
const StInitStrFoo = struct {
|
|
x: i32,
|
|
y: bool,
|
|
};
|
|
var st_init_str_foo = StInitStrFoo{
|
|
.x = 13,
|
|
.y = true,
|
|
};
|
|
|
|
test "inline for with same type but different values" {
|
|
var res: usize = 0;
|
|
inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| {
|
|
var a: T = undefined;
|
|
res += a.len;
|
|
}
|
|
try expect(res == 5);
|
|
}
|
|
|
|
test "f32 at compile time is lossy" {
|
|
try expect(@as(f32, 1 << 24) + 1 == 1 << 24);
|
|
}
|
|
|
|
test "f64 at compile time is lossy" {
|
|
try expect(@as(f64, 1 << 53) + 1 == 1 << 53);
|
|
}
|
|
|
|
test {
|
|
comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192);
|
|
}
|